1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-28 15:38:19 +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:
epriestley 2011-05-26 10:00:26 -07:00
parent 686ffafa21
commit dbedb012eb
5 changed files with 218 additions and 6 deletions

View file

@ -143,6 +143,12 @@ return array(
'amazon-ses.access-key' => null, 'amazon-ses.access-key' => null,
'amazon-ses.secret-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 // 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" // 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 // that allows recipients to reply by email and interact with tasks. For

View file

@ -339,6 +339,7 @@ phutil_register_library_map(array(
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base',
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses', 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/amazonses',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite',
'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/sendgrid',
'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test', 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/test',
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/base', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/base',
'PhabricatorMetaMTAController' => 'applications/metamta/controller/base', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/base',
@ -772,6 +773,7 @@ phutil_register_library_map(array(
'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorLogoutController' => 'PhabricatorAuthController',
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTAController' => 'PhabricatorController',
'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO',

View file

@ -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;
}
}

View 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');

View file

@ -5,17 +5,18 @@ Instructions for configuring Phabricator to send mail.
= Overview = = 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 Amazon SES (Simple Email Service); or
- by using SendGrid's REST API; or
- via a custom adapter you write; or - via a custom adapter you write; or
- by dropping email into a hole and not delivering it. - by dropping email into a hole and not delivering it.
Of these, ##sendmail## is the default but requires some configuration. SES is Of these, ##sendmail## is the default but requires some configuration. SES and
the easiest but costs money and has some limitations. Writing a custom solution SendGrid are easier, but cost money and have some limitations. Writing a custom
requires digging into the code. See below for details on how to set up each solution requires digging into the code. See below for details on how to set up
method. each method.
Phabricator can also send outbound email in two ways: Phabricator can also send outbound email in two ways:
@ -50,6 +51,8 @@ your configuration. Possible values are:
"sendmail", see "Adapter: Sendmail". "sendmail", see "Adapter: Sendmail".
- ##PhabricatorMailImplementationAmazonSESAdapter##: use Amazon SES, see - ##PhabricatorMailImplementationAmazonSESAdapter##: use Amazon SES, see
"Adapter: Amazon SES". "Adapter: Amazon SES".
- ##PhabricatorMailImplementationSendGridAdapter##: use SendGrid, see
"Adapter: SendGrid".
- ##Some Custom Class You Write##: use a custom adapter you write, see - ##Some Custom Class You Write##: use a custom adapter you write, see
"Adapter: Custom". "Adapter: Custom".
- ##PhabricatorMailImplementationTestAdapter##: this will - ##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 performance will improve greatly if you configure outbound email to send in
the background. 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 = = Adapter: Custom =
You can provide a custom adapter by writing a concrete subclass of You can provide a custom adapter by writing a concrete subclass of