Source of file Mailer.php
Size: 8,598 Bytes - Last Modified: 2021-12-24T06:19:27+00:00
/var/www/docs.ssmods.com/process/src/src/Mailer.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 | <?php namespace Kinglozzer\SilverStripeMailgunner; use Convert; use Debug; use Exception; use Mailer as SilverstripeMailer; use Mailgun\HttpClientConfigurator; use Mailgun\Mailgun; use Mailgun\Messages\BatchMessage; use Mailgun\Messages\MessageBuilder; use SS_Log; use SapphireTest; class Mailer extends SilverstripeMailer { /** * @var string * @config */ private static $api_domain = ''; /** * @var string * @config */ private static $api_endpoint = ''; /** * @var string * @config */ private static $api_key = ''; /** * @var boolean * @config */ private static $debug = false; /** * An array of temporary file handles opened to store attachments * @var array */ protected $tempFileHandles = []; /** * @var Mailgun */ protected $mailgunClient; /** * {@inheritdoc} */ public function __construct() { $config = $this->config(); $configurator = new HttpClientConfigurator(); $configurator->setApiKey($config->api_key); $configurator->setDebug($config->debug); if ($config->api_endpoint) { $configurator->setEndpoint($config->api_endpoint); } $this->setMailgunClient(Mailgun::configure($configurator)); } /** * @param Mailgun $client * @return self */ public function setMailgunClient(Mailgun $client) { $this->mailgunClient = $client; return $this; } /** * @return Mailgun */ public function getMailgunClient() { return $this->mailgunClient; } /** * {@inheritdoc} */ public function sendPlain($to, $from, $subject, $plainContent, $attachments = [], $headers = []) { return $this->sendMessage($to, $from, $subject, $htmlContent = '', $plainContent, $attachments, $headers); } /** * {@inheritdoc} */ public function sendHTML($to, $from, $subject, $htmlContent, $attachments = [], $headers = [], $plainContent = '') { return $this->sendMessage($to, $from, $subject, $htmlContent, $plainContent, $attachments, $headers); } /** * @param string $to * @param string $from * @param string $subject * @param string $content * @param string $plainContent * @param array $attachments * @param array $headers */ protected function sendMessage($to, $from, $subject, $content, $plainContent, $attachments, $headers) { $domain = $this->config()->api_domain; $client = $this->getMailgunClient(); $attachments = $this->prepareAttachments($attachments); if (isset($headers['X-Mailgunner-Batch-Message'])) { $builder = $client->BatchMessage($domain); unset($headers['X-Mailgunner-Batch-Message']); } else { $builder = $client->MessageBuilder(); } try { $this->buildMessage($builder, $to, $from, $subject, $content, $plainContent, $attachments, $headers); if ($builder instanceof BatchMessage) { $builder->finalize(); } else { $client->sendMessage($domain, $builder->getMessage(), $builder->getFiles()); } } catch (Exception $e) { // Close and remove any temp files created for attachments $this->closeTempFileHandles(); // Throwing the exception would break SilverStripe's Email API expectations, so we log // errors and show a message (which is hidden in live mode) SS_Log::log('Mailgun error: ' . $e->getMessage(), SS_Log::ERR); if (!SapphireTest::is_running_test()) { Debug::message('Mailgun error: ' . $e->getMessage()); } return false; } $this->closeTempFileHandles(); // This is a stupid API :( return [$to, $subject, $content, $headers, '']; } /** * @param MessageBuilder $builder * @param string $to * @param string $from * @param string $subject * @param string $content * @param string $plainContent * @param array $attachments * @param array $headers */ protected function buildMessage( MessageBuilder $builder, $to, $from, $subject, $content, $plainContent, array $attachments, array $headers ) { // Add base info $parsedFrom = $this->parseAddresses($from); foreach ($parsedFrom as $email => $name) { $builder->setFromAddress($email, ['full_name' => $name]); } if (empty($plainContent)) { $plainContent = Convert::xml2raw($content); } $builder->setSubject($subject); $builder->setHtmlBody($content); $builder->setTextBody($plainContent); // Add attachments foreach ($attachments as $attachment) { $builder->addAttachment($attachment['filePath'], $attachment['remoteName']); } // Parse Cc & Bcc headers out if they're set $ccAddresses = isset($headers['Cc']) ? $headers['Cc'] : ''; $bccAddresses = isset($headers['Bcc']) ? $headers['Bcc'] : ''; // We handle these ourselves, so can remove them from the list of headers unset($headers['Cc']); unset($headers['Bcc']); // Add remaining custom headers foreach ($headers as $name => $data) { $builder->addCustomHeader($name, $data); } // Add recipients. This is done last as the 'BatchMessage' message builder // will trigger sends for every 1000 addresses $to = $this->parseAddresses($to); foreach ($to as $email => $name) { $builder->addToRecipient($email, ['full_name' => $name]); } $ccAddresses = $this->parseAddresses($ccAddresses); foreach ($ccAddresses as $email => $name) { $builder->addCcRecipient($email, ['full_name' => $name]); } $bccAddresses = $this->parseAddresses($bccAddresses); foreach ($bccAddresses as $email => $name) { $builder->addBccRecipient($email, ['full_name' => $name]); } } /** * @todo This can't deal with mismatched quotes, or commas in names. * E.g. "Smith, John" <john.smith@example.com> or "John O'smith" <john.osmith@example.com> * @param string * @return array */ protected function parseAddresses($addresses) { $parsed = []; $expr = '/\s*["\']?([^><,;"\']+)["\']?\s*((?:<[^><,]+>)?)\s*/'; if (preg_match_all($expr, $addresses, $matches, PREG_SET_ORDER) > 0) { foreach ($matches as $result) { if (empty($result[2])) { // If we couldn't parse out a name $parsed[$result[1]] = ''; } else { $email = trim($result[2], '<>'); $parsed[$email] = trim($result[1]); } } } return $parsed; } /** * Prepare attachments for sending. SilverStripe extracts the content and * passes that to the mailer, so to save encoding it we just write them all * to individual files and let Mailgun deal with the rest. * * @todo Can we handle this better? * @param array $attachments * @return array */ protected function prepareAttachments(array $attachments) { $prepared = []; foreach ($attachments as $attachment) { $tempFile = $this->writeToTempFile($attachment['contents']); $prepared[] = [ 'filePath' => $tempFile, 'remoteName' => $attachment['filename'] ]; } return $prepared; } /** * @param string $contents * @return string */ protected function writeToTempFile($contents) { $tempFile = tempnam(sys_get_temp_dir(), 'SS_MG_TMP'); $fileHandle = fopen($tempFile, 'r+'); fwrite($fileHandle, $contents); $this->tempFileHandles[] = [ 'handle' => $fileHandle, 'path' => $tempFile ]; return $tempFile; } /** * @return void */ protected function closeTempFileHandles() { foreach ($this->tempFileHandles as $key => $data) { fclose($data['handle']); unlink($data['path']); unset($this->tempFileHandles[$key]); } } } |