Add detail about bounce to activity
authorEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 11 Sep 2023 22:13:10 +0000 (10:13 +1200)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 11 Sep 2023 22:13:10 +0000 (10:13 +1200)
Note adding fetch_activities to the test exposed a mysql error so I had
to add handling there

CRM/Utils/Mail/EmailProcessor.php
tests/phpunit/CRM/Utils/Mail/EmailProcessorTest.php

index c1e511df8740bdb8952fa1a547d81c241383a2c8..0f891fcaf1f2c23d130153393cc0907b7cee3cb2 100644 (file)
@@ -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']])
+                  . '<br>'
+                  . 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;
index 1d1d0e5b607681745bcfc08b56d452a3efd25591..a8826dba42e5034b0fd4d4e7fd2bfc664976dd3a 100644 (file)
@@ -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']);
   }
 
   /**