From 43a6f34e7f2bd69ebf01bcda309cdc570c01629d Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 5 Jan 2019 06:57:06 -0800 Subject: [PATCH] Update the SMTP (PHPMailer) adapter for the new mail API; remove "encoding" and "mailer" Summary: Ref T920. Ref T12404. - Update to the new "$message" API. - Remove "encoding". I believe "base64" is always the best value for this since we stopped seeing issues once we changed the default. - Remove "mailer". This is a legacy option that makes little sense given how configuration now works. - Rename to "SMTP". This doesn't affect users anymore since this mailer has been configured as `smtp` for about a year. - This does NOT add a timeout since the SMTP code is inside PHPMailer (see T12404). Test Plan: Sent messages with many mail features via GMail SMTP and SendGrid SMTP. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T12404, T920 Differential Revision: https://secure.phabricator.com/D19961 --- src/__phutil_library_map__.php | 10 +- .../PhabricatorMailAmazonSESAdapter.php | 2 +- .../PhabricatorMailPHPMailerAdapter.php | 150 ----------------- .../adapter/PhabricatorMailSMTPAdapter.php | 154 ++++++++++++++++++ ...php => PhabricatorMailSendmailAdapter.php} | 2 +- 5 files changed, 161 insertions(+), 157 deletions(-) delete mode 100644 src/applications/metamta/adapter/PhabricatorMailPHPMailerAdapter.php create mode 100644 src/applications/metamta/adapter/PhabricatorMailSMTPAdapter.php rename src/applications/metamta/adapter/{PhabricatorMailPHPMailerLiteAdapter.php => PhabricatorMailSendmailAdapter.php} (98%) diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index fb6cfed1fa..49d2500b21 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3417,15 +3417,15 @@ phutil_register_library_map(array( 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfEmailHeraldAction.php', 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'applications/metamta/herald/PhabricatorMailOutboundRoutingSelfNotificationHeraldAction.php', 'PhabricatorMailOutboundStatus' => 'applications/metamta/constants/PhabricatorMailOutboundStatus.php', - 'PhabricatorMailPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailPHPMailerAdapter.php', - 'PhabricatorMailPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailPHPMailerLiteAdapter.php', 'PhabricatorMailPostmarkAdapter' => 'applications/metamta/adapter/PhabricatorMailPostmarkAdapter.php', 'PhabricatorMailPropertiesDestructionEngineExtension' => 'applications/metamta/engineextension/PhabricatorMailPropertiesDestructionEngineExtension.php', 'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php', 'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 'PhabricatorMailRoutingRule' => 'applications/metamta/constants/PhabricatorMailRoutingRule.php', + 'PhabricatorMailSMTPAdapter' => 'applications/metamta/adapter/PhabricatorMailSMTPAdapter.php', 'PhabricatorMailSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailSendGridAdapter.php', + 'PhabricatorMailSendmailAdapter' => 'applications/metamta/adapter/PhabricatorMailSendmailAdapter.php', 'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php', 'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php', 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', @@ -9222,7 +9222,7 @@ phutil_register_library_map(array( 'PhabricatorMacroTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', 'PhabricatorMailAdapter' => 'Phobject', - 'PhabricatorMailAmazonSESAdapter' => 'PhabricatorMailPHPMailerLiteAdapter', + 'PhabricatorMailAmazonSESAdapter' => 'PhabricatorMailSendmailAdapter', 'PhabricatorMailAttachment' => 'Phobject', 'PhabricatorMailConfigTestCase' => 'PhabricatorTestCase', 'PhabricatorMailEmailEngine' => 'PhabricatorMailMessageEngine', @@ -9251,15 +9251,15 @@ phutil_register_library_map(array( 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 'PhabricatorMailOutboundStatus' => 'Phobject', - 'PhabricatorMailPHPMailerAdapter' => 'PhabricatorMailAdapter', - 'PhabricatorMailPHPMailerLiteAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailPostmarkAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailPropertiesDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorMailReceiver' => 'Phobject', 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', 'PhabricatorMailReplyHandler' => 'Phobject', 'PhabricatorMailRoutingRule' => 'Phobject', + 'PhabricatorMailSMTPAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailSendGridAdapter' => 'PhabricatorMailAdapter', + 'PhabricatorMailSendmailAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorMailStamp' => 'Phobject', 'PhabricatorMailTarget' => 'Phobject', diff --git a/src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php b/src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php index 31168293a9..5505f5de86 100644 --- a/src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php @@ -1,7 +1,7 @@ 'string|null', - 'port' => 'int', - 'user' => 'string|null', - 'password' => 'string|null', - 'protocol' => 'string|null', - 'encoding' => 'string', - 'mailer' => 'string', - )); - } - - public function newDefaultOptions() { - return array( - 'host' => null, - 'port' => 25, - 'user' => null, - 'password' => null, - 'protocol' => null, - 'encoding' => 'base64', - 'mailer' => 'smtp', - ); - } - - /** - * @phutil-external-symbol class PHPMailer - */ - public function prepareForSend() { - $root = phutil_get_library_root('phabricator'); - $root = dirname($root); - require_once $root.'/externals/phpmailer/class.phpmailer.php'; - $this->mailer = new PHPMailer($use_exceptions = true); - $this->mailer->CharSet = 'utf-8'; - - $encoding = $this->getOption('encoding'); - $this->mailer->Encoding = $encoding; - - // By default, PHPMailer sends one mail per recipient. We handle - // combining or separating To and Cc higher in the stack, so tell it to - // send mail exactly like we ask. - $this->mailer->SingleTo = false; - - $mailer = $this->getOption('mailer'); - if ($mailer == 'smtp') { - $this->mailer->IsSMTP(); - $this->mailer->Host = $this->getOption('host'); - $this->mailer->Port = $this->getOption('port'); - $user = $this->getOption('user'); - if ($user) { - $this->mailer->SMTPAuth = true; - $this->mailer->Username = $user; - $this->mailer->Password = $this->getOption('password'); - } - - $protocol = $this->getOption('protocol'); - if ($protocol) { - $protocol = phutil_utf8_strtolower($protocol); - $this->mailer->SMTPSecure = $protocol; - } - } else if ($mailer == 'sendmail') { - $this->mailer->IsSendmail(); - } else { - // Do nothing, by default PHPMailer send message using PHP mail() - // function. - } - } - - public function supportsMessageIDHeader() { - return true; - } - - public function setFrom($email, $name = '') { - $this->mailer->SetFrom($email, $name, $crazy_side_effects = false); - return $this; - } - - public function addReplyTo($email, $name = '') { - $this->mailer->AddReplyTo($email, $name); - return $this; - } - - public function addTos(array $emails) { - foreach ($emails as $email) { - $this->mailer->AddAddress($email); - } - return $this; - } - - public function addCCs(array $emails) { - foreach ($emails as $email) { - $this->mailer->AddCC($email); - } - return $this; - } - - public function addAttachment($data, $filename, $mimetype) { - $this->mailer->AddStringAttachment( - $data, - $filename, - 'base64', - $mimetype); - return $this; - } - - public function addHeader($header_name, $header_value) { - if (strtolower($header_name) == 'message-id') { - $this->mailer->MessageID = $header_value; - } else { - $this->mailer->AddCustomHeader($header_name.': '.$header_value); - } - return $this; - } - - public function setBody($body) { - $this->mailer->IsHTML(false); - $this->mailer->Body = $body; - return $this; - } - - public function setHTMLBody($html_body) { - $this->mailer->IsHTML(true); - $this->mailer->Body = $html_body; - return $this; - } - - public function setSubject($subject) { - $this->mailer->Subject = $subject; - return $this; - } - - public function hasValidRecipients() { - return true; - } - - public function send() { - return $this->mailer->Send(); - } - -} diff --git a/src/applications/metamta/adapter/PhabricatorMailSMTPAdapter.php b/src/applications/metamta/adapter/PhabricatorMailSMTPAdapter.php new file mode 100644 index 0000000000..a3c6298279 --- /dev/null +++ b/src/applications/metamta/adapter/PhabricatorMailSMTPAdapter.php @@ -0,0 +1,154 @@ + 'string|null', + 'port' => 'int', + 'user' => 'string|null', + 'password' => 'string|null', + 'protocol' => 'string|null', + )); + } + + public function newDefaultOptions() { + return array( + 'host' => null, + 'port' => 25, + 'user' => null, + 'password' => null, + 'protocol' => null, + ); + } + + /** + * @phutil-external-symbol class PHPMailer + */ + public function sendMessage(PhabricatorMailExternalMessage $message) { + $root = phutil_get_library_root('phabricator'); + $root = dirname($root); + require_once $root.'/externals/phpmailer/class.phpmailer.php'; + $smtp = new PHPMailer($use_exceptions = true); + + $smtp->CharSet = 'utf-8'; + $smtp->Encoding = 'base64'; + + // By default, PHPMailer sends one mail per recipient. We handle + // combining or separating To and Cc higher in the stack, so tell it to + // send mail exactly like we ask. + $smtp->SingleTo = false; + + $smtp->IsSMTP(); + $smtp->Host = $this->getOption('host'); + $smtp->Port = $this->getOption('port'); + $user = $this->getOption('user'); + if (strlen($user)) { + $smtp->SMTPAuth = true; + $smtp->Username = $user; + $smtp->Password = $this->getOption('password'); + } + + $protocol = $this->getOption('protocol'); + if ($protocol) { + $protocol = phutil_utf8_strtolower($protocol); + $smtp->SMTPSecure = $protocol; + } + + $subject = $message->getSubject(); + if ($subject !== null) { + $smtp->Subject = $subject; + } + + $from_address = $message->getFromAddress(); + if ($from_address) { + $smtp->SetFrom( + $from_address->getAddress(), + (string)$from_address->getDisplayName(), + $crazy_side_effects = false); + } + + $reply_address = $message->getReplyToAddress(); + if ($reply_address) { + $smtp->AddReplyTo( + $reply_address->getAddress(), + (string)$reply_address->getDisplayName()); + } + + $to_addresses = $message->getToAddresses(); + if ($to_addresses) { + foreach ($to_addresses as $address) { + $smtp->AddAddress( + $address->getAddress(), + (string)$address->getDisplayName()); + } + } + + $cc_addresses = $message->getCCAddresses(); + if ($cc_addresses) { + foreach ($cc_addresses as $address) { + $smtp->AddCC( + $address->getAddress(), + (string)$address->getDisplayName()); + } + } + + $headers = $message->getHeaders(); + if ($headers) { + $list = array(); + foreach ($headers as $header) { + $name = $header->getName(); + $value = $header->getValue(); + + if (phutil_utf8_strtolower($name) === 'message-id') { + $smtp->MessageID = $value; + } else { + $smtp->AddCustomHeader("{$name}: {$value}"); + } + } + } + + $text_body = $message->getTextBody(); + if ($text_body !== null) { + $smtp->Body = $text_body; + } + + $html_body = $message->getHTMLBody(); + if ($html_body !== null) { + $smtp->IsHTML(true); + $smtp->Body = $html_body; + if ($text_body !== null) { + $smtp->AltBody = $text_body; + } + } + + $attachments = $message->getAttachments(); + if ($attachments) { + foreach ($attachments as $attachment) { + $smtp->AddStringAttachment( + $attachment->getData(), + $attachment->getFilename(), + 'base64', + $attachment->getMimeType()); + } + } + + $smtp->Send(); + } + +} diff --git a/src/applications/metamta/adapter/PhabricatorMailPHPMailerLiteAdapter.php b/src/applications/metamta/adapter/PhabricatorMailSendmailAdapter.php similarity index 98% rename from src/applications/metamta/adapter/PhabricatorMailPHPMailerLiteAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailSendmailAdapter.php index 4557adc219..920d8da99f 100644 --- a/src/applications/metamta/adapter/PhabricatorMailPHPMailerLiteAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailSendmailAdapter.php @@ -5,7 +5,7 @@ * * @concrete-extensible */ -class PhabricatorMailPHPMailerLiteAdapter +class PhabricatorMailSendmailAdapter extends PhabricatorMailAdapter { const ADAPTERTYPE = 'sendmail';