mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-09 16:32:39 +01:00
Add support for SendGrid as an outbound mail adapter
Summary: SendGrid is a popular mail delivery platform, similar to Amazon SES. Provide support for delivering email via their REST API. Test Plan: Created a SendGrid account, configured my local install to use it, sent some mail, received mail. Reviewers: tuomaspelkonen, jungejason, aran CC: ccheever Differential Revision: 347
This commit is contained in:
parent
686ffafa21
commit
dbedb012eb
5 changed files with 218 additions and 6 deletions
|
@ -143,6 +143,12 @@ return array(
|
|||
'amazon-ses.access-key' => null,
|
||||
'amazon-ses.secret-key' => null,
|
||||
|
||||
// If you're using Sendgrid to send email, provide your access credentials
|
||||
// here. This will use the REST API. You can also use Sendgrid as a normal
|
||||
// SMTP service.
|
||||
'sendgrid.api-user' => null,
|
||||
'sendgrid.api-key' => null,
|
||||
|
||||
// You can configure a reply handler domain so that email sent from Maniphest
|
||||
// will have a special "Reply To" address like "T123+82+af19f@example.com"
|
||||
// that allows recipients to reply by email and interact with tasks. For
|
||||
|
|
|
@ -339,6 +339,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
|
||||
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
|
||||
'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/sendgrid',
|
||||
'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test',
|
||||
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/base',
|
||||
'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
|
||||
|
@ -772,6 +773,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorLogoutController' => 'PhabricatorAuthController',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
|
||||
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||
'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||
'PhabricatorMetaMTAController' => 'PhabricatorController',
|
||||
'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Mail adapter that uses SendGrid's web API to deliver email.
|
||||
*/
|
||||
class PhabricatorMailImplementationSendGridAdapter
|
||||
extends PhabricatorMailImplementationAdapter {
|
||||
|
||||
private $params = array();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 setSubject($subject) {
|
||||
$this->params['subject'] = $subject;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setIsHTML($is_html) {
|
||||
$this->params['is-html'] = $is_html;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function supportsMessageIDHeader() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function send() {
|
||||
|
||||
$user = PhabricatorEnv::getEnvConfig('sendgrid.api-user');
|
||||
$key = PhabricatorEnv::getEnvConfig('sendgrid.api-key');
|
||||
|
||||
if (!$user || !$key) {
|
||||
throw new Exception(
|
||||
"Configure 'sendgrid.api-user' and 'sendgrid.api-key' to use ".
|
||||
"SendGrid for mail delivery.");
|
||||
}
|
||||
|
||||
$params = array();
|
||||
|
||||
$ii = 0;
|
||||
foreach (idx($this->params, 'tos', array()) as $to) {
|
||||
$params['to['.($ii++).']'] = $to;
|
||||
}
|
||||
|
||||
$params['subject'] = idx($this->params, 'subject');
|
||||
if (idx($this->params, 'is-html')) {
|
||||
$params['html'] = idx($this->params, 'body');
|
||||
} else {
|
||||
$params['text'] = idx($this->params, 'body');
|
||||
}
|
||||
|
||||
$params['from'] = idx($this->params, 'from');
|
||||
if (idx($this->params['from-name'])) {
|
||||
$params['fromname'] = idx($this->params, 'fromname');
|
||||
}
|
||||
|
||||
if (idx($this->params, 'replyto')) {
|
||||
$replyto = $this->params['replyto'];
|
||||
|
||||
// Pick off the email part, no support for the name part in this API.
|
||||
$params['replyto'] = $replyto[0];
|
||||
}
|
||||
|
||||
$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);
|
||||
|
||||
list($code, $body) = $future->resolve();
|
||||
|
||||
if ($code !== 200) {
|
||||
throw new Exception("REST API call failed with HTTP code {$code}.");
|
||||
}
|
||||
|
||||
$response = json_decode($body, true);
|
||||
if (!is_array($response)) {
|
||||
throw new Exception("Failed to JSON decode response: {$body}");
|
||||
}
|
||||
|
||||
if ($response['message'] !== 'success') {
|
||||
$errors = implode(";", $response['errors']);
|
||||
throw new Exception("Request failed with errors: {$errors}.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
16
src/applications/metamta/adapter/sendgrid/__init__.php
Normal file
16
src/applications/metamta/adapter/sendgrid/__init__.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/metamta/adapter/base');
|
||||
phutil_require_module('phabricator', 'infrastructure/env');
|
||||
|
||||
phutil_require_module('phutil', 'future/https');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorMailImplementationSendGridAdapter.php');
|
|
@ -5,17 +5,18 @@ Instructions for configuring Phabricator to send mail.
|
|||
|
||||
= Overview =
|
||||
|
||||
Phabricator can send outbound email via four different adapters:
|
||||
Phabricator can send outbound email via several different adapters:
|
||||
|
||||
- by running ##sendmail## on the local host; or
|
||||
- by running ##sendmail## on the local host with SMTP; or
|
||||
- by using Amazon SES (Simple Email Service); or
|
||||
- by using SendGrid's REST API; or
|
||||
- via a custom adapter you write; or
|
||||
- by dropping email into a hole and not delivering it.
|
||||
|
||||
Of these, ##sendmail## is the default but requires some configuration. SES is
|
||||
the easiest but costs money and has some limitations. Writing a custom solution
|
||||
requires digging into the code. See below for details on how to set up each
|
||||
method.
|
||||
Of these, ##sendmail## is the default but requires some configuration. SES and
|
||||
SendGrid are easier, but cost money and have some limitations. Writing a custom
|
||||
solution requires digging into the code. See below for details on how to set up
|
||||
each method.
|
||||
|
||||
Phabricator can also send outbound email in two ways:
|
||||
|
||||
|
@ -50,6 +51,8 @@ your configuration. Possible values are:
|
|||
"sendmail", see "Adapter: Sendmail".
|
||||
- ##PhabricatorMailImplementationAmazonSESAdapter##: use Amazon SES, see
|
||||
"Adapter: Amazon SES".
|
||||
- ##PhabricatorMailImplementationSendGridAdapter##: use SendGrid, see
|
||||
"Adapter: SendGrid".
|
||||
- ##Some Custom Class You Write##: use a custom adapter you write, see
|
||||
"Adapter: Custom".
|
||||
- ##PhabricatorMailImplementationTestAdapter##: this will
|
||||
|
@ -90,6 +93,25 @@ NOTE: Amazon SES is slow to accept mail (often 1-2 seconds) and application
|
|||
performance will improve greatly if you configure outbound email to send in
|
||||
the background.
|
||||
|
||||
= Adapter: SendGrid =
|
||||
|
||||
SendGrid is an email delivery service like Amazon SES. You can learn more at
|
||||
<http://sendgrid.com/>. It is easy to configure, but not free.
|
||||
|
||||
You can configure SendGrid in two ways: you can send via SMTP or via the REST
|
||||
API. To use SMTP, just configure ##sendmail## and leave Phabricator's setup
|
||||
with defaults. To use the REST API, follow the instructions in this section.
|
||||
|
||||
To configure Phabricator to use SendGrid, set these configuration keys:
|
||||
|
||||
- **metamta.mail-adapter**: set to
|
||||
"PhabricatorMailImplementationSendGridAdapter".
|
||||
- **sendgrid.api-user**: set to your SendGrid login name.
|
||||
- **sendgrid.api-key**: set to your SendGrid password.
|
||||
|
||||
If you're logged into your SendGrid account, you may be able to find this
|
||||
information easily by visiting <http://sendgrid.com/developer>.
|
||||
|
||||
= Adapter: Custom =
|
||||
|
||||
You can provide a custom adapter by writing a concrete subclass of
|
||||
|
|
Loading…
Reference in a new issue