mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Update Postmark adapter for multiple mail media
Summary: Depends on D19955. Ref T920. Ref T5969. Update Postmark to accept new Message objects. Also: - Update the inbound whitelist. - Add a little support for `media` configuration. - Add a service call timeout (see T5969). - Drop the needless word "Implementation" from the Adapter class tree. I could call these "Mailers" instead of "Adapters", but then we get "PhabricatorMailMailer" which feels questionable. Test Plan: Used `bin/mail send-test` to send mail via Postmark with various options (mulitple recipients, text vs html, attachments). Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T5969, T920 Differential Revision: https://secure.phabricator.com/D19956
This commit is contained in:
parent
b5797ce60a
commit
a8657e6ab6
18 changed files with 272 additions and 208 deletions
|
@ -3387,6 +3387,8 @@ phutil_register_library_map(array(
|
|||
'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 @@ phutil_register_library_map(array(
|
|||
'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 @@ 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',
|
||||
'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 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorMacroTransactionType' => 'PhabricatorModularTransactionType',
|
||||
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMailAdapter' => 'Phobject',
|
||||
'PhabricatorMailAmazonSESAdapter' => 'PhabricatorMailPHPMailerLiteAdapter',
|
||||
'PhabricatorMailAttachment' => 'Phobject',
|
||||
'PhabricatorMailConfigTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorMailEmailEngine' => 'PhabricatorMailMessageEngine',
|
||||
|
@ -9231,14 +9233,7 @@ phutil_register_library_map(array(
|
|||
'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 @@ 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',
|
||||
'PhabricatorMailSendGridAdapter' => 'PhabricatorMailAdapter',
|
||||
'PhabricatorMailSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorMailStamp' => 'Phobject',
|
||||
'PhabricatorMailTarget' => 'Phobject',
|
||||
'PhabricatorMailTestAdapter' => 'PhabricatorMailAdapter',
|
||||
'PhabricatorMailUtil' => 'Phobject',
|
||||
'PhabricatorMainMenuBarExtension' => 'Phobject',
|
||||
'PhabricatorMainMenuSearchView' => 'AphrontView',
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
||||
abstract class PhabricatorMailAdapter
|
||||
extends Phobject {
|
||||
|
||||
private $key;
|
||||
private $priority;
|
||||
private $media;
|
||||
private $options = array();
|
||||
|
||||
private $supportsInbound = true;
|
||||
private $supportsOutbound = true;
|
||||
private $mediaMap;
|
||||
|
||||
final public function getAdapterType() {
|
||||
return $this->getPhobjectClassConstant('ADAPTERTYPE');
|
||||
|
@ -20,37 +23,67 @@ abstract class PhabricatorMailImplementationAdapter extends Phobject {
|
|||
->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 class PhabricatorMailImplementationAdapter extends Phobject {
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailImplementationAmazonSESAdapter
|
||||
extends PhabricatorMailImplementationPHPMailerLiteAdapter {
|
||||
final class PhabricatorMailAmazonSESAdapter
|
||||
extends PhabricatorMailPHPMailerLiteAdapter {
|
||||
|
||||
const ADAPTERTYPE = 'ses';
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailImplementationPostmarkAdapter
|
||||
extends PhabricatorMailImplementationAdapter {
|
||||
|
||||
const ADAPTERTYPE = 'postmark';
|
||||
|
||||
private $parameters = array();
|
||||
|
||||
public function setFrom($email, $name = '') {
|
||||
$this->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<string>',
|
||||
));
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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';
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailImplementationPHPMailerAdapter
|
||||
extends PhabricatorMailImplementationAdapter {
|
||||
final class PhabricatorMailPHPMailerAdapter
|
||||
extends PhabricatorMailAdapter {
|
||||
|
||||
const ADAPTERTYPE = 'smtp';
|
||||
|
|
@ -2,9 +2,11 @@
|
|||
|
||||
/**
|
||||
* TODO: Should be final, but inherited by SES.
|
||||
*
|
||||
* @concrete-extensible
|
||||
*/
|
||||
class PhabricatorMailImplementationPHPMailerLiteAdapter
|
||||
extends PhabricatorMailImplementationAdapter {
|
||||
class PhabricatorMailPHPMailerLiteAdapter
|
||||
extends PhabricatorMailAdapter {
|
||||
|
||||
const ADAPTERTYPE = 'sendmail';
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMailPostmarkAdapter
|
||||
extends PhabricatorMailAdapter {
|
||||
|
||||
const ADAPTERTYPE = 'postmark';
|
||||
|
||||
public function getSupportedMessageTypes() {
|
||||
return array(
|
||||
PhabricatorMailEmailMessage::MESSAGETYPE,
|
||||
);
|
||||
}
|
||||
|
||||
public function supportsMessageIDHeader() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function validateOptions(array $options) {
|
||||
PhutilTypeSpec::checkMap(
|
||||
$options,
|
||||
array(
|
||||
'access-token' => 'string',
|
||||
'inbound-addresses' => 'list<string>',
|
||||
));
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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';
|
||||
|
|
@ -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';
|
||||
|
|
@ -21,7 +21,7 @@ final class PhabricatorMetaMTAMailgunReceiveController
|
|||
array(
|
||||
'inbound' => true,
|
||||
'types' => array(
|
||||
PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE,
|
||||
PhabricatorMailMailgunAdapter::ADAPTERTYPE,
|
||||
),
|
||||
));
|
||||
foreach ($mailers as $mailer) {
|
||||
|
|
|
@ -16,7 +16,7 @@ final class PhabricatorMetaMTAPostmarkReceiveController
|
|||
array(
|
||||
'inbound' => true,
|
||||
'types' => array(
|
||||
PhabricatorMailImplementationPostmarkAdapter::ADAPTERTYPE,
|
||||
PhabricatorMailPostmarkAdapter::ADAPTERTYPE,
|
||||
),
|
||||
));
|
||||
if (!$mailers) {
|
||||
|
|
|
@ -15,7 +15,7 @@ final class PhabricatorMetaMTASendGridReceiveController
|
|||
array(
|
||||
'inbound' => true,
|
||||
'types' => array(
|
||||
PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE,
|
||||
PhabricatorMailSendGridAdapter::ADAPTERTYPE,
|
||||
),
|
||||
));
|
||||
if (!$mailers) {
|
||||
|
|
|
@ -8,8 +8,7 @@ abstract class PhabricatorMailMessageEngine
|
|||
private $actors = array();
|
||||
private $preferences;
|
||||
|
||||
final public function setMailer(
|
||||
PhabricatorMailImplementationAdapter $mailer) {
|
||||
final public function setMailer(PhabricatorMailAdapter $mailer) {
|
||||
|
||||
$this->mailer = $mailer;
|
||||
return $this;
|
||||
|
|
|
@ -547,13 +547,14 @@ final class PhabricatorMetaMTAMail
|
|||
'types' => 'optional list<string>',
|
||||
'inbound' => 'optional bool',
|
||||
'outbound' => 'optional bool',
|
||||
'media' => 'optional list<string>',
|
||||
));
|
||||
|
||||
$mailers = array();
|
||||
|
||||
$config = PhabricatorEnv::getEnvConfig('cluster.mailers');
|
||||
|
||||
$adapters = PhabricatorMailImplementationAdapter::getAllAdapters();
|
||||
$adapters = PhabricatorMailAdapter::getAllAdapters();
|
||||
$next_priority = -1;
|
||||
|
||||
foreach ($config as $spec) {
|
||||
|
@ -583,6 +584,11 @@ final class PhabricatorMetaMTAMail
|
|||
$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 @@ final class PhabricatorMetaMTAMail
|
|||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -17,7 +17,7 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
$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 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
$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 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
$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 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
$user = $this->generateNewTestUser();
|
||||
$phid = $user->getPHID();
|
||||
|
||||
$mailer = new PhabricatorMailImplementationTestAdapter();
|
||||
$mailer = new PhabricatorMailTestAdapter();
|
||||
|
||||
$mail = new PhabricatorMetaMTAMail();
|
||||
$mail->addTos(array($phid));
|
||||
|
@ -182,7 +182,7 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
$supports_message_id,
|
||||
$is_first_mail) {
|
||||
|
||||
$mailer = new PhabricatorMailImplementationTestAdapter();
|
||||
$mailer = new PhabricatorMailTestAdapter();
|
||||
|
||||
$mailer->prepareForSend(
|
||||
array(
|
||||
|
@ -261,10 +261,10 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
$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 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
->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 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
->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 @@ final class PhabricatorMetaMTAMailTestCase extends PhabricatorTestCase {
|
|||
->setBody($string_1kb)
|
||||
->setHTMLBody($html_1mb);
|
||||
|
||||
$mailer = new PhabricatorMailImplementationTestAdapter();
|
||||
$mailer = new PhabricatorMailTestAdapter();
|
||||
$mail->sendWithMailers(array($mailer));
|
||||
$this->assertEqual(
|
||||
PhabricatorMailOutboundStatus::STATUS_SENT,
|
||||
|
|
|
@ -85,12 +85,18 @@ The supported keys for each mailer are:
|
|||
used to receive inbound mail.
|
||||
- `outbound`: Optional bool. Use `false` to prevent this mailer from being
|
||||
used to send outbound mail.
|
||||
- `media`: Optional list<string>. 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 @@ It also supports these local mailers:
|
|||
- `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 @@ The option accepts a list of CIDR ranges, like `1.2.3.4/16` (IPv4) or
|
|||
|
||||
```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: <https://postmarkapp.com/support/article/800-ips-for-firewalls>
|
||||
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ final class PhabricatorClusterMailersConfigType
|
|||
}
|
||||
}
|
||||
|
||||
$adapters = PhabricatorMailImplementationAdapter::getAllAdapters();
|
||||
$adapters = PhabricatorMailAdapter::getAllAdapters();
|
||||
|
||||
$map = array();
|
||||
foreach ($value as $index => $spec) {
|
||||
|
|
Loading…
Reference in a new issue