Page MenuHomePhabricator

D19017.id45613.diff
No OneTemporary

D19017.id45613.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3272,6 +3272,7 @@
'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php',
'PhabricatorMetaMTAMemberQuery' => 'applications/metamta/query/PhabricatorMetaMTAMemberQuery.php',
'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php',
+ 'PhabricatorMetaMTAPostmarkReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php',
'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php',
'PhabricatorMetaMTAReceivedMailProcessingException' => 'applications/metamta/exception/PhabricatorMetaMTAReceivedMailProcessingException.php',
'PhabricatorMetaMTAReceivedMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php',
@@ -8787,6 +8788,7 @@
'PhabricatorMetaMTAMailgunReceiveController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAMemberQuery' => 'PhabricatorQuery',
'PhabricatorMetaMTAPermanentFailureException' => 'Exception',
+ 'PhabricatorMetaMTAPostmarkReceiveController' => 'PhabricatorMetaMTAController',
'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO',
'PhabricatorMetaMTAReceivedMailProcessingException' => 'Exception',
'PhabricatorMetaMTAReceivedMailTestCase' => 'PhabricatorTestCase',
diff --git a/src/applications/metamta/application/PhabricatorMetaMTAApplication.php b/src/applications/metamta/application/PhabricatorMetaMTAApplication.php
--- a/src/applications/metamta/application/PhabricatorMetaMTAApplication.php
+++ b/src/applications/metamta/application/PhabricatorMetaMTAApplication.php
@@ -42,6 +42,7 @@
'detail/(?P<id>[1-9]\d*)/' => 'PhabricatorMetaMTAMailViewController',
'sendgrid/' => 'PhabricatorMetaMTASendGridReceiveController',
'mailgun/' => 'PhabricatorMetaMTAMailgunReceiveController',
+ 'postmark/' => 'PhabricatorMetaMTAPostmarkReceiveController',
),
);
}
diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
--- a/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
+++ b/src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
@@ -17,15 +17,12 @@
// inbound mail from any of them. Test the signature to see if it matches
// any configured Mailgun mailer.
- $mailers = PhabricatorMetaMTAMail::newMailers();
- $mailgun_type = PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE;
+ $mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
+ array(
+ PhabricatorMailImplementationMailgunAdapter::ADAPTERTYPE,
+ ));
foreach ($mailers as $mailer) {
- if ($mailer->getAdapterType() != $mailgun_type) {
- continue;
- }
-
$api_key = $mailer->getOption('api-key');
-
$hash = hash_hmac('sha256', $timestamp.$token, $api_key);
if (phutil_hashes_are_identical($sig, $hash)) {
return true;
diff --git a/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php
new file mode 100644
--- /dev/null
+++ b/src/applications/metamta/controller/PhabricatorMetaMTAPostmarkReceiveController.php
@@ -0,0 +1,87 @@
+<?php
+
+final class PhabricatorMetaMTAPostmarkReceiveController
+ extends PhabricatorMetaMTAController {
+
+ public function shouldRequireLogin() {
+ return false;
+ }
+
+ /**
+ * @phutil-external-symbol class PhabricatorStartup
+ */
+ public function handleRequest(AphrontRequest $request) {
+ // Don't process requests if we don't have a configured Postmark adapter.
+ $mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
+ array(
+ PhabricatorMailImplementationPostmarkAdapter::ADAPTERTYPE,
+ ));
+ if (!$mailers) {
+ return new Aphront404Response();
+ }
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+ $raw_input = PhabricatorStartup::getRawInput();
+
+ try {
+ $data = phutil_json_decode($raw_input);
+ } catch (Exception $ex) {
+ return new Aphront400Response();
+ }
+
+ $raw_headers = array();
+ $header_items = idx($data, 'Headers', array());
+ foreach ($header_items as $header_item) {
+ $name = idx($header_item, 'Name');
+ $value = idx($header_item, 'Value');
+ $raw_headers[$name] = $value;
+ }
+
+ $headers = array(
+ 'to' => idx($data, 'To'),
+ 'from' => idx($data, 'From'),
+ 'cc' => idx($data, 'Cc'),
+ 'subject' => idx($data, 'Subject'),
+ ) + $raw_headers;
+
+
+ $received = id(new PhabricatorMetaMTAReceivedMail())
+ ->setHeaders($headers)
+ ->setBodies(
+ array(
+ 'text' => idx($data, 'TextBody'),
+ 'html' => idx($data, 'HtmlBody'),
+ ));
+
+ $file_phids = array();
+ $attachments = idx($data, 'Attachments', array());
+ foreach ($attachments as $attachment) {
+ $file_data = idx($attachment, 'Content');
+ $file_data = base64_decode($file_data);
+
+ try {
+ $file = PhabricatorFile::newFromFileData(
+ $file_data,
+ array(
+ 'name' => idx($attachment, 'Name'),
+ 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
+ ));
+ $file_phids[] = $file->getPHID();
+ } catch (Exception $ex) {
+ phlog($ex);
+ }
+ }
+ $received->setAttachments($file_phids);
+
+ try {
+ $received->save();
+ $received->processReceivedMail();
+ } catch (Exception $ex) {
+ phlog($ex);
+ }
+
+ return id(new AphrontWebpageResponse())
+ ->setContent(pht("Got it! Thanks, Postmark!\n"));
+ }
+
+}
diff --git a/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php b/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php
--- a/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php
+++ b/src/applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php
@@ -8,24 +8,14 @@
}
public function handleRequest(AphrontRequest $request) {
- $mailers = PhabricatorMetaMTAMail::newMailers();
- $sendgrid_type = PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE;
-
// SendGrid doesn't sign payloads so we can't be sure that SendGrid
// actually sent this request, but require a configured SendGrid mailer
// before we activate this endpoint.
-
- $has_sendgrid = false;
- foreach ($mailers as $mailer) {
- if ($mailer->getAdapterType() != $sendgrid_type) {
- continue;
- }
-
- $has_sendgrid = true;
- break;
- }
-
- if (!$has_sendgrid) {
+ $mailers = PhabricatorMetaMTAMail::newMailersWithTypes(
+ array(
+ PhabricatorMailImplementationSendGridAdapter::ADAPTERTYPE,
+ ));
+ if (!$mailers) {
return new Aphront404Response();
}
diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php
--- a/src/applications/metamta/storage/PhabricatorMetaMTAMail.php
+++ b/src/applications/metamta/storage/PhabricatorMetaMTAMail.php
@@ -482,6 +482,20 @@
return $this->sendWithMailers($mailers);
}
+ public static function newMailersWithTypes(array $types) {
+ $mailers = self::newMailers();
+ $types = array_fuse($types);
+
+ foreach ($mailers as $key => $mailer) {
+ $mailer_type = $mailer->getAdapterType();
+ if (!isset($types[$mailer_type])) {
+ unset($mailers[$key]);
+ }
+ }
+
+ return array_values($mailers);
+ }
+
public static function newMailers() {
$mailers = array();
diff --git a/src/docs/user/configuration/configuring_inbound_email.diviner b/src/docs/user/configuration/configuring_inbound_email.diviner
--- a/src/docs/user/configuration/configuring_inbound_email.diviner
+++ b/src/docs/user/configuration/configuring_inbound_email.diviner
@@ -14,6 +14,7 @@
| Receive Mail With | Setup | Cost | Notes |
|--------|-------|------|-------|
| Mailgun | Easy | Cheap | Recommended |
+| Postmark | Easy | Cheap | Recommended |
| SendGrid | Easy | Cheap | |
| Local MTA | Extremely Difficult | Free | Strongly discouraged! |
@@ -130,6 +131,17 @@
example domain with your actual domain.
- Set the `mailgun.api-key` config key to your Mailgun API key.
+Postmark Setup
+==============
+
+To process inbound mail from Postmark, configure this URI as your inbound
+webhook URI in the Postmark control panel:
+
+```
+https://<phabricator.yourdomain.com>/mail/postmark/
+```
+
+
= SendGrid Setup =
To use SendGrid, you need a SendGrid account with access to the "Parse API" for

File Metadata

Mime Type
text/plain
Expires
Mon, Oct 21, 3:52 AM (3 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6718309
Default Alt Text
D19017.id45613.diff (8 KB)

Event Timeline