From 5d971ce8e8d4093c9d6fd853f4a65a5babadd833 Mon Sep 17 00:00:00 2001 From: Samuele Masetto Date: Tue, 17 Dec 2024 08:37:55 +0100 Subject: [PATCH 1/3] "Domain not found" error (error code 450 - class 4.1.2) is not a temporary error --- ext/flexmailer/src/Listener/DefaultSender.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ext/flexmailer/src/Listener/DefaultSender.php b/ext/flexmailer/src/Listener/DefaultSender.php index c29050cdf8ce..6814dd2453fd 100644 --- a/ext/flexmailer/src/Listener/DefaultSender.php +++ b/ext/flexmailer/src/Listener/DefaultSender.php @@ -163,7 +163,9 @@ public function onSend(SendBatchEvent $e) { */ protected function isTemporaryError($message) { // SMTP response code is buried in the message. - $code = preg_match('/ \(code: (.+), response: /', $message, $matches) ? $matches[1] : ''; + preg_match('/ \(code: (.+), response: ([0-9\.]+) /', $message, $matches); + $code = $matches ? $matches[1] : ''; + $class = $matches ? $matches[2] : ''; if (strpos($message, 'Failed to write to socket') !== FALSE) { return TRUE; @@ -174,6 +176,11 @@ protected function isTemporaryError($message) { return FALSE; } + // code: 450, response: 4.1.2: "Recipient address rejected: Domain not found" (consider as permanent failure) + if ($code === '450' && $class === '4.1.2') { + return FALSE; + } + if (str_contains($message, 'Failed to set sender')) { return TRUE; } From 57ba842976c8e4a6f17781b521241089d4374cc8 Mon Sep 17 00:00:00 2001 From: Samuele Masetto Date: Sat, 21 Dec 2024 10:07:32 +0100 Subject: [PATCH 2/3] add an option in CiviMail settings to treat 450 4.1.2 as permanent --- CRM/Admin/Form/Preferences/Mailing.php | 1 + ext/flexmailer/src/Listener/DefaultSender.php | 13 +++++++------ settings/Mailing.setting.php | 16 ++++++++++++++++ templates/CRM/Admin/Form/Preferences/Mailing.hlp | 8 ++++++++ 4 files changed, 32 insertions(+), 6 deletions(-) diff --git a/CRM/Admin/Form/Preferences/Mailing.php b/CRM/Admin/Form/Preferences/Mailing.php index 83d0c0e3970f..7ddbaaca0151 100644 --- a/CRM/Admin/Form/Preferences/Mailing.php +++ b/CRM/Admin/Form/Preferences/Mailing.php @@ -37,6 +37,7 @@ class CRM_Admin_Form_Preferences_Mailing extends CRM_Admin_Form_Preferences { 'url_tracking_default' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'open_tracking_default' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, 'scheduled_reminder_smarty' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, + 'smtp_450_is_permanent' => CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME, ]; public function postProcess() { diff --git a/ext/flexmailer/src/Listener/DefaultSender.php b/ext/flexmailer/src/Listener/DefaultSender.php index 6814dd2453fd..bfc6756af6ef 100644 --- a/ext/flexmailer/src/Listener/DefaultSender.php +++ b/ext/flexmailer/src/Listener/DefaultSender.php @@ -163,9 +163,7 @@ public function onSend(SendBatchEvent $e) { */ protected function isTemporaryError($message) { // SMTP response code is buried in the message. - preg_match('/ \(code: (.+), response: ([0-9\.]+) /', $message, $matches); - $code = $matches ? $matches[1] : ''; - $class = $matches ? $matches[2] : ''; + $code = preg_match('/ \(code: (.+), response: /', $message, $matches) ? $matches[1] : ''; if (strpos($message, 'Failed to write to socket') !== FALSE) { return TRUE; @@ -176,9 +174,12 @@ protected function isTemporaryError($message) { return FALSE; } - // code: 450, response: 4.1.2: "Recipient address rejected: Domain not found" (consider as permanent failure) - if ($code === '450' && $class === '4.1.2') { - return FALSE; + // Consider SMTP Erorr 450, class 4.1.2 "Domain not found", as permanent failures if the corresponding setting is enabled + if ($code === '450' && \Civi::settings()->get('smtp_450_is_permanent')) { + $class = preg_match('/ \(code: (.+), response: ([0-9\.]+) /', $message, $matches) ? $matches[2] : ''; + if ($class === '4.1.2') { + return FALSE; + } } if (str_contains($message, 'Failed to set sender')) { diff --git a/settings/Mailing.setting.php b/settings/Mailing.setting.php index 1cf19112b5f2..55593ecfcade 100644 --- a/settings/Mailing.setting.php +++ b/settings/Mailing.setting.php @@ -455,4 +455,20 @@ 'description' => ts('Controls whether scheduled reminders will attempt to process smarty tokens.'), 'help_text' => NULL, ], + 'smtp_450_is_permanent' => [ + 'group_name' => 'Mailing Preferences', + 'group' => 'mailing', + 'name' => 'smtp_450_is_permanent', + 'type' => 'Boolean', + 'html_type' => 'checkbox', + 'quick_form_type' => 'CheckBox', + 'default' => 0, + 'title' => ts('Treat SMTP Error 450 4.1.2 as permanent'), + 'add' => '5.80', + 'is_domain' => 1, + 'is_contact' => 0, + 'description' => ts('Consider domains that will not resolve (SMTP Erorr 450 - class 4.1.2 "Domain not found") as permanent failures. '), + 'help_text' => NULL, + 'help' => ['id' => 'smtp_450_is_permanent'], + ], ]; diff --git a/templates/CRM/Admin/Form/Preferences/Mailing.hlp b/templates/CRM/Admin/Form/Preferences/Mailing.hlp index 8cfe3b810a34..90521910e16d 100644 --- a/templates/CRM/Admin/Form/Preferences/Mailing.hlp +++ b/templates/CRM/Admin/Form/Preferences/Mailing.hlp @@ -14,3 +14,11 @@

{ts}Specify an Email From Address to use when the system sends an email but a reply is not expected, for example when a user is sent an email for a double opt-in.{/ts}

{ts}Leaving this blank will use the default which will be do-not-reply@default_domain where the default_domain will be the email domain address of your default mailing account also used for bounce handling.{/ts}

{/htxt} +{htxt id="smtp_450_is_permanent-title"} + {ts}Treat SMTP Error 450 4.1.2 as permanent.{/ts} +{/htxt} +{htxt id="smtp_450_is_permanent"} +

{ts}Some SMTP servers are configured to not accept an email if the recipient cannot be reached. Most of the time it means that the domain doesn't exist at all and the SMTP server returns a 5xx permanent error.{/ts}

+

{ts}There're other cases when the domain name is actually registered but its name servers are not reachable, or they don't give a meaningful answer. In these cases the SMTP server returns a 450 temporary delivery error and this is when CiviCRM gets stuck trying a trying to deliver those messages.{/ts}

+

{ts}This option it is useful to decide how to handle these cases, whether to follow the "standard" or consider them as permanent failures.{/ts}

+{/htxt} From ed388eb89b0644c27ada0ae84cfd817902d92d7e Mon Sep 17 00:00:00 2001 From: Samuele Masetto Date: Mon, 23 Dec 2024 11:04:59 +0100 Subject: [PATCH 3/3] fix typos --- settings/Mailing.setting.php | 2 +- templates/CRM/Admin/Form/Preferences/Mailing.hlp | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/settings/Mailing.setting.php b/settings/Mailing.setting.php index 55593ecfcade..678ba7c9ce23 100644 --- a/settings/Mailing.setting.php +++ b/settings/Mailing.setting.php @@ -467,7 +467,7 @@ 'add' => '5.80', 'is_domain' => 1, 'is_contact' => 0, - 'description' => ts('Consider domains that will not resolve (SMTP Erorr 450 - class 4.1.2 "Domain not found") as permanent failures. '), + 'description' => ts('Consider domains that will not resolve (SMTP Error 450 - class 4.1.2 "Domain not found") as permanent failures.'), 'help_text' => NULL, 'help' => ['id' => 'smtp_450_is_permanent'], ], diff --git a/templates/CRM/Admin/Form/Preferences/Mailing.hlp b/templates/CRM/Admin/Form/Preferences/Mailing.hlp index 90521910e16d..758bde5d053e 100644 --- a/templates/CRM/Admin/Form/Preferences/Mailing.hlp +++ b/templates/CRM/Admin/Form/Preferences/Mailing.hlp @@ -18,7 +18,5 @@ {ts}Treat SMTP Error 450 4.1.2 as permanent.{/ts} {/htxt} {htxt id="smtp_450_is_permanent"} -

{ts}Some SMTP servers are configured to not accept an email if the recipient cannot be reached. Most of the time it means that the domain doesn't exist at all and the SMTP server returns a 5xx permanent error.{/ts}

-

{ts}There're other cases when the domain name is actually registered but its name servers are not reachable, or they don't give a meaningful answer. In these cases the SMTP server returns a 450 temporary delivery error and this is when CiviCRM gets stuck trying a trying to deliver those messages.{/ts}

-

{ts}This option it is useful to decide how to handle these cases, whether to follow the "standard" or consider them as permanent failures.{/ts}

+

{ts}Some SMTP servers are configured to not accept an email if the recipient cannot be reached. Most of the time it means that the domain doesn't exist at all and the SMTP server returns a 5xx permanent error. But sometimes the domain name is actually registered but its name servers are not reachable, or they don't give a meaningful answer. In these cases the SMTP server returns a 450 temporary delivery error and the mailing job gets stuck in status Running. Enabling this option will consider them as permanent failures.{/ts}

{/htxt}