Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14046652
D7989.id18119.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.id18119.diff
View Options
Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -1574,6 +1574,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',
@@ -1589,6 +1590,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',
@@ -1620,6 +1622,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',
@@ -4194,6 +4197,7 @@
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
+ 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter',
@@ -4207,6 +4211,7 @@
'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow',
'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow',
'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase',
+ 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorMailingListPHIDTypeList' => 'PhabricatorPHIDType',
'PhabricatorMailingListQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorMailingListSearchEngine' => 'PhabricatorApplicationSearchEngine',
@@ -4235,6 +4240,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,27 @@
+<?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,124 @@
+<?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) {
+ 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 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(
+ pht('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
Thu, Nov 14, 10:39 PM (5 d, 7 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6767681
Default Alt Text
D7989.id18119.diff (11 KB)
Attached To
Mode
D7989: Mailgun receive support
Attached
Detach File
Event Timeline
Log In to Comment