2011-05-26 19:00:26 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Mail adapter that uses SendGrid's web API to deliver email.
|
|
|
|
*/
|
2012-03-14 00:21:04 +01:00
|
|
|
final class PhabricatorMailImplementationSendGridAdapter
|
2011-05-26 19:00:26 +02:00
|
|
|
extends PhabricatorMailImplementationAdapter {
|
|
|
|
|
2018-02-06 14:23:47 +01:00
|
|
|
const ADAPTERTYPE = 'sendgrid';
|
|
|
|
|
2011-05-26 19:00:26 +02:00
|
|
|
private $params = array();
|
|
|
|
|
2018-02-06 00:58:07 +01:00
|
|
|
protected function validateOptions(array $options) {
|
|
|
|
PhutilTypeSpec::checkMap(
|
|
|
|
$options,
|
|
|
|
array(
|
|
|
|
'api-user' => 'string',
|
|
|
|
'api-key' => 'string',
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
public function newDefaultOptions() {
|
|
|
|
return array(
|
|
|
|
'api-user' => null,
|
|
|
|
'api-key' => null,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2011-05-26 19:00:26 +02:00
|
|
|
public function setFrom($email, $name = '') {
|
|
|
|
$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;
|
|
|
|
}
|
|
|
|
|
2011-10-14 21:07:29 +02:00
|
|
|
public function addAttachment($data, $filename, $mimetype) {
|
2011-11-08 23:14:00 +01:00
|
|
|
if (empty($this->params['files'])) {
|
|
|
|
$this->params['files'] = array();
|
|
|
|
}
|
|
|
|
$this->params['files'][$filename] = $data;
|
2011-10-14 21:07:29 +02:00
|
|
|
}
|
|
|
|
|
2011-05-26 19:00:26 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:04:10 +02:00
|
|
|
public function setHTMLBody($body) {
|
|
|
|
$this->params['html-body'] = $body;
|
2011-05-26 19:00:26 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-08-15 17:04:10 +02:00
|
|
|
|
|
|
|
public function setSubject($subject) {
|
|
|
|
$this->params['subject'] = $subject;
|
2011-05-26 19:00:26 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function supportsMessageIDHeader() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function send() {
|
2018-02-06 00:58:07 +01:00
|
|
|
$user = $this->getOption('api-user');
|
|
|
|
$key = $this->getOption('api-key');
|
2011-05-26 19:00:26 +02:00
|
|
|
|
|
|
|
$params = array();
|
|
|
|
|
|
|
|
$ii = 0;
|
|
|
|
foreach (idx($this->params, 'tos', array()) as $to) {
|
|
|
|
$params['to['.($ii++).']'] = $to;
|
|
|
|
}
|
|
|
|
|
|
|
|
$params['subject'] = idx($this->params, 'subject');
|
2014-08-15 17:04:10 +02:00
|
|
|
$params['text'] = idx($this->params, 'body');
|
|
|
|
|
|
|
|
if (idx($this->params, 'html-body')) {
|
|
|
|
$params['html'] = idx($this->params, 'html-body');
|
2011-05-26 19:00:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$params['from'] = idx($this->params, 'from');
|
2011-05-28 01:21:50 +02:00
|
|
|
if (idx($this->params, 'from-name')) {
|
|
|
|
$params['fromname'] = $this->params['from-name'];
|
2011-05-26 19:00:26 +02:00
|
|
|
}
|
|
|
|
|
2011-05-28 01:21:50 +02:00
|
|
|
if (idx($this->params, 'reply-to')) {
|
|
|
|
$replyto = $this->params['reply-to'];
|
2011-05-26 19:00:26 +02:00
|
|
|
|
|
|
|
// Pick off the email part, no support for the name part in this API.
|
2011-05-28 01:21:50 +02:00
|
|
|
$params['replyto'] = $replyto[0]['email'];
|
2011-05-26 19:00:26 +02:00
|
|
|
}
|
|
|
|
|
2011-11-08 23:14:00 +01:00
|
|
|
foreach (idx($this->params, 'files', array()) as $name => $data) {
|
|
|
|
$params['files['.$name.']'] = $data;
|
|
|
|
}
|
|
|
|
|
2011-05-26 19:00:26 +02:00
|
|
|
$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']));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($headers) {
|
|
|
|
// Convert to dictionary.
|
|
|
|
$headers = ipull($headers, 1, 0);
|
|
|
|
$headers = json_encode($headers);
|
|
|
|
$params['headers'] = $headers;
|
|
|
|
}
|
|
|
|
|
|
|
|
$params['api_user'] = $user;
|
|
|
|
$params['api_key'] = $key;
|
|
|
|
|
|
|
|
$future = new HTTPSFuture(
|
|
|
|
'https://sendgrid.com/api/mail.send.json',
|
|
|
|
$params);
|
2011-08-18 18:55:35 +02:00
|
|
|
$future->setMethod('POST');
|
2011-05-26 19:00:26 +02:00
|
|
|
|
2011-08-18 18:55:35 +02:00
|
|
|
list($body) = $future->resolvex();
|
2011-05-26 19:00:26 +02:00
|
|
|
|
2015-05-05 12:20:11 +02:00
|
|
|
$response = null;
|
|
|
|
try {
|
|
|
|
$response = phutil_json_decode($body);
|
|
|
|
} catch (PhutilJSONParserException $ex) {
|
|
|
|
throw new PhutilProxyException(
|
|
|
|
pht('Failed to JSON decode response.'),
|
|
|
|
$ex);
|
2011-05-26 19:00:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($response['message'] !== 'success') {
|
2014-06-09 20:36:49 +02:00
|
|
|
$errors = implode(';', $response['errors']);
|
2015-05-05 12:20:11 +02:00
|
|
|
throw new Exception(pht('Request failed with errors: %s.', $errors));
|
2011-05-26 19:00:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|