mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-02 01:48:23 +01:00
Upgrade Sendgrid to the modern mailer API; removes "api-user" option
Summary: Ref T920. Ref T5969. - Update to the new "$message" API. - Update to Sendgrid v3. - Add a timeout. - This removes the "api-user" option, which Sendgrid no longer seems to use. Test Plan: Sent Sendgrid messages with `bin/mail send-test ...` using subject/headers/attachments/html/to/cc. Reviewers: amckinley Reviewed By: amckinley Subscribers: jbrownEP Maniphest Tasks: T5969, T920 Differential Revision: https://secure.phabricator.com/D19960
This commit is contained in:
parent
d7da3560ec
commit
64e3296fe6
1 changed files with 94 additions and 123 deletions
|
@ -8,166 +8,137 @@ final class PhabricatorMailSendGridAdapter
|
||||||
|
|
||||||
const ADAPTERTYPE = 'sendgrid';
|
const ADAPTERTYPE = 'sendgrid';
|
||||||
|
|
||||||
private $params = array();
|
public function getSupportedMessageTypes() {
|
||||||
|
return array(
|
||||||
|
PhabricatorMailEmailMessage::MESSAGETYPE,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected function validateOptions(array $options) {
|
protected function validateOptions(array $options) {
|
||||||
PhutilTypeSpec::checkMap(
|
PhutilTypeSpec::checkMap(
|
||||||
$options,
|
$options,
|
||||||
array(
|
array(
|
||||||
'api-user' => 'string',
|
|
||||||
'api-key' => 'string',
|
'api-key' => 'string',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function newDefaultOptions() {
|
public function newDefaultOptions() {
|
||||||
return array(
|
return array(
|
||||||
'api-user' => null,
|
|
||||||
'api-key' => null,
|
'api-key' => null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFrom($email, $name = '') {
|
public function sendMessage(PhabricatorMailExternalMessage $message) {
|
||||||
$this->params['from'] = $email;
|
|
||||||
$this->params['from-name'] = $name;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addReplyTo($email, $name = '') {
|
|
||||||
if (empty($this->params['reply-to'])) {
|
|
||||||
$this->params['reply-to'] = array();
|
|
||||||
}
|
|
||||||
$this->params['reply-to'][] = array(
|
|
||||||
'email' => $email,
|
|
||||||
'name' => $name,
|
|
||||||
);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addTos(array $emails) {
|
|
||||||
foreach ($emails as $email) {
|
|
||||||
$this->params['tos'][] = $email;
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addCCs(array $emails) {
|
|
||||||
foreach ($emails as $email) {
|
|
||||||
$this->params['ccs'][] = $email;
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addAttachment($data, $filename, $mimetype) {
|
|
||||||
if (empty($this->params['files'])) {
|
|
||||||
$this->params['files'] = array();
|
|
||||||
}
|
|
||||||
$this->params['files'][$filename] = $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addHeader($header_name, $header_value) {
|
|
||||||
$this->params['headers'][] = array($header_name, $header_value);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setBody($body) {
|
|
||||||
$this->params['body'] = $body;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setHTMLBody($body) {
|
|
||||||
$this->params['html-body'] = $body;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function setSubject($subject) {
|
|
||||||
$this->params['subject'] = $subject;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function supportsMessageIDHeader() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send() {
|
|
||||||
$user = $this->getOption('api-user');
|
|
||||||
$key = $this->getOption('api-key');
|
$key = $this->getOption('api-key');
|
||||||
|
|
||||||
$params = array();
|
$parameters = array();
|
||||||
|
|
||||||
$ii = 0;
|
$subject = $message->getSubject();
|
||||||
foreach (idx($this->params, 'tos', array()) as $to) {
|
if ($subject !== null) {
|
||||||
$params['to['.($ii++).']'] = $to;
|
$parameters['subject'] = $subject;
|
||||||
}
|
}
|
||||||
|
|
||||||
$params['subject'] = idx($this->params, 'subject');
|
$personalizations = array();
|
||||||
$params['text'] = idx($this->params, 'body');
|
|
||||||
|
|
||||||
if (idx($this->params, 'html-body')) {
|
$to_addresses = $message->getToAddresses();
|
||||||
$params['html'] = idx($this->params, 'html-body');
|
if ($to_addresses) {
|
||||||
|
$personalizations['to'] = array();
|
||||||
|
foreach ($to_addresses as $address) {
|
||||||
|
$personalizations['to'][] = $this->newPersonalization($address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$params['from'] = idx($this->params, 'from');
|
$cc_addresses = $message->getCCAddresses();
|
||||||
if (idx($this->params, 'from-name')) {
|
if ($cc_addresses) {
|
||||||
$params['fromname'] = $this->params['from-name'];
|
$personalizations['cc'] = array();
|
||||||
|
foreach ($cc_addresses as $address) {
|
||||||
|
$personalizations['cc'][] = $this->newPersonalization($address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx($this->params, 'reply-to')) {
|
// This is a list of different sets of recipients who should receive copies
|
||||||
$replyto = $this->params['reply-to'];
|
// of the mail. We handle "one message to each recipient" ourselves.
|
||||||
|
$parameters['personalizations'] = array(
|
||||||
|
$personalizations,
|
||||||
|
);
|
||||||
|
|
||||||
// Pick off the email part, no support for the name part in this API.
|
$from_address = $message->getFromAddress();
|
||||||
$params['replyto'] = $replyto[0]['email'];
|
if ($from_address) {
|
||||||
|
$parameters['from'] = $this->newPersonalization($from_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (idx($this->params, 'files', array()) as $name => $data) {
|
$reply_address = $message->getReplyToAddress();
|
||||||
$params['files['.$name.']'] = $data;
|
if ($reply_address) {
|
||||||
}
|
$parameters['reply_to'] = $this->newPersonalization($reply_address);
|
||||||
|
|
||||||
$headers = idx($this->params, 'headers', array());
|
|
||||||
|
|
||||||
// See SendGrid Support Ticket #29390; there's no explicit REST API support
|
|
||||||
// for CC right now but it works if you add a generic "Cc" header.
|
|
||||||
//
|
|
||||||
// SendGrid said this is supported:
|
|
||||||
// "You can use CC as you are trying to do there [by adding a generic
|
|
||||||
// header]. It is supported despite our limited documentation to this
|
|
||||||
// effect, I am glad you were able to figure it out regardless. ..."
|
|
||||||
if (idx($this->params, 'ccs')) {
|
|
||||||
$headers[] = array('Cc', implode(', ', $this->params['ccs']));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$headers = $message->getHeaders();
|
||||||
if ($headers) {
|
if ($headers) {
|
||||||
// Convert to dictionary.
|
$map = array();
|
||||||
$headers = ipull($headers, 1, 0);
|
foreach ($headers as $header) {
|
||||||
$headers = json_encode($headers);
|
$map[$header->getName()] = $header->getValue();
|
||||||
$params['headers'] = $headers;
|
}
|
||||||
|
$parameters['headers'] = $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
$params['api_user'] = $user;
|
$content = array();
|
||||||
$params['api_key'] = $key;
|
$text_body = $message->getTextBody();
|
||||||
|
if ($text_body !== null) {
|
||||||
$future = new HTTPSFuture(
|
$content[] = array(
|
||||||
'https://sendgrid.com/api/mail.send.json',
|
'type' => 'text/plain',
|
||||||
$params);
|
'value' => $text_body,
|
||||||
$future->setMethod('POST');
|
);
|
||||||
|
|
||||||
list($body) = $future->resolvex();
|
|
||||||
|
|
||||||
$response = null;
|
|
||||||
try {
|
|
||||||
$response = phutil_json_decode($body);
|
|
||||||
} catch (PhutilJSONParserException $ex) {
|
|
||||||
throw new PhutilProxyException(
|
|
||||||
pht('Failed to JSON decode response.'),
|
|
||||||
$ex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response['message'] !== 'success') {
|
$html_body = $message->getHTMLBody();
|
||||||
$errors = implode(';', $response['errors']);
|
if ($html_body !== null) {
|
||||||
throw new Exception(pht('Request failed with errors: %s.', $errors));
|
$content[] = array(
|
||||||
|
'type' => 'text/html',
|
||||||
|
'value' => $html_body,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$parameters['content'] = $content;
|
||||||
|
|
||||||
|
$attachments = $message->getAttachments();
|
||||||
|
if ($attachments) {
|
||||||
|
$files = array();
|
||||||
|
foreach ($attachments as $attachment) {
|
||||||
|
$files[] = array(
|
||||||
|
'content' => base64_encode($attachment->getData()),
|
||||||
|
'type' => $attachment->getMimeType(),
|
||||||
|
'filename' => $attachment->getFilename(),
|
||||||
|
'disposition' => 'attachment',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$parameters['attachments'] = $files;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
$sendgrid_uri = 'https://api.sendgrid.com/v3/mail/send';
|
||||||
|
$json_parameters = phutil_json_encode($parameters);
|
||||||
|
|
||||||
|
id(new HTTPSFuture($sendgrid_uri))
|
||||||
|
->setMethod('POST')
|
||||||
|
->addHeader('Authorization', "Bearer {$key}")
|
||||||
|
->addHeader('Content-Type', 'application/json')
|
||||||
|
->setData($json_parameters)
|
||||||
|
->setTimeout(60)
|
||||||
|
->resolvex();
|
||||||
|
|
||||||
|
// The SendGrid v3 API does not return a JSON response body. We get a
|
||||||
|
// non-2XX HTTP response in the case of an error, which throws above.
|
||||||
|
}
|
||||||
|
|
||||||
|
private function newPersonalization(PhutilEmailAddress $address) {
|
||||||
|
$result = array(
|
||||||
|
'email' => $address->getAddress(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$display_name = $address->getDisplayName();
|
||||||
|
if ($display_name) {
|
||||||
|
$result['name'] = $display_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue