@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve error and header behaviors for Mailgun received mail webhook

Summary:
Ref T10709. Two issues:

- If a user sends an invalid `!command`, we can throw, which means we don't return HTTP 200. This makes Mailgun re-send the mail later.
- We don't parse headers of the modern API correctly, so the "Message-ID" failsafe doesn't work. Parse them correctly. I //believe// Mailgun's API changed at some point.

Test Plan:
This is difficult to test exhaustively in isolation. I used Mailgun's web tools to verify the format of the hook request, and faked some requests locally.

I'll keep an eye on this as it goes to production and make sure the fix is correct there.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10709

Differential Revision: https://secure.phabricator.com/D15575

+25 -9
+25 -9
src/applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php
··· 28 28 pht('Mail signature is not valid. Check your Mailgun API key.')); 29 29 } 30 30 31 - $user = $request->getUser(); 32 - 33 - $raw_headers = $request->getStr('headers'); 34 - $raw_headers = explode("\n", rtrim($raw_headers)); 31 + $raw_headers = $request->getStr('message-headers'); 35 32 $raw_dict = array(); 36 - foreach (array_filter($raw_headers) as $header) { 37 - list($name, $value) = explode(':', $header, 2); 38 - $raw_dict[$name] = ltrim($value); 33 + if (strlen($raw_headers)) { 34 + $raw_headers = phutil_json_decode($raw_headers); 35 + foreach ($raw_headers as $raw_header) { 36 + list($name, $value) = $raw_header; 37 + $raw_dict[$name] = $value; 38 + } 39 39 } 40 40 41 41 $headers = array( ··· 65 65 } 66 66 } 67 67 $received->setAttachments($file_phids); 68 - $received->save(); 69 68 70 - $received->processReceivedMail(); 69 + try { 70 + $received->save(); 71 + $received->processReceivedMail(); 72 + } catch (Exception $ex) { 73 + // We can get exceptions here in two cases. 74 + 75 + // First, saving the message may throw if we have already received a 76 + // message with the same Message ID. In this case, we're declining to 77 + // process a duplicate message, so failing silently is correct. 78 + 79 + // Second, processing the message may throw (for example, if it contains 80 + // an invalid !command). This will generate an email as a side effect, 81 + // so we don't need to explicitly handle the exception here. 82 + 83 + // In these cases, we want to return HTTP 200. If we do not, MailGun will 84 + // re-transmit the message later. 85 + phlog($ex); 86 + } 71 87 72 88 $response = new AphrontWebpageResponse(); 73 89 $response->setContent(pht("Got it! Thanks, Mailgun!\n"));