Created
December 9, 2020 00:44
-
-
Save basherr/8ee9cef685dc1ea95b3485e542dc9ce3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\ProxyEmail; | |
use Illuminate\Support\Collection; | |
/** | |
* class EmailBuilder | |
* | |
* build recipients and prepare outgoing emails | |
* | |
* @package App\ProxyEmail | |
*/ | |
class EmailBuilder | |
{ | |
/** | |
* prepare emails to be send to the recipients | |
* | |
* @param void | |
* @return void | |
*/ | |
public function buildOutgoingList(Email $email): Collection | |
{ | |
// retrieve a list of proxy-domain emails from the envelope recipients | |
// this is a list of who we will be delivering to in this process | |
return $this->buildRecipientList($email->getEnvelopeTo()) | |
->map(function ($recipient) use ($email) { | |
// we will prepare rather than send so we can record sent table entries first & | |
// manage race conditions, sending all emails at once at the end | |
return $this->prepareOutgoing($email, $recipient); | |
}) | |
->filter(); // remove any nulls (duplicates) | |
} | |
/** | |
* Build a list of recipients who we need to forward this copy to. If we | |
* encounter reply-token addresses, we need to forward to all of them as a | |
* group (in the same email) by replacing them all out at once. This is | |
* because they are external email addresses & we can't send them multiple | |
* copies, or a version with reply-token addresses still in place (as this | |
* will look like a spoof). | |
* | |
* @param \Illuminate\Support\Collection $recipients | |
* @return \Illuminate\Support\Collection | |
*/ | |
protected function buildRecipientList($recipients) | |
{ | |
$groupedRecipients = $recipients->mapToGroups(function ($recipient) { | |
// ensure only gemacademy.nz addresses are in envelope:to | |
return [$this->recipientType($recipient) => $this->recipientAddress($recipient)]; | |
}); | |
// if there are reply-token addresses we have to replace them out all at once | |
return $groupedRecipients->get('proxy', collect()) | |
->push($groupedRecipients->get('reply-token')); | |
} | |
/** | |
* Prepare an OutgoingEmail based off the received email, but targeting the | |
* specified recipient | |
* | |
* @param \App\ProxyEmail\Email $email the email we are forwarding | |
* @param string|\Illuminate\Support\Collection $recipient the recipient (or array of recipients) we are targeting to replace with this send | |
* @return null|\App\ProxyEmail\OutgoingEmail null if duplicate, otherwise an OutgoingEmail ready to send | |
*/ | |
protected function prepareOutgoing(Email $email, $recipient) | |
{ | |
// if this email was not a duplicate, prepare it for forwarding on | |
return resolve(OutgoingEmail::class) | |
->setEmail($email) | |
->updateRecipients($recipient) // this is who this particular outgoing email is targeting | |
->ensureNotDuplicate(); // returns null if duplicate, otherwise OutgoingEmail | |
} | |
/** | |
* Determine what type of recipient this is: proxy (e.g. gemacademy.nz), reply-token, or external | |
* | |
* @param string $recipient recipient address | |
* @return string type of recipient this address represents - either proxy; reply-token; or external | |
*/ | |
protected function recipientType($recipient) | |
{ | |
if (strpos($recipient, '@' . env('PROXY_DOMAIN')) === false) { | |
return 'external'; | |
} | |
// if it looks like reply-23432456@<domain> it's a reply-token address | |
return preg_match('/^reply-\d+\@/', $recipient) ? 'reply-token' : 'proxy'; | |
} | |
/** | |
* Extract an email address out of a receipient - e.g. [email protected], vs | |
* "Your Name" <[email protected]> vs <[email protected]> | |
* | |
* @return string clean email address | |
*/ | |
protected function recipientAddress($recipient) | |
{ | |
$matches = []; | |
if (preg_match('/<([^>]+)>/', $recipient, $matches)) { | |
return $matches[1]; | |
} else { | |
return $recipient; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment