Skip to content

Instantly share code, notes, and snippets.

@basherr
Created December 9, 2020 00:44
Show Gist options
  • Save basherr/8ee9cef685dc1ea95b3485e542dc9ce3 to your computer and use it in GitHub Desktop.
Save basherr/8ee9cef685dc1ea95b3485e542dc9ce3 to your computer and use it in GitHub Desktop.
<?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