SuiteCRM Bounce handling after campaign sent

After a campaign was sent there are two locations for bounce reports below “View Status” for a campaign:

  1. Bounced Messages, Invalid Email
  2. Bounced Messages, Other

While the email addresses are marked INVALID for ALL email addresses found for the first case “Invalid Email” this cannot be said for second case “Other”.

My mail server reports correctly for all of the many cases - I checked the first 20 and my mail server has reported correctly that the recipient mail server reported “user unknown” as in:

Feb 5 12:57:08 korolev sendmail[402961]: 6151v5DH402945: to=RECIPIENT_EMAIL_ADDRESS, ctladdr=BOUNCE_EMAIL_ADDRESS (2291/2291), delay=00:00:02, xdelay=00:00:02, mailer=esmtp, pri=12017, relay=RECIPIENT_EMAIL_ADDRESS_DOMAIN.mail…ction.outlook.com. [52.101.40.0], dsn=5.4.1, stat=User unknown

Yet the email address is NOT marked invalid - this is a little frustrating, I have quite a lot of them.
This is the actual return reciept:

Reporting-MTA: dns; barrett.com.au
Received-From-MTA: DNS; localhost
Arrival-Date: Thu, 5 Feb 2026 12:57:06 +1100
Final-Recipient: RFC822; EMAIL_ADDRESS_RECIPIENT
Action: failed
Status: 5.4.1
Remote-MTA: DNS; DOMAIN_RECIPIENT.mail.protection.outlook.com
Diagnostic-Code: SMTP; 550 5.4.1 Recipient address rejected: Access denied. For more information see  [CY4PEPF0000FCC0.namprd03.prod.outlook.com 2026-02-05T01:57:08.183Z 08DE63A2ECABE068]
Last-Attempt-Date: Thu, 5 Feb 2026 12:57:08 +1100

Why does SuiteCRM not mark these emails as invalid?

I just checked a document from MICROSOFT.

In that document it states that in fact a 5.4.1 is a “USER UNKNOWN” error.

But the code in SuiteCRM is rather simple - to put it bluntly - to check bounced emails:

function checkBouncedEmailInvalid($email_description)
{
  /* Consider as invalid if we get a permanent error status
    (5.X.X)* and in   addition we get an smtp error 550. 
    https://tools.ietf.org/html/rfc3464#section-2.3.4
    https://tools.ietf.org/html/rfc3464#section-2.3.6
    https://www.usps.org/info/smtp_codes.html
    Example:
     Status: 5.0.0 Diagnostic-Code: smtp; 550 #5.1.0 Address rejected.
    Example:
     Status: 5.5.0 Diagnostic-Code: smtp; 550 5.5.0 
     Requested action not taken: mailbox unavailable* 
    Example:
     Status: 5.1.1 Diagnostic-Code: smtp; 554 5.1.1/

   if (preg_match('/^Status:\s([0-9]+).([0-9]+).([0-9]+)/m’,
       $email_description, $match)) 
   {
     // 5.1.1 (permanent) Bad destination mailbox address
     if ($match[1] == ‘5’ && $match[2] == ‘1’ && $match[3] == ‘1’) 
     {
       return true;
     }
     // Permanent error with smtp error code for non-existent email address
     if ($match[1] == '5' && 
         preg_match('/^Diagnostic-Code:\s*smtp\s*;.*550/m',
         $email_description)) 
     {
       return true;
     }
   }

   return false;
}

This is my understanding of the critera:

The regular expression checks for lines in the email description that start with “Status:,” followed by a sequence of three numbers separated by periods. If it finds a line with a permanent error status (5.X.X) and a line that contains “Diagnostic-Code: smtp; 550,” it returns true to indicate that the email is invalid due to a “550” SMTP error.

You’re email looks like it should return true based on that.

Was the campaign id returned in the header? That’s the only way it would know which email bounced. That’s the only thing I see is missing.

The campaign ID is in there, it actually is the “target_tracker_key” referencing the actual person.

It indeed is a bug I just found, this is the return:

Diagnostic-Code: SMTP; 550 5.4.1 Recipient address rejected: Access denied. For more information see [``CY4PEPF0000FCC0.namprd03.prod.outlook.com`` 2026-02-05T01:57:08.183Z 08DE63A2ECABE068]

This does NOT match the regular expression:

if ($match[1] == ‘5’ && preg_match(‘/^Diagnostic-Code:\ssmtp\s;.*550/m’, $email_description)) {
return true;
}

as the return from MICROSOFT is ALL UPPERCASE “SMTP” and the regular expression checks for LOWER CASE only, it SHOULD BE:

if ($match[1] == ‘5’ && preg_match(‘/^Diagnostic-Code:\ssmtp\s;.*550/im’, $email_description)) {
return true;
}

Note the “i”, the “m” is for MULTIPLE lines.

The bounce handling does NOT work for ALL “*.prod.outlook.com” based mail servers.

1 Like