Menu
Accedi Crea account
Deliverability

Bounce code SMTP: come leggerli davvero (e perché il 90% li interpreta male)

I bounce code SMTP non sono tutti uguali: un 421 non è un 550, e un 451 non è un 550. Guida pratica per leggerli, parsarli e impostare retry intelligenti.

12 Nov 2024 · 10 min di lettura · Target SMTP

Ogni giorno milioni di email rimbalzano contro server di posta restituendo codici di stato a tre cifre. Il problema è che la maggior parte degli sviluppatori legge solo la prima cifra (4 o 5) e archivia il messaggio come "soft bounce" o "hard bounce", perdendo informazione cruciale. In realtà RFC 5321 e RFC 3463 definiscono una semantica precisa che, se ignorata, porta a strategie di retry sbagliate, reputation IP rovinata e cancellazioni di contatti validi. In questo articolo analizziamo i bounce code più comuni nel 2026, come parsarli con regex robuste, quando ritentare davvero e quando arrenderti subito.

La differenza tra status code e enhanced status code

Un bounce SMTP completo contiene tre informazioni distinte: il codice di risposta a tre cifre (es. 550), il codice esteso secondo RFC 3463 (es. 5.1.1) e un testo libero in inglese spesso scritto dal sysadmin del destinatario. Esempio reale di una risposta Google Workspace:

550-5.1.1 The email account that you tried to reach does not exist. Please try
550-5.1.1 double-checking the recipient's email address for typos or
550-5.1.1 unnecessary spaces. Learn more at
550 5.1.1  https://support.google.com/mail/?p=NoSuchUser z6si12345678wmf.42 - gsmtp

Qui abbiamo: 550 (basic code, RFC 5321), 5.1.1 (enhanced code, RFC 3463), e il testo. Il basic dice "permanent failure", l'enhanced dice esattamente "bad destination mailbox address". Sono due livelli diversi di informazione: il primo cifra (5) coincide tra i due, ma il livello di dettaglio è radicalmente differente.

Tabella dei codici più comuni

CodiceEnhancedSignificato realeRetry?
4214.7.0Servizio temporaneamente non disponibile, connessione chiusaSì, 15-30 min
4214.7.28IP temporaneamente bloccato per rate limit (Gmail tipico)Sì, backoff esponenziale
4504.2.1Mailbox non disponibile (out of office, manutenzione)Sì, 1 ora
4514.3.0Errore locale del receiver, riprovaSì, 30 min
4524.2.2Mailbox piena, quota superataSì, 6-24 ore
5505.1.1Utente inesistente (hard bounce definitivo)NO, suppress
5505.1.2Dominio inesistente o MX non risolvibileNO, suppress
5505.2.1Mailbox disabilitataNO, suppress
5505.7.1Rifiutato per policy (spam, SPF/DKIM fail)Dipende
5505.7.26Multiple authentication failure (Gmail)NO, fix DKIM/SPF
5525.2.3Messaggio troppo grandeNO, riduci payload
5535.1.8Sender address rifiutato (envelope MAIL FROM)NO, fix sender
5545.7.1Transazione fallita, spesso reputationNO, investiga
⚠️ Attenzione: il codice 5.7.1 è il più ambiguo dell'ecosistema SMTP. Può significare "questo singolo messaggio è considerato spam" oppure "il tuo IP è in blacklist". Senza leggere il testo libero non puoi distinguere i due casi, e la strategia di rimedio è opposta.

Parsare bounce code con regex

La maggior parte dei provider SMTP italiani consegna i bounce in due forme: inline (durante la sessione SMTP, restituiti come eccezione dal client) oppure asincroni (DSN - Delivery Status Notification, una mail di ritorno con MIME type multipart/report). Per gli inline ecco una regex Python robusta:

import re

BOUNCE_RE = re.compile(
    r"^(?P<basic>[45]d{2})[s-]"
    r"(?:(?P<enhanced>[245].d{1,3}.d{1,3})s+)?"
    r"(?P<message>.+)$",
    re.MULTILINE
)

def parse_bounce(raw: str) -> dict:
    last_line = raw.strip().split("
")[-1]
    m = BOUNCE_RE.match(last_line)
    if not m:
        return {"basic": None, "enhanced": None, "message": raw}
    return {
        "basic": int(m.group("basic")),
        "enhanced": m.group("enhanced"),
        "message": m.group("message").strip(),
        "permanent": m.group("basic").startswith("5"),
    }

Per i DSN asincroni, la library standard email.parser di Python espone direttamente il blocco message/delivery-status; non serve regex se non per pulizia finale.

Strategia di retry corretta

Una retry policy sbagliata è la causa numero uno di reputation IP devastata. Tre regole non negoziabili:

  1. 4xx = retry, 5xx = stop. Sembra ovvio, ma metà dei sistemi custom sbaglia almeno questo.
  2. Backoff esponenziale con jitter. Niente retry ogni 60 secondi a oltranza: delay = min(2^attempt + random(0, 30), 14400) in secondi, max 4 ore.
  3. Hard cap a 72 ore. RFC 5321 raccomanda di smettere dopo 4-5 giorni; in pratica 72 ore è il cap industriale corretto.
def next_retry_delay(attempt: int, basic: int, enhanced: str) -> int | None:
    if basic >= 500:
        return None
    if enhanced == "4.2.2":  # mailbox piena
        return min(3600 * (attempt + 1), 21600)
    if enhanced == "4.7.28":  # rate limit Gmail
        return min(900 * (2 ** attempt), 7200)
    if attempt >= 12:
        return None
    return min(60 * (2 ** attempt) + random.randint(0, 30), 14400)

I codici "trappola" da conoscere

421 4.7.0 vs 550 5.7.1: errore o blacklist?

Quando un Gmail risponde 421 4.7.0 IP not in whitelist non è un errore: è una richiesta di rallentare. Aspetta 30 minuti, non ritentare prima. Se invece risponde 550 5.7.1 Our system has detected unusual traffic, il messaggio è già rifiutato definitivamente e il tuo IP è sotto osservazione.

451 4.3.0: il "boh" di Postfix

Postfix usa 451 4.3.0 come catch-all per errori locali (database non raggiungibile, content filter offline). Significa quasi sempre "ritenta tra 15 minuti, sarà tornato".

550 5.4.1: rete o policy?

Outlook/Office 365 usa 550 5.4.1 Recipient address rejected: Access denied sia per indirizzi inesistenti sia per regole policy interne. In assenza di altre informazioni considera l'indirizzo invalido e suppressalo.

💡 Suggerimento: tieni una suppression list separata per tipologia: hard bounce permanenti, complaint (FBL), unsubscribe, manuali. Non mescolarle. Quando reinvii dopo 6 mesi, vorrai sapere se l'indirizzo era invalido o se aveva cliccato "spam".

Cosa NON fare con i bounce

  • Mai cancellare contatti al primo soft bounce. Tre soft bounce consecutivi su tre invii separati sono il minimo per declassificare un indirizzo.
  • Mai trattare il 552 come problema dell'utente. È un problema tuo: il messaggio è troppo grande. Comprimi allegati o usa link a CDN.
  • Mai ignorare i 5.7.x. Sono i bounce di reputation: nascondono problemi sistemici che peggiorano nel tempo.
  • Mai accettare il bounce code dal subject del DSN. Il testo umano (Returned mail: see transcript for details) è inaffidabile, parsare sempre il blocco message/delivery-status.

Riferimenti normativi

La gestione bounce è la differenza tra un sender che sopravvive un anno e uno che brucia il primo IP in tre mesi. Se gestisci email transactional di volume medio-alto, Target SMTP applica automaticamente le retry policy descritte e mantiene suppression list separate per tipologia; il Send-Time Firewall intercetta inoltre invii verso indirizzi storicamente in hard bounce prima ancora che lascino il server, evitando il danno reputazionale al colpo successivo.

Tag #smtp #deliverability #bounce #rfc
Condividi: X LinkedIn Email

Articoli correlati