ListUnsubscribe - Fix VERP parsing (alternate separators; optional localpart-prefix)
authorTim Otten <totten@civicrm.org>
Wed, 17 Jan 2024 22:36:55 +0000 (14:36 -0800)
committerTim Otten <totten@civicrm.org>
Wed, 24 Jan 2024 08:47:36 +0000 (00:47 -0800)
CRM/Mailing/Service/ListUnsubscribe.php
tests/phpunit/CRM/Mailing/BaseMailingSystemTest.php

index 5439047895472b2eb23c01077c9bb9ac272d9ad9..32d9c5764302b6d4071537310bf152a30c269b75 100644 (file)
@@ -41,7 +41,9 @@ class CRM_Mailing_Service_ListUnsubscribe extends \Civi\Core\Service\AutoService
       return;
     }
 
-    if (!preg_match(';^<mailto:u\.(\d+)\.(\d+)\.(\w*)@(.*)>$;', $params['List-Unsubscribe'], $m)) {
+    $sep = preg_quote(Civi::settings()->get('verpSeparator'), ';');
+    $regex = ";^<mailto:[^>]*u{$sep}(\d+){$sep}(\d+){$sep}(\w*)@(.+)>$;";
+    if (!preg_match($regex, $params['List-Unsubscribe'], $m)) {
       \Civi::log()->warning('Failed to set final value of List-Unsubscribe');
       return;
     }
index b401711d6971f085c6030d28da4613ee65dbe48e..9f958015c9fd5cde79dc9ab8fb6818c1447348ec 100644 (file)
@@ -41,6 +41,7 @@ abstract class CRM_Mailing_BaseMailingSystemTest extends CiviUnitTestCase {
     parent::setUp();
     $this->useTransaction();
     CRM_Mailing_BAO_MailingJob::$mailsProcessed = 0;
+    CRM_Core_BAO_MailSettings::defaultDAO(TRUE);
 
     $this->_groupID = $this->groupCreate();
     $this->createContactsInGroup(2, $this->_groupID);
@@ -141,6 +142,19 @@ abstract class CRM_Mailing_BaseMailingSystemTest extends CiviUnitTestCase {
     $this->assertEquals(2, $getMembers('Removed')->count());
   }
 
+  public function testHttpUnsubscribe_altVerp(): void {
+    CRM_Core_DAO::executeQuery('UPDATE civicrm_mail_settings SET localpart = "aeiou.aeiou-"');
+    CRM_Core_BAO_MailSettings::defaultDAO(TRUE);
+
+    try {
+      Civi::settings()->set('verpSeparator', '-');
+      $this->testHttpUnsubscribe();
+    }
+    finally {
+      $this->revertSetting('verpSeparator');
+    }
+  }
+
   /**
    * Generate a fully-formatted mailing (with body_text content).
    */