Source of file MandrillSwiftTransport.php
Size: 15,283 Bytes - Last Modified: 2021-12-23T10:01:22+00:00
/var/www/docs.ssmods.com/process/src/code/MandrillSwiftTransport.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 | <?php namespace LeKoala\Mandrill; use Exception; use Mandrill; use Psr\Log\LoggerInterface; use ReflectionClass; use ReflectionException; use SilverStripe\Assets\FileNameFilter; use SilverStripe\Control\Director; use SilverStripe\Core\Injector\Injector; use Swift_Attachment; use Swift_Events_EventListener; use Swift_Events_SendEvent; use Swift_Events_SimpleEventDispatcher; use Swift_Mime_Header; use Swift_Mime_Headers_OpenDKIMHeader; use Swift_Mime_Headers_UnstructuredHeader; use Swift_Mime_SimpleMessage; use Swift_MimePart; use Swift_Transport; use Swift_Transport_SimpleMailInvoker; /** * A Mandrill transport for Swift Mailer using our custom client * * Heavily inspired by AccordGroup/MandrillSwiftMailer * * @link https://github.com/slowprog/MandrillSwiftMailer * @link https://www.Mandrill.com/api#/reference/introduction * @link https://github.com/AccordGroup/MandrillSwiftMailer * @author LeKoala <thomas@lekoala.be> */ class MandrillSwiftTransport implements Swift_Transport { /** * @var Swift_Transport_SimpleMailInvoker */ protected $invoker; /** * @var Swift_Events_SimpleEventDispatcher */ protected $eventDispatcher; /** * @var Mandrill */ protected $client; /** * @var array */ protected $resultApi; /** * @var string */ protected $fromEmail; /** * @var boolean */ protected $isStarted = false; public function __construct(Mandrill $client) { $this->client = $client; $this->invoker = new \Swift_Transport_SimpleMailInvoker(); $this->eventDispatcher = new \Swift_Events_SimpleEventDispatcher(); } /** * Not used */ public function isStarted() { return $this->isStarted; } /** * Not used */ public function start() { $this->isStarted = true; } /** * Not used */ public function stop() { $this->isStarted = false; } /** * {@inheritdoc} */ public function ping() { return true; } /** * @param Swift_Mime_SimpleMessage $message * @param string[] $failedRecipients * @return int Number of messages sent * @throws ReflectionException * @throws Exception */ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) { $this->resultApi = null; if ($event = $this->eventDispatcher->createSendEvent($this, $message)) { $this->eventDispatcher->dispatchEvent($event, 'beforeSendPerformed'); if ($event->bubbleCancelled()) { return 0; } } $sendCount = 0; $disableSending = $message->getHeaders()->has('X-SendingDisabled') || !MandrillHelper::getSendingEnabled(); $mandrillMessage = $this->getMandrillMessage($message); $client = $this->client; if ($disableSending) { $result = []; foreach ($mandrillMessage['to'] as $recipient) { $result[] = [ 'email' => $recipient['email'], 'status' => 'sent', 'reject_reason' => '', '_id' => uniqid(), 'disabled' => true, ]; } } else { $result = $client->messages->send($mandrillMessage); } $this->resultApi = $result; if (MandrillHelper::getLoggingEnabled()) { $this->logMessageContent($message, $result); } foreach ($this->resultApi as $item) { if ($item['status'] === 'sent' || $item['status'] === 'queued') { $sendCount++; } else { $failedRecipients[] = $item['email']; } } if ($event) { if ($sendCount > 0) { $event->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); } else { $event->setResult(Swift_Events_SendEvent::RESULT_FAILED); } $this->eventDispatcher->dispatchEvent($event, 'sendPerformed'); } return $sendCount; } /** * Log message content * * @param Swift_Mime_SimpleMessage $message * @param array $results Results from the api * @throws Exception */ protected function logMessageContent(Swift_Mime_SimpleMessage $message, $results = []) { // Folder not set $logFolder = MandrillHelper::getLogFolder(); if (!$logFolder) { return; } // Logging disabled if (!MandrillHelper::getLoggingEnabled()) { return; } $subject = $message->getSubject(); $body = $message->getBody(); $contentType = $this->getMessagePrimaryContentType($message); $logContent = $body; // Append some extra information at the end $logContent .= '<hr><pre>Debug infos:' . "\n\n"; $logContent .= 'To : ' . print_r($message->getTo(), true) . "\n"; $logContent .= 'Subject : ' . $subject . "\n"; $logContent .= 'From : ' . print_r($message->getFrom(), true) . "\n"; $logContent .= 'Headers:' . "\n"; /** @var Swift_Mime_Header $header */ foreach ($message->getHeaders()->getAll() as $header) { $logContent .= ' ' . $header->getFieldName() . ': ' . $header->getFieldBody() . "\n"; } if (!empty($params['recipients'])) { $logContent .= 'Recipients : ' . print_r($message->getTo(), true) . "\n"; } $logContent .= 'Results:' . "\n"; $logContent .= print_r($results, true) . "\n"; $logContent .= '</pre>'; // Generate filename $filter = new FileNameFilter(); $title = substr($filter->filter($subject), 0, 35); $logName = date('Ymd_His') . '_' . $title; // Store attachments if any $attachments = $message->getChildren(); if (!empty($attachments)) { $logContent .= '<hr />'; foreach ($attachments as $attachment) { if ($attachment instanceof Swift_Attachment) { $attachmentDestination = $logFolder . '/' . $logName . '_' . $attachment->getFilename(); file_put_contents($attachmentDestination, $attachment->getBody()); $logContent .= 'File : <a href="' . $attachmentDestination . '">' . $attachment->getFilename() . '</a><br/>'; } } } // Store it $ext = ($contentType == 'text/html') ? 'html' : 'txt'; $r = file_put_contents($logFolder . '/' . $logName . '.' . $ext, $logContent); if (!$r && Director::isDev()) { throw new Exception('Failed to store email in ' . $logFolder); } } /** * @return LoggerInterface */ public function getLogger() { return Injector::inst()->get(LoggerInterface::class)->withName('Mandrill'); } /** * @param Swift_Events_EventListener $plugin */ public function registerPlugin(Swift_Events_EventListener $plugin) { $this->eventDispatcher->bindEventListener($plugin); } /** * @return array */ protected function getSupportedContentTypes() { return array( 'text/plain', 'text/html' ); } /** * @param string $contentType * @return bool */ protected function supportsContentType($contentType) { return in_array($contentType, $this->getSupportedContentTypes()); } /** * @param Swift_Mime_SimpleMessage $message * @return string * @throws ReflectionException */ protected function getMessagePrimaryContentType(Swift_Mime_SimpleMessage $message) { $contentType = $message->getContentType(); if ($this->supportsContentType($contentType)) { return $contentType; } // SwiftMailer hides the content type set in the constructor of Swift_Mime_SimpleMessage as soon // as you add another part to the message. We need to access the protected property // _userContentType to get the original type. $messageRef = new ReflectionClass($message); if ($messageRef->hasProperty('_userContentType')) { $propRef = $messageRef->getProperty('_userContentType'); $propRef->setAccessible(true); $contentType = $propRef->getValue($message); } return $contentType; } /** * https://mandrillapp.com/api/docs/messages.php.html#method-send * * @param Swift_Mime_SimpleMessage $message * @return array Mandrill Send Message * @throws ReflectionException */ public function getMandrillMessage(Swift_Mime_SimpleMessage $message) { $contentType = $this->getMessagePrimaryContentType($message); $fromAddresses = $message->getFrom(); $fromEmails = array_keys($fromAddresses); $toAddresses = $message->getTo(); $ccAddresses = $message->getCc() ? $message->getCc() : []; $bccAddresses = $message->getBcc() ? $message->getBcc() : []; $replyToAddresses = $message->getReplyTo() ? $message->getReplyTo() : []; $to = array(); $attachments = array(); $images = array(); $headers = array(); $tags = array(); foreach ($toAddresses as $toEmail => $toName) { $to[] = array( 'email' => $toEmail, 'name' => $toName, 'type' => 'to' ); } foreach ($replyToAddresses as $replyToEmail => $replyToName) { if ($replyToName) { $headers['Reply-To'] = sprintf('%s <%s>', $replyToEmail, $replyToName); } else { $headers['Reply-To'] = $replyToEmail; } } foreach ($ccAddresses as $ccEmail => $ccName) { $to[] = array( 'email' => $ccEmail, 'name' => $ccName, 'type' => 'cc' ); } foreach ($bccAddresses as $bccEmail => $bccName) { $to[] = array( 'email' => $bccEmail, 'name' => $bccName, 'type' => 'bcc' ); } $bodyHtml = $bodyText = null; if ($contentType === 'text/plain') { $bodyText = $message->getBody(); } elseif ($contentType === 'text/html') { $bodyHtml = $message->getBody(); } else { $bodyHtml = $message->getBody(); } foreach ($message->getChildren() as $child) { if ($child instanceof \Swift_Image) { $images[] = array( 'type' => $child->getContentType(), 'name' => $child->getId(), 'content' => base64_encode($child->getBody()), ); } elseif ($child instanceof Swift_Attachment && !($child instanceof \Swift_Image)) { $attachments[] = array( 'type' => $child->getContentType(), 'name' => $child->getFilename(), 'content' => base64_encode($child->getBody()) ); } elseif ($child instanceof Swift_MimePart && $this->supportsContentType($child->getContentType())) { if ($child->getContentType() == "text/html") { $bodyHtml = $child->getBody(); } elseif ($child->getContentType() == "text/plain") { $bodyText = $child->getBody(); } } } $mandrillMessage = array( 'html' => $bodyHtml, 'text' => $bodyText, 'subject' => $message->getSubject(), 'from_email' => $fromEmails[0], 'from_name' => $fromAddresses[$fromEmails[0]], 'to' => $to, 'headers' => $headers, 'tags' => $tags ); // Merge the default parameters $mandrillMessage = array_merge( MandrillHelper::config()->default_params, $mandrillMessage ); if (count($attachments) > 0) { $mandrillMessage['attachments'] = $attachments; } if (count($images) > 0) { $mandrillMessage['images'] = $images; } /** @var Swift_Mime_Headers_OpenDKIMHeader|Swift_Mime_Headers_UnstructuredHeader $header */ foreach ($message->getHeaders()->getAll() as $header) { if ($header->getFieldType() === \Swift_Mime_Header::TYPE_TEXT) { if (method_exists($header, "getValue")) { $headerValue = $header->getValue(); } else { $headerValue = $header->toString(); } switch ($header->getFieldName()) { case 'List-Unsubscribe': $headers['List-Unsubscribe'] = $headerValue; $mandrillMessage['headers'] = $headers; break; case 'X-MC-InlineCSS': $mandrillMessage['inline_css'] = $headerValue; break; case 'X-MC-Tags': $tags = $headerValue; if (!is_array($tags)) { $tags = explode(',', $tags); } $mandrillMessage['tags'] = $tags; break; case 'X-MC-Autotext': $autoText = $headerValue; if (in_array($autoText, array('true', 'on', 'yes', 'y', true), true)) { $mandrillMessage['auto_text'] = true; } if (in_array($autoText, array('false', 'off', 'no', 'n', false), true)) { $mandrillMessage['auto_text'] = false; } break; case 'X-MC-GoogleAnalytics': $analyticsDomains = explode(',', $headerValue); if (is_array($analyticsDomains)) { $mandrillMessage['google_analytics_domains'] = $analyticsDomains; } break; case 'X-MC-GoogleAnalyticsCampaign': $mandrillMessage['google_analytics_campaign'] = $headerValue; break; default: if (strncmp($header->getFieldName(), 'X-', 2) === 0) { $headers[$header->getFieldName()] = $headerValue; $mandrillMessage['headers'] = $headers; } break; } } } // if ($this->getSubaccount()) { // $mandrillMessage['subaccount'] = $this->getSubaccount(); // } return $mandrillMessage; } /** * @return null|array */ public function getResultApi() { return $this->resultApi; } } |