From 740624b8580afe2bad97d7a2d88d371c9180ba25 Mon Sep 17 00:00:00 2001 From: Rich Lott Date: Thu, 13 Dec 2018 17:04:38 +0000 Subject: [PATCH] workaround Mailgun not returning all headers in webhook --- CRM/Mailgunny/Page/Webhook.php | 36 ++++++++++++++++-------- mailgunny.php | 51 +++++++++++++++++----------------- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/CRM/Mailgunny/Page/Webhook.php b/CRM/Mailgunny/Page/Webhook.php index 195144e..73277d2 100644 --- a/CRM/Mailgunny/Page/Webhook.php +++ b/CRM/Mailgunny/Page/Webhook.php @@ -58,8 +58,7 @@ class CRM_Mailgunny_Page_Webhook extends CRM_Core_Page { * @return string */ public function getApiKey() { - // @todo fetch from somewhere. - $v = Civi::settings()->get('mailgun_api_key'); + return Civi::settings()->get('mailgun_api_key'); } /** @@ -74,6 +73,7 @@ class CRM_Mailgunny_Page_Webhook extends CRM_Core_Page { elseif ($event->severity === 'temporary') { $this->processTemporaryBounce($event); } + echo '{"success": 1}'; break; case 'accepted': @@ -90,8 +90,6 @@ class CRM_Mailgunny_Page_Webhook extends CRM_Core_Page { default: throw new CRM_Mailgunny_WebhookRejectedException("Unrecognised webhook event type is not handled by this webhook."); } - - } public function processPermanentBounce($event) { @@ -103,7 +101,10 @@ class CRM_Mailgunny_Page_Webhook extends CRM_Core_Page { public function processCommonBounce($event, $type) { Civi::log()->info("Mailgun Webhook processing bounce: $type"); // Ideally we would have access to 'X-CiviMail-Bounce' but I don't think we do. - $bounce_params = $this->extractVerpData($event->envelope->sender ?? ''); + $bounce_params = $this->extractVerpData($event); + if (!$bounce_params) { + throw new CRM_Mailgunny_WebhookRejectedException("Cannot find VERP data necessary to process bounce."); + } $bounce_params['bounce_type_id'] = $this->getCiviBounceTypeId($type); $bounce_params['bounce_reason'] = ($event->{'delivery-status'}->description ?? '') . " " @@ -112,18 +113,31 @@ class CRM_Mailgunny_Page_Webhook extends CRM_Core_Page { $bounced = CRM_Mailing_Event_BAO_Bounce::create($bounce_params); } /** - * Extract data from verp email address string. - * - * Credit goes to https://github.com/mecachisenros + * Extract data from verp data if we can. * * @param string $data e.g. 'b.22.23.1bc42342342@example.com' * @return array with keys: job_id, event_queue_id, hash */ - public function extractVerpData($data) { + public function extractVerpData($event) { + + if (!empty($event->{'user-variables'}->{'civimail-bounce'})) { + // Great, we found the header we added in our hook_civicrm_alterMailParams. + $data = $event->{'user-variables'}->{'civimail-bounce'}; + } + elseif (!empty($event->envelope->sender)) { + // Hmmm. See if the envelope sender has anything useful in it. + $data = $event->envelope->sender; + } + + // Credit goes to https://github.com/mecachisenros for the verp parsing: $verp_separator = Civi::settings()->get('verpSeparator'); $localpart = CRM_Core_BAO_MailSettings::defaultLocalpart(); - $verp_items = array_combine(['job_id', 'event_queue_id', 'hash'], - explode($verp_separator, substr(substr($data, 0, strpos($data, '@')), strlen($localpart) + 2))); + $parts = explode($verp_separator, substr(substr($data, 0, strpos($data, '@')), strlen($localpart) + 2)); + + $verp_items = (count($parts) === 3) + ? array_combine(['job_id', 'event_queue_id', 'hash'], $parts) + : []; + return $verp_items; } diff --git a/mailgunny.php b/mailgunny.php index fcd3abe..af586fd 100644 --- a/mailgunny.php +++ b/mailgunny.php @@ -134,30 +134,31 @@ function mailgunny_civicrm_entityTypes(&$entityTypes) { _mailgunny_civix_civicrm_entityTypes($entityTypes); } -// --- Functions below this ship commented out. Uncomment as required. --- - /** - * Implements hook_civicrm_preProcess(). + * Try to embed VERP data in a way that Mailgun will provide to webhooks. * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_preProcess - * -function mailgunny_civicrm_preProcess($formName, &$form) { - -} // */ - -/** - * Implements hook_civicrm_navigationMenu(). - * - * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_navigationMenu - * -function mailgunny_civicrm_navigationMenu(&$menu) { - _mailgunny_civix_insert_navigation_menu($menu, 'Mailings', array( - 'label' => E::ts('New subliminal message'), - 'name' => 'mailing_subliminal_message', - 'url' => 'civicrm/mailing/subliminal', - 'permission' => 'access CiviMail', - 'operator' => 'OR', - 'separator' => 0, - )); - _mailgunny_civix_navigationMenu($menu); -} // */ + * Implements hook_civicrm_alterMailParams(&$params, $context) + */ +function mailgunny_civicrm_alterMailParams(&$params, $context) { + if (isset($params['X-CiviMail-Bounce'])) { + // Copy this header to one that will be returned by Mailgun's webhook. + $params['X-Mailgun-Variables'] = json_encode(['civimail-bounce' => $params['X-CiviMail-Bounce']]); + } + elseif (isset($params['Return-Path'])) { + // Copy this header to one that will be returned by Mailgun's webhook. + $params['X-Mailgun-Variables'] = json_encode(['civimail-bounce' => $params['Return-Path']]); + } + /* + ⬦ $context = (string [10]) `flexmailer` + ⬦ $params['X-CiviMail-Mosaico'] = (string [3]) `Yes` + ⬦ $params['List-Unsubscribe'] = (string [52]) `` + ⬦ $params['Precedence'] = (string [4]) `bulk` + ⬦ $params['job_id'] = (string [2]) `72` + ⬦ $params['From'] = (string [37]) `"Artful Robot" ` + ⬦ $params['toEmail'] = (string [20]) `hello@artfulrobot.uk` + ⬦ $params['toName'] = (string [12]) `Artful Robot` + ⬦ $params['Return-Path'] = (string [43]) `b.72.32.fa5f74c72c53c77f@crm.artfulrobot.uk` + ⬦ $params['X-CiviMail-Bounce'] = (string [43]) `b.72.32.fa5f74c72c53c77f@crm.artfulrobot.uk` + ⬦ $params['attachments'] = (array) + */ +}