Agent Wranglers

EML-32Recommended

Stop on permanent failures and retry temporary ones

Read every bounce and SMTP reply. Suppress an address after a permanent failure for a bad mailbox, and retry only temporary failures.

How to do it

SMTP reply codes starting with 5 are permanent, and those starting with 4 are temporary (RFC 5321). Enhanced status codes add detail (RFC 3463). 5.1.x means the address is bad, so suppress it. 5.7.x means the receiver refused you for policy or authentication. Fix your sending instead of dropping the address. Parse delivery status notifications (RFC 3464) and match them to the message, for example with a unique return path per message (VERP).

Examples

Plain text example

550 5.1.1 <nobody@example.com>: Recipient address rejected: User unknown
550 5.7.515 Access denied, sending domain does not meet the required authentication level
451 4.7.1 Try again later

JavaScript example

function bounceAction(enhancedCode) {
  if (enhancedCode.startsWith('4.')) return 'retry';
  if (enhancedCode.startsWith('5.1.')) return 'suppress-address';
  return 'alert-sender-team';
}

Python example

def bounce_action(enhanced_code: str) -> str:
    if enhanced_code.startswith("4."):
        return "retry"
    if enhanced_code.startswith("5.1."):
        return "suppress-address"
    return "alert-sender-team"

How to check

Send to an address that does not exist. The bounce is recorded against the message, and the address is suppressed. A test bounce with 5.7.1 raises an alert and leaves the address active.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/email/bounces-and-complaints/handle-bounces">Agent Wranglers email playbook</a>. In code you write, add a comment next to it with the same link.