Un rejet, c'est un serveur de messagerie qui vous indique pourquoi il n'a pas accepté votre message, sous la forme d'un code à trois chiffres. Classer correctement ces codes, c'est ce qui distingue la suppression d'une adresse réellement morte du rejet d'une adresse qui aurait été délivrée lors d'une nouvelle tentative. Ce guide construit un classificateur de rejets et montre comment appliquer la même classification avant l'envoi plutôt qu'après.
La réponse en bref#
Le premier chiffre du code SMTP décide de l'action : 5xx est un échec
permanent — à supprimer — et 4xx est temporaire — à réessayer. Le
raffinement qui compte est le code de statut étendu : un 5.7.x est un blocage
lié à la politique ou à la réputation (le serveur qui vous refuse, sans juger
la boîte aux lettres), que vous ne devez pas traiter comme une adresse morte. Un
vérificateur applique la même logique à une sonde de boîte aux lettres, ce qui
vous permet de classer une adresse avant qu'un vrai rejet ne survienne.
Les deux dimensions d'un rejet#
Tout rejet possède deux propriétés qu'il vaut la peine de distinguer :
- La permanence — s'agit-il d'un échec définitif (
5xx, un rejet définitif) ou temporaire (4xx, un rejet temporaire) ? C'est ce qui décide entre supprimer et réessayer. - L'objet — le serveur juge-t-il la boîte aux lettres (« utilisateur inconnu ») ou votre expéditeur (« votre IP est sur liste de blocage ») ? Un rejet permanent de votre expéditeur ressemble à un rejet définitif, mais ne doit pas être traité comme tel — supprimer le destinataire ne résout rien, car le problème vient de votre réputation.
Le guide des codes de réponse SMTP couvre toute la grammaire ; la classification consiste à la transformer en action.
Un classificateur de rejets#
Voici un classificateur qui lit le code SMTP et le code étendu optionnel, puis
renvoie une action. Il gère le cas que la plupart des classificateurs naïfs
manquent — le blocage lié à la politique déguisé en 5xx :
/**
* Classify a bounce into an action.
* @param {number} code basic SMTP code, e.g. 550
* @param {string} [enhanced] enhanced status code, e.g. "5.1.1"
*/
export function classifyBounce(code, enhanced) {
const cls = Math.floor(code / 100); // 2, 4, or 5
// Policy / reputation block: the server is refusing YOU, not the mailbox.
// Suppressing the recipient would be treating the wrong problem.
if (enhanced?.startsWith("5.7") || enhanced?.startsWith("4.7")) {
return { type: "policy", action: "review", note: "sender reputation, not the mailbox" };
}
if (cls === 5) {
// Permanent: no such user, disabled, or the domain won't relay.
return { type: "hard", action: "suppress", reason: "rejected_email" };
}
if (cls === 4) {
// Temporary: full mailbox, greylisting, or a rate limit.
const fullMailbox = code === 452 || enhanced === "4.2.2";
return {
type: "soft",
action: "retry",
reason: fullMailbox ? "full_mailbox" : "timeout",
};
}
return { type: "unknown", action: "retry" };
}
classifyBounce(550, "5.1.1"); // { type: "hard", action: "suppress" }
classifyBounce(452); // { type: "soft", action: "retry", reason: "full_mailbox" }
classifyBounce(554, "5.7.1"); // { type: "policy", action: "review" } ← don't suppress
La règle intégrée ici : ne supprimez que les rejets nets de boîte aux
lettres. Un 5.7.x signifie qu'il faut corriger votre réputation
d'expéditeur ; supprimer le destinataire masque le signal sans rien résoudre.
Classer avant le rejet, pas après#
Le problème de la classification des rejets, c'est qu'elle est réactive — vous n'apprenez qu'une adresse est morte qu'en lui envoyant un message et en abîmant votre réputation au passage. La vérification applique la même classification à une sonde SMTP plutôt qu'à un vrai envoi, si bien que vous obtenez le verdict sans le rejet. Les codes de verdict et de raison correspondent directement aux mêmes actions :
const ACTION_BY_REASON = {
accepted_email: "keep", // deliverable
rejected_email: "suppress", // hard bounce confirmed by probe
invalid_email: "suppress", // bad syntax
invalid_domain: "suppress", // no mail route
low_quality: "suppress", // disposable
low_deliverability: "segment", // catch-all or full mailbox — send carefully
timeout: "retry", // greylisted / no answer yet
unavailable_smtp: "retry", // couldn't reach the server
unknown: "retry",
};
// From a verification result row:
const action = ACTION_BY_REASON[row.reason] ?? "retry";
Le même arbre de décision, déplacé plus tôt dans le temps. Les adresses qui
auraient produit un rejet définitif reviennent en undeliverable et sont
supprimées avant l'envoi ; les adresses unknown bénéficient d'une nouvelle
tentative au lieu d'une supposition.
L'intégrer dans la boucle#
Quel que soit le sens dans lequel vous l'exécutez, la sortie alimente un seul endroit — votre liste de suppression :
- En réactif : analysez les webhooks de rejet de votre ESP, exécutez
classifyBounce, puis supprimez les rejets définitifs tout en planifiant de nouvelles tentatives pour les rejets temporaires. - En proactif : lancez un travail de vérification en masse,
récupérez les résultats avec
include=results, associez chaquereasonviaACTION_BY_REASON, puis appliquez les actions — la boucle exporter-vérifier-supprimer que les guides de nettoyage ESP détaillent pour chaque plateforme.
Conserver les deux est idéal : vérifiez de manière proactive pour prévenir la plupart des rejets, et classez de manière réactive les rejets résiduels afin de rattraper les adresses qui se sont dégradées depuis.
Foire aux questions#
Quelle est la différence entre un rejet définitif (hard bounce) et un rejet temporaire (soft bounce), au niveau du code ?#
La classe SMTP : 5xx est un rejet définitif (permanent — à supprimer), 4xx
est un rejet temporaire (à réessayer). Le seul piège est un code étendu 5.7.x,
qui correspond à un blocage permanent lié à la politique visant votre
expéditeur plutôt qu'à une boîte aux lettres morte — classez-le séparément et
corrigez votre réputation au lieu de supprimer le destinataire.
Combien de fois faut-il réessayer un rejet temporaire avant de supprimer l'adresse ?#
Il n'existe pas de chiffre universel, mais un schéma courant consiste à réessayer une adresse en rejet temporaire sur quelques envois consécutifs et à la faire passer en supprimée si elle ne se rétablit jamais — ce qui correspond en gros à ce que font les fournisseurs de messagerie et les ESP en interne. Les boîtes aux lettres pleines se libèrent souvent d'elles-mêmes, si bien que les rejets temporaires méritent une patience qu'un rejet définitif ne mérite pas.
Puis-je classer les adresses avant de leur envoyer un e-mail ?#
Oui — c'est précisément le rôle de la vérification. Une sonde SMTP de boîte aux
lettres produit les mêmes signaux qu'un rejet, associés à un verdict
deliverable | risky | undeliverable | unknown accompagné d'un code de raison,
ce qui vous permet de supprimer les adresses mortes avant même qu'elles ne
rejettent. Le tableau ACTION_BY_REASON ci-dessus transforme ces verdicts en
les mêmes actions supprimer/réessayer/conserver.
Besoin des verdicts à classer ? Le plan gratuit inclut 100 crédits,
et la référence de l'API documente les codes de raison et le
point de terminaison de résultats /jobs que lit la boucle proactive.