diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -3387,6 +3387,8 @@ 'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php', 'PhabricatorMacroTransactionType' => 'applications/macro/xaction/PhabricatorMacroTransactionType.php', 'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php', + 'PhabricatorMailAdapter' => 'applications/metamta/adapter/PhabricatorMailAdapter.php', + 'PhabricatorMailAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php', 'PhabricatorMailAttachment' => 'applications/metamta/message/PhabricatorMailAttachment.php', 'PhabricatorMailConfigTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMailConfigTestCase.php', 'PhabricatorMailEmailEngine' => 'applications/metamta/engine/PhabricatorMailEmailEngine.php', @@ -3397,14 +3399,7 @@ 'PhabricatorMailEngineExtension' => 'applications/metamta/engine/PhabricatorMailEngineExtension.php', 'PhabricatorMailExternalMessage' => 'applications/metamta/message/PhabricatorMailExternalMessage.php', 'PhabricatorMailHeader' => 'applications/metamta/message/PhabricatorMailHeader.php', - 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php', - 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php', - 'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php', - 'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php', - 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php', - 'PhabricatorMailImplementationPostmarkAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPostmarkAdapter.php', - 'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php', - 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php', + 'PhabricatorMailMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailMailgunAdapter.php', 'PhabricatorMailManagementListInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php', 'PhabricatorMailManagementListOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php', 'PhabricatorMailManagementReceiveTestWorkflow' => 'applications/metamta/management/PhabricatorMailManagementReceiveTestWorkflow.php', @@ -3422,14 +3417,19 @@ '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', + 'PhabricatorMailSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailSendGridAdapter.php', 'PhabricatorMailSetupCheck' => 'applications/config/check/PhabricatorMailSetupCheck.php', 'PhabricatorMailStamp' => 'applications/metamta/stamp/PhabricatorMailStamp.php', 'PhabricatorMailTarget' => 'applications/metamta/replyhandler/PhabricatorMailTarget.php', + 'PhabricatorMailTestAdapter' => 'applications/metamta/adapter/PhabricatorMailTestAdapter.php', 'PhabricatorMailUtil' => 'applications/metamta/util/PhabricatorMailUtil.php', 'PhabricatorMainMenuBarExtension' => 'view/page/menu/PhabricatorMainMenuBarExtension.php', 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', @@ -9221,6 +9221,8 @@ 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMacroTransactionType' => 'PhabricatorModularTransactionType', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', + 'PhabricatorMailAdapter' => 'Phobject', + 'PhabricatorMailAmazonSESAdapter' => 'PhabricatorMailPHPMailerLiteAdapter', 'PhabricatorMailAttachment' => 'Phobject', 'PhabricatorMailConfigTestCase' => 'PhabricatorTestCase', 'PhabricatorMailEmailEngine' => 'PhabricatorMailMessageEngine', @@ -9231,14 +9233,7 @@ 'PhabricatorMailEngineExtension' => 'Phobject', 'PhabricatorMailExternalMessage' => 'Phobject', 'PhabricatorMailHeader' => 'Phobject', - 'PhabricatorMailImplementationAdapter' => 'Phobject', - 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', - 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter', - 'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter', - 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', - 'PhabricatorMailImplementationPostmarkAdapter' => 'PhabricatorMailImplementationAdapter', - 'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter', - 'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter', + 'PhabricatorMailMailgunAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailManagementListInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementListOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementReceiveTestWorkflow' => 'PhabricatorMailManagementWorkflow', @@ -9256,14 +9251,19 @@ 'PhabricatorMailOutboundRoutingSelfEmailHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 'PhabricatorMailOutboundRoutingSelfNotificationHeraldAction' => 'PhabricatorMailOutboundRoutingHeraldAction', 'PhabricatorMailOutboundStatus' => 'Phobject', + 'PhabricatorMailPHPMailerAdapter' => 'PhabricatorMailAdapter', + 'PhabricatorMailPHPMailerLiteAdapter' => 'PhabricatorMailAdapter', + 'PhabricatorMailPostmarkAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailPropertiesDestructionEngineExtension' => 'PhabricatorDestructionEngineExtension', 'PhabricatorMailReceiver' => 'Phobject', 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', 'PhabricatorMailReplyHandler' => 'Phobject', 'PhabricatorMailRoutingRule' => 'Phobject', + 'PhabricatorMailSendGridAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck', 'PhabricatorMailStamp' => 'Phobject', 'PhabricatorMailTarget' => 'Phobject', + 'PhabricatorMailTestAdapter' => 'PhabricatorMailAdapter', 'PhabricatorMailUtil' => 'Phobject', 'PhabricatorMainMenuBarExtension' => 'Phobject', 'PhabricatorMainMenuSearchView' => 'AphrontView', diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationAdapter.php b/src/applications/metamta/adapter/PhabricatorMailAdapter.php rename from src/applications/metamta/adapter/PhabricatorMailImplementationAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailAdapter.php --- a/src/applications/metamta/adapter/PhabricatorMailImplementationAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailAdapter.php @@ -1,13 +1,16 @@ getPhobjectClassConstant('ADAPTERTYPE'); @@ -20,37 +23,67 @@ ->execute(); } + /* abstract */ public function getSupportedMessageTypes() { + throw new PhutilMethodNotImplementedException(); + } - abstract public function setFrom($email, $name = ''); - abstract public function addReplyTo($email, $name = ''); - abstract public function addTos(array $emails); - abstract public function addCCs(array $emails); - abstract public function addAttachment($data, $filename, $mimetype); - abstract public function addHeader($header_name, $header_value); - abstract public function setBody($plaintext_body); - abstract public function setHTMLBody($html_body); - abstract public function setSubject($subject); - + /* abstract */ public function sendMessage( + PhabricatorMailExternalMessage $message) { + throw new PhutilMethodNotImplementedException(); + } /** - * Some mailers, notably Amazon SES, do not support us setting a specific - * Message-ID header. + * Return true if this adapter supports setting a "Message-ID" when sending + * email. + * + * This is an ugly implementation detail because mail threading is a horrible + * mess, implemented differently by every client in existence. */ - abstract public function supportsMessageIDHeader(); + public function supportsMessageIDHeader() { + return false; + } + final public function supportsMessageType($message_type) { + if ($this->mediaMap === null) { + $media_map = $this->getSupportedMessageTypes(); + $media_map = array_fuse($media_map); - /** - * Send the message. Generally, this means connecting to some service and - * handing data to it. - * - * If the adapter determines that the mail will never be deliverable, it - * should throw a @{class:PhabricatorMetaMTAPermanentFailureException}. - * - * For temporary failures, throw some other exception or return `false`. - * - * @return bool True on success. - */ - abstract public function send(); + if ($this->media) { + $config_map = $this->media; + $config_map = array_fuse($config_map); + + $media_map = array_intersect_key($media_map, $config_map); + } + + $this->mediaMap = $media_map; + } + + return isset($this->mediaMap[$message_type]); + } + + final public function setMedia(array $media) { + $native_map = $this->getSupportedMessageTypes(); + $native_map = array_fuse($native_map); + + foreach ($media as $medium) { + if (!isset($native_map[$medium])) { + throw new Exception( + pht( + 'Adapter ("%s") is configured for medium "%s", but this is not '. + 'a supported delivery medium. Supported media are: %s.', + $medium, + implode(', ', $native_map))); + } + } + + $this->media = $media; + $this->mediaMap = null; + return $this; + } + + final public function getMedia() { + return $this->media; + } final public function setKey($key) { $this->key = $key; @@ -110,18 +143,4 @@ abstract public function newDefaultOptions(); - public function prepareForSend() { - return; - } - - protected function renderAddress($email, $name = null) { - if (strlen($name)) { - return (string)id(new PhutilEmailAddress()) - ->setDisplayName($name) - ->setAddress($email); - } else { - return $email; - } - } - } diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php b/src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php rename from src/applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php --- a/src/applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailAmazonSESAdapter.php @@ -1,7 +1,7 @@ parameters['From'] = $this->renderAddress($email, $name); - return $this; - } - - public function addReplyTo($email, $name = '') { - $this->parameters['ReplyTo'] = $this->renderAddress($email, $name); - return $this; - } - - public function addTos(array $emails) { - foreach ($emails as $email) { - $this->parameters['To'][] = $email; - } - return $this; - } - - public function addCCs(array $emails) { - foreach ($emails as $email) { - $this->parameters['Cc'][] = $email; - } - return $this; - } - - public function addAttachment($data, $filename, $mimetype) { - $this->parameters['Attachments'][] = array( - 'Name' => $filename, - 'ContentType' => $mimetype, - 'Content' => base64_encode($data), - ); - - return $this; - } - - public function addHeader($header_name, $header_value) { - $this->parameters['Headers'][] = array( - 'Name' => $header_name, - 'Value' => $header_value, - ); - return $this; - } - - public function setBody($body) { - $this->parameters['TextBody'] = $body; - return $this; - } - - public function setHTMLBody($html_body) { - $this->parameters['HtmlBody'] = $html_body; - return $this; - } - - public function setSubject($subject) { - $this->parameters['Subject'] = $subject; - return $this; - } - - public function supportsMessageIDHeader() { - return true; - } - - protected function validateOptions(array $options) { - PhutilTypeSpec::checkMap( - $options, - array( - 'access-token' => 'string', - 'inbound-addresses' => 'list', - )); - - // Make sure this is properly formatted. - PhutilCIDRList::newList($options['inbound-addresses']); - } - - public function newDefaultOptions() { - return array( - 'access-token' => null, - 'inbound-addresses' => array( - // Via Postmark support circa February 2018, see: - // - // https://postmarkapp.com/support/article/800-ips-for-firewalls - // - // "Configuring Outbound Email" should be updated if this changes. - '50.31.156.6/32', - ), - ); - } - - public function send() { - $access_token = $this->getOption('access-token'); - - $parameters = $this->parameters; - $flatten = array( - 'To', - 'Cc', - ); - - foreach ($flatten as $key) { - if (isset($parameters[$key])) { - $parameters[$key] = implode(', ', $parameters[$key]); - } - } - - id(new PhutilPostmarkFuture()) - ->setAccessToken($access_token) - ->setMethod('email', $parameters) - ->resolve(); - - return true; - } - -} diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php b/src/applications/metamta/adapter/PhabricatorMailMailgunAdapter.php rename from src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailMailgunAdapter.php --- a/src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailMailgunAdapter.php @@ -3,8 +3,8 @@ /** * Mail adapter that uses Mailgun's web API to deliver email. */ -final class PhabricatorMailImplementationMailgunAdapter - extends PhabricatorMailImplementationAdapter { +final class PhabricatorMailMailgunAdapter + extends PhabricatorMailAdapter { const ADAPTERTYPE = 'mailgun'; diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php b/src/applications/metamta/adapter/PhabricatorMailPHPMailerAdapter.php rename from src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailPHPMailerAdapter.php --- a/src/applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailPHPMailerAdapter.php @@ -1,7 +1,7 @@ 'string', + 'inbound-addresses' => 'list', + )); + + // Make sure this is properly formatted. + PhutilCIDRList::newList($options['inbound-addresses']); + } + + public function newDefaultOptions() { + return array( + 'access-token' => null, + 'inbound-addresses' => array( + // Via Postmark support circa February 2018, see: + // + // https://postmarkapp.com/support/article/800-ips-for-firewalls + // + // "Configuring Outbound Email" should be updated if this changes. + // + // These addresses were last updated in January 2019. + '50.31.156.6/32', + '50.31.156.77/32', + '18.217.206.57/32', + ), + ); + } + + public function sendMessage(PhabricatorMailExternalMessage $message) { + $access_token = $this->getOption('access-token'); + + $parameters = array(); + + $subject = $message->getSubject(); + if ($subject !== null) { + $parameters['Subject'] = $subject; + } + + $from_address = $message->getFromAddress(); + if ($from_address) { + $parameters['From'] = (string)$from_address; + } + + $to_addresses = $message->getToAddresses(); + if ($to_addresses) { + $to = array(); + foreach ($to_addresses as $address) { + $to[] = (string)$address; + } + $parameters['To'] = implode(', ', $to); + } + + $cc_addresses = $message->getCCAddresses(); + if ($cc_addresses) { + $cc = array(); + foreach ($cc_addresses as $address) { + $cc[] = (string)$address; + } + $parameters['Cc'] = implode(', ', $cc); + } + + $reply_address = $message->getReplyToAddress(); + if ($reply_address) { + $parameters['ReplyTo'] = (string)$reply_address; + } + + $headers = $message->getHeaders(); + if ($headers) { + $list = array(); + foreach ($headers as $header) { + $list[] = array( + 'Name' => $header->getName(), + 'Value' => $header->getValue(), + ); + } + $parameters['Headers'] = $list; + } + + $text_body = $message->getTextBody(); + if ($text_body !== null) { + $parameters['TextBody'] = $text_body; + } + + $html_body = $message->getHTMLBody(); + if ($html_body !== null) { + $parameters['HtmlBody'] = $html_body; + } + + $attachments = $message->getAttachments(); + if ($attachments) { + $files = array(); + foreach ($attachments as $attachment) { + $files[] = array( + 'Name' => $attachment->getFilename(), + 'ContentType' => $attachment->getMimeType(), + 'Content' => base64_encode($attachment->getData()), + ); + } + $parameters['Attachments'] = $files; + } + + id(new PhutilPostmarkFuture()) + ->setAccessToken($access_token) + ->setMethod('email', $parameters) + ->setTimeout(60) + ->resolve(); + } + +} diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php b/src/applications/metamta/adapter/PhabricatorMailSendGridAdapter.php rename from src/applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailSendGridAdapter.php --- a/src/applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailSendGridAdapter.php @@ -3,8 +3,8 @@ /** * Mail adapter that uses SendGrid's web API to deliver email. */ -final class PhabricatorMailImplementationSendGridAdapter - extends PhabricatorMailImplementationAdapter { +final class PhabricatorMailSendGridAdapter + extends PhabricatorMailAdapter { const ADAPTERTYPE = 'sendgrid'; diff --git a/src/applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php b/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php rename from src/applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php rename to src/applications/metamta/adapter/PhabricatorMailTestAdapter.php --- a/src/applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php +++ b/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php @@ -4,8 +4,8 @@ * Mail adapter that doesn't actually send any email, for writing unit tests * against. */ -final class PhabricatorMailImplementationTestAdapter - extends PhabricatorMailImplementationAdapter { +final class PhabricatorMailTestAdapter + extends PhabricatorMailAdapter { const ADAPTERTYPE = 'test'; diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php --- a/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php @@ -21,7 +21,7 @@ array( 'inbound' => true, 'types' => array( - PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE, + PhabricatorMailMailgunAdapter::ADAPTERTYPE, ), )); foreach ($mailers as $mailer) { diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php --- a/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php @@ -16,7 +16,7 @@ array( 'inbound' => true, 'types' => array( - PhabricatorMailImplementationPostmarkAdapter::ADAPTERTYPE, + PhabricatorMailPostmarkAdapter::ADAPTERTYPE, ), )); if (!$mailers) { diff --git a/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php --- a/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php +++ b/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php @@ -15,7 +15,7 @@ array( 'inbound' => true, 'types' => array( - PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE, + PhabricatorMailSendGridAdapter::ADAPTERTYPE, ), )); if (!$mailers) { diff --git a/src/applications/metamta/engine/PhabricatorMailMessageEngine.php b/src/applications/metamta/engine/PhabricatorMailMessageEngine.php --- a/src/applications/metamta/engine/PhabricatorMailMessageEngine.php +++ b/src/applications/metamta/engine/PhabricatorMailMessageEngine.php @@ -8,8 +8,7 @@ private $actors = array(); private $preferences; - final public function setMailer( - PhabricatorMailImplementationAdapter $mailer) { + final public function setMailer(PhabricatorMailAdapter $mailer) { $this->mailer = $mailer; return $this; diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php --- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php @@ -547,13 +547,14 @@ 'types' => 'optional list', 'inbound' => 'optional bool', 'outbound' => 'optional bool', + 'media' => 'optional list', )); $mailers = array(); $config = PhabricatorEnv::getEnvConfig('cluster.mailers'); - $adapters = PhabricatorMailImplementationAdapter::getAllAdapters(); + $adapters = PhabricatorMailAdapter::getAllAdapters(); $next_priority = -1; foreach ($config as $spec) { @@ -583,6 +584,11 @@ $mailer->setSupportsInbound(idx($spec, 'inbound', true)); $mailer->setSupportsOutbound(idx($spec, 'outbound', true)); + $media = idx($spec, 'media'); + if ($media !== null) { + $mailer->setMedia($media); + } + $mailers[] = $mailer; } @@ -618,6 +624,24 @@ } } + // Select only the mailers which can transmit messages with requested media + // types. + if (!empty($constraints['media'])) { + foreach ($mailers as $key => $mailer) { + $supports_any = false; + foreach ($constraints['media'] as $medium) { + if ($mailer->supportsMessageType($medium)) { + $supports_any = true; + break; + } + } + + if (!$supports_any) { + unset($mailers[$key]); + } + } + } + $sorted = array(); $groups = mgroup($mailers, 'getPriority'); krsort($groups); diff --git a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php --- a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php +++ b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php @@ -17,7 +17,7 @@ $mail = new PhabricatorMetaMTAMail(); $mail->addTos(array($phid)); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mail->sendWithMailers(array($mailer)); $this->assertEqual( PhabricatorMailOutboundStatus::STATUS_SENT, @@ -28,7 +28,7 @@ $mail = new PhabricatorMetaMTAMail(); $mail->addTos(array($phid)); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mailer->setFailTemporarily(true); try { $mail->sendWithMailers(array($mailer)); @@ -44,7 +44,7 @@ $mail = new PhabricatorMetaMTAMail(); $mail->addTos(array($phid)); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mailer->setFailPermanently(true); try { $mail->sendWithMailers(array($mailer)); @@ -60,7 +60,7 @@ $user = $this->generateNewTestUser(); $phid = $user->getPHID(); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mail = new PhabricatorMetaMTAMail(); $mail->addTos(array($phid)); @@ -182,7 +182,7 @@ $supports_message_id, $is_first_mail) { - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mailer->prepareForSend( array( @@ -261,10 +261,10 @@ $status_queue = PhabricatorMailOutboundStatus::STATUS_QUEUE; $status_fail = PhabricatorMailOutboundStatus::STATUS_FAIL; - $mailer1 = id(new PhabricatorMailImplementationTestAdapter()) + $mailer1 = id(new PhabricatorMailTestAdapter()) ->setKey('mailer1'); - $mailer2 = id(new PhabricatorMailImplementationTestAdapter()) + $mailer2 = id(new PhabricatorMailTestAdapter()) ->setKey('mailer2'); $mailers = array( @@ -350,7 +350,7 @@ ->setBody($string_1kb) ->setHTMLBody($html_1kb); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mail->sendWithMailers(array($mailer)); $this->assertEqual( PhabricatorMailOutboundStatus::STATUS_SENT, @@ -370,7 +370,7 @@ ->setBody($string_1mb) ->setHTMLBody($html_1mb); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mail->sendWithMailers(array($mailer)); $this->assertEqual( PhabricatorMailOutboundStatus::STATUS_SENT, @@ -398,7 +398,7 @@ ->setBody($string_1kb) ->setHTMLBody($html_1mb); - $mailer = new PhabricatorMailImplementationTestAdapter(); + $mailer = new PhabricatorMailTestAdapter(); $mail->sendWithMailers(array($mailer)); $this->assertEqual( PhabricatorMailOutboundStatus::STATUS_SENT, diff --git a/src/docs/user/configuration/configuring_outbound_email.diviner b/src/docs/user/configuration/configuring_outbound_email.diviner --- a/src/docs/user/configuration/configuring_outbound_email.diviner +++ b/src/docs/user/configuration/configuring_outbound_email.diviner @@ -85,12 +85,18 @@ used to receive inbound mail. - `outbound`: Optional bool. Use `false` to prevent this mailer from being used to send outbound mail. + - `media`: Optional list. Some mailers support delivering multiple + types of messages (like Email and SMS). If you want to configure a mailer + to support only a subset of possible message types, list only those message + types. Normally, you do not need to configure this. See below for a list + of media types. The `type` field can be used to select these third-party mailers: - `mailgun`: Use Mailgun. - `ses`: Use Amazon SES. - `sendgrid`: Use Sendgrid. + - `postmark`: Use Postmark. It also supports these local mailers: @@ -99,7 +105,11 @@ - `test`: Internal mailer for testing. Does not send mail. You can also write your own mailer by extending -`PhabricatorMailImplementationAdapter`. +`PhabricatorMailAdapter`. + +The `media` field supports these values: + + - `email`: Configure this mailer for email. Once you've selected a mailer, find the corresponding section below for instructions on configuring it. @@ -171,11 +181,13 @@ ```lang=json [ - "50.31.156.6/32" + "50.31.156.6/32", + "50.31.156.77/32", + "18.217.206.57/32" ] ``` -The default address ranges were last updated in February 2018, and were +The default address ranges were last updated in January 2019, and were documented at: diff --git a/src/infrastructure/cluster/config/PhabricatorClusterMailersConfigType.php b/src/infrastructure/cluster/config/PhabricatorClusterMailersConfigType.php --- a/src/infrastructure/cluster/config/PhabricatorClusterMailersConfigType.php +++ b/src/infrastructure/cluster/config/PhabricatorClusterMailersConfigType.php @@ -31,7 +31,7 @@ } } - $adapters = PhabricatorMailImplementationAdapter::getAllAdapters(); + $adapters = PhabricatorMailAdapter::getAllAdapters(); $map = array(); foreach ($value as $index => $spec) {