From fa47654fb90ef85cd4469d649a5da1f8da805c8f Mon Sep 17 00:00:00 2001 From: Eileen McNaughton Date: Tue, 12 Sep 2023 10:13:10 +1200 Subject: [PATCH] Add detail about bounce to activity Note adding fetch_activities to the test exposed a mysql error so I had to add handling there --- CRM/Utils/Mail/EmailProcessor.php | 44 ++++++++++++++++--- .../CRM/Utils/Mail/EmailProcessorTest.php | 4 +- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/CRM/Utils/Mail/EmailProcessor.php b/CRM/Utils/Mail/EmailProcessor.php index c1e511df87..0f891fcaf1 100644 --- a/CRM/Utils/Mail/EmailProcessor.php +++ b/CRM/Utils/Mail/EmailProcessor.php @@ -96,6 +96,13 @@ class CRM_Utils_Mail_EmailProcessor { $bounceActivityTypeID = (int) $activityType['id']; } } + $bounceTypes = []; + if ($isBounceProcessing) { + $result = CRM_Core_DAO::executeQuery('SELECT * FROM civicrm_mailing_bounce_type'); + while ($result->fetch()) { + $bounceTypes[$result->id] = ['id' => $result->id, 'name' => $result->name, 'description' => $result->description, 'hold_threshold' => $result->hold_threshold]; + } + } // retrieve the emails try { @@ -128,10 +135,23 @@ class CRM_Utils_Mail_EmailProcessor { continue; } + $bounceString = ''; // if its the activities that needs to be processed .. try { if ($incomingMail->isBounce()) { $activityTypeID = $bounceActivityTypeID; + $bounce = CRM_Mailing_BAO_BouncePattern::match($incomingMail->getBody()); + if (!empty($bounce['bounce_type_id'])) { + $bounceType = $bounceTypes[$bounce['bounce_type_id']]; + $bounceString = ts('Bounce type: %1. %2', [1 => $bounceType['name'], 2 => $bounceType['description']]) + . '
' + . ts('Email will be put on hold after %1 of this type of bounce', [1 => $bounceType['hold_threshold']]) + . "\n"; + } + else { + $bounceString = ts('Bounce type not identified, email will not be put on hold') + . "\n"; + } } $mailParams = CRM_Utils_Mail_Incoming::parseMailingObject($mail, $incomingMail->getAttachments(), $createContact, $emailFields, [$incomingMail->getFrom()]); $activityParams = [ @@ -177,18 +197,28 @@ class CRM_Utils_Mail_EmailProcessor { } $result = civicrm_api3('Activity', 'create', $activityParams); + $matches = TRUE; + CRM_Utils_Hook::emailProcessor('activity', $activityParams, $mail, $result); + echo "Processed as Activity: {$mail->subject}\n"; } catch (Exception $e) { - echo "Failed Processing: {$mail->subject}. Reason: " . $e->getMessage() . "\n"; - $store->markIgnored($key); - continue; + // Try again with just the bounceString as the details. + // This allows us to still process even if we hit https://lab.civicrm.org/dev/mail/issues/36 + // as tested in testBounceProcessingInvalidCharacter. + $activityParams['details'] = trim($bounceString); + try { + civicrm_api3('Activity', 'create', $activityParams); + $matches = TRUE; + } + catch (CRM_Core_Exception $e) { + echo "Failed Processing: {$mail->subject}. Reason: " . $e->getMessage() . "\n"; + $store->markIgnored($key); + continue; + } } - $matches = TRUE; - CRM_Utils_Hook::emailProcessor('activity', $activityParams, $mail, $result); - echo "Processed as Activity: {$mail->subject}\n"; } - // if $matches is empty, this email is not CiviMail-bound + // This is an awkward exit when processing is done. It probably needs revisiting if (!$incomingMail->isVerp() && empty($matches)) { $store->markIgnored($key); continue; diff --git a/tests/phpunit/CRM/Utils/Mail/EmailProcessorTest.php b/tests/phpunit/CRM/Utils/Mail/EmailProcessorTest.php index 1d1d0e5b60..a8826dba42 100644 --- a/tests/phpunit/CRM/Utils/Mail/EmailProcessorTest.php +++ b/tests/phpunit/CRM/Utils/Mail/EmailProcessorTest.php @@ -89,9 +89,11 @@ class CRM_Utils_Mail_EmailProcessorTest extends CiviUnitTestCase { $mail = 'test_invalid_character.eml'; copy(__DIR__ . '/data/bounces/' . $mail, __DIR__ . '/data/mail/' . $mail); - $this->callAPISuccess('job', 'fetch_bounces', []); + $this->callAPISuccess('job', 'fetch_bounces', ['is_create_activities' => TRUE]); $this->assertFileDoesNotExist(__DIR__ . '/data/mail/' . $mail); $this->checkMailingBounces(1); + $activity = $this->callAPISuccessGetSingle('Activity', ['activity_type_id' => 'Bounce']); + $this->assertEquals('Bounce type not identified, email will not be put on hold', $activity['details']); } /** -- 2.25.1