Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15415778
D7989.id18151.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D7989.id18151.diff
View Options
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -1575,6 +1575,7 @@
'PhabricatorMail' => 'applications/metamta/PhabricatorMail.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',
'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php',
@@ -1590,6 +1591,7 @@
'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php',
'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php',
'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php',
+ 'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php',
'PhabricatorMailingListPHIDTypeList' => 'applications/mailinglists/phid/PhabricatorMailingListPHIDTypeList.php',
'PhabricatorMailingListQuery' => 'applications/mailinglists/query/PhabricatorMailingListQuery.php',
'PhabricatorMailingListSearchEngine' => 'applications/mailinglists/query/PhabricatorMailingListSearchEngine.php',
@@ -1621,6 +1623,7 @@
'PhabricatorMetaMTAMailBody' => 'applications/metamta/view/PhabricatorMetaMTAMailBody.php',
'PhabricatorMetaMTAMailBodyTestCase' => 'applications/metamta/view/__tests__/PhabricatorMetaMTAMailBodyTestCase.php',
'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php',
+ 'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php',
'PhabricatorMetaMTAMailingList' => 'applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php',
'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php',
'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php',
@@ -4211,6 +4214,7 @@
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
+ 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
@@ -4224,6 +4228,7 @@
'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow',
'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorMailingListPHIDTypeList' => 'PhabricatorPHIDType',
'PhabricatorMailingListQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorMailingListSearchEngine' => 'PhabricatorApplicationSearchEngine',
@@ -4253,6 +4258,7 @@
'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase',
'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorMetaMTAMailgunReceiveController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMailingList' =>
array(
0 => 'PhabricatorMetaMTADAO',
Index: src/applications/config/option/PhabricatorMailgunConfigOptions.php
===================================================================
--- /dev/null
+++ src/applications/config/option/PhabricatorMailgunConfigOptions.php
@@ -0,0 +1,28 @@
+<?php
+
+final class PhabricatorMailgunConfigOptions
+ extends PhabricatorApplicationConfigOptions {
+
+ public function getName() {
+ return pht("Integration with Mailgun");
+ }
+
+ public function getDescription() {
+ return pht("Configure Mailgun integration.");
+ }
+
+ public function getOptions() {
+ return array(
+ $this->newOption('mailgun.api-key', 'string', null)
+ ->setMasked(true)
+ ->setDescription(pht('Mailgun API key.')),
+ $this->newOption('mailgun.domain', 'string', null)
+ ->setDescription(
+ pht(
+ 'Mailgun domain name. See https://mailgun.com/cp/domains'))
+ ->addExample('mycompany.com', 'Use specific domain'),
+ );
+
+ }
+
+}
Index: src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php
===================================================================
--- /dev/null
+++ src/applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * Mail adapter that uses Mailgun's web API to deliver email.
+ */
+final class PhabricatorMailImplementationMailgunAdapter
+ 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 addAttachment($data, $filename, $mimetype) {
+ // TODO: implement attachments. Requires changes in HTTPSFuture
+ throw new Exception(
+ "Mailgun adapter does not currently support attachments.");
+ }
+
+ 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() {
+ $key = PhabricatorEnv::getEnvConfig('mailgun.api-key');
+ $domain = PhabricatorEnv::getEnvConfig('mailgun.domain');
+ $params = array();
+
+ $params['to'] = idx($this->params, 'tos', array());
+ $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');
+ }
+
+ $from = idx($this->params, 'from');
+ if (idx($this->params, 'from-name')) {
+ $params['from'] = "{$this->params['from-name']} <{$from}>";
+ } else {
+ $params['from'] = $from;
+ }
+
+ if (idx($this->params, 'reply-to')) {
+ $replyto = $this->params['reply-to'];
+ $params['h:reply-to'] = $replyto;
+ }
+
+ if (idx($this->params, 'ccs')) {
+ $params['cc'] = $this->params['ccs'];
+ }
+
+ $future = new HTTPSFuture(
+ "https://api:{$key}@api.mailgun.net/v2/{$domain}/messages",
+ $params);
+ $future->setMethod('POST');
+
+ list($body) = $future->resolvex();
+
+ $response = json_decode($body, true);
+ if (!is_array($response)) {
+ throw new Exception("Failed to JSON decode response: {$body}");
+ }
+
+ if (!idx($response, 'id')) {
+ $message = $response['message'];
+ throw new Exception("Request failed with errors: {$message}.");
+ }
+
+ return true;
+ }
+
+}
Index: src/applications/metamta/application/PhabricatorApplicationMetaMTA.php
===================================================================
--- src/applications/metamta/application/PhabricatorApplicationMetaMTA.php
+++ src/applications/metamta/application/PhabricatorApplicationMetaMTA.php
@@ -34,6 +34,7 @@
return array(
$this->getBaseURI() => array(
'sendgrid/' => 'PhabricatorMetaMTASendGridReceiveController',
+ 'mailgun/' => 'PhabricatorMetaMTAMailgunReceiveController',
),
);
}
Index: src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
===================================================================
--- /dev/null
+++ src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
@@ -0,0 +1,76 @@
+<?php
+
+final class PhabricatorMetaMTAMailgunReceiveController
+ extends PhabricatorMetaMTAController {
+
+ public function shouldRequireLogin() {
+ return false;
+ }
+
+ private function verifyMessage() {
+ $api_key = PhabricatorEnv::getEnvConfig('mailgun.api-key');
+ $request = $this->getRequest();
+ $timestamp = $request->getStr('timestamp');
+ $token = $request->getStr('token');
+ $sig = $request->getStr('signature');
+ return hash_hmac('sha256', $timestamp.$token, $api_key) == $sig;
+
+ }
+ public function processRequest() {
+
+ // No CSRF for Mailgun.
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+
+ if (!$this->verifyMessage()) {
+ throw new Exception(
+ 'Mail signature is not valid. Check your Mailgun API key.');
+ }
+
+ $request = $this->getRequest();
+ $user = $request->getUser();
+
+ $raw_headers = $request->getStr('headers');
+ $raw_headers = explode("\n", rtrim($raw_headers));
+ $raw_dict = array();
+ foreach (array_filter($raw_headers) as $header) {
+ list($name, $value) = explode(':', $header, 2);
+ $raw_dict[$name] = ltrim($value);
+ }
+
+ $headers = array(
+ 'to' => $request->getStr('recipient'),
+ 'from' => $request->getStr('from'),
+ 'subject' => $request->getStr('subject'),
+ ) + $raw_dict;
+
+ $received = new PhabricatorMetaMTAReceivedMail();
+ $received->setHeaders($headers);
+ $received->setBodies(array(
+ 'text' => $request->getStr('stripped-text'),
+ 'html' => $request->getStr('stripped-html'),
+ ));
+
+ $file_phids = array();
+ foreach ($_FILES as $file_raw) {
+ try {
+ $file = PhabricatorFile::newFromPHPUpload(
+ $file_raw,
+ array(
+ 'authorPHID' => $user->getPHID(),
+ ));
+ $file_phids[] = $file->getPHID();
+ } catch (Exception $ex) {
+ phlog($ex);
+ }
+ }
+ $received->setAttachments($file_phids);
+ $received->save();
+
+ $received->processReceivedMail();
+
+ $response = new AphrontWebpageResponse();
+ $response->setContent(pht("Got it! Thanks, Mailgun!\n"));
+ return $response;
+ }
+
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Mar 21, 7:50 AM (1 d, 18 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7223644
Default Alt Text
D7989.id18151.diff (11 KB)
Attached To
Mode
D7989: Mailgun receive support
Attached
Detach File
Event Timeline
Log In to Comment