Une liste pleine d’adresses mortes coûte plus cher que les envois qu’elle gaspille. Chaque hard bounce indique à Gmail, Outlook et Yahoo que vous ne savez pas à qui vous écrivez, et ils le retiennent contre votre domaine et votre IP d’envoi. Au-delà d’un certain point, la campagne suivante atterrit dans les spams, y compris pour les bonnes adresses.
La vérification d’email sert à trouver ces adresses avant qu’un fournisseur de messagerie ne le fasse. Ce guide suit une adresse à travers les quatre étapes qu’exécute un vérificateur, dans l’ordre, et montre quelle partie d’une réponse de l’API BounceIntel chaque étape remplit. À la fin, vous devriez pouvoir lire un résultat vous-même plutôt que de vous fier à une étiquette d’un seul mot.
Ce qu’est la vérification (et ce qu’elle n’est pas)
La vérification d’email est un test automatisé qui détermine si une adresse peut recevoir du courrier maintenant. Elle s’appuie sur deux sources : les enregistrements DNS publics et une courte conversation avec le serveur de messagerie qui recevrait le message. Aucun email n’est envoyé. La conversation s’arrête avant que le moindre contenu ne soit transmis, et la personne derrière l’adresse ne voit rien.
Il faut être tout aussi clair sur ce que la vérification ne peut pas vous dire :
- Si un humain lit la boîte. Une boîte peut exister et être abandonnée. Les données d’engagement répondent à cette question, pas la vérification.
- Si l’adresse fonctionnera encore le mois prochain. Les gens changent d’emploi et les boîtes sont supprimées. Un résultat décrit le moment du test, c’est pourquoi chaque résultat BounceIntel contient
score.freshness, defreshàexpired. - Si une adresse est un piège à spam. Les domaines connus pour exploiter des pièges sont signalés, mais un piège bien conçu ressemble exactement à une adresse réelle et fonctionnelle.
- Si vous avez le droit d’écrire à quelqu’un. C’est une question de consentement, et aucun test technique n’y répond.
Étape 1 : syntaxe et normalisation
La première étape ne quitte jamais le vérificateur. Elle coupe l’adresse au niveau du @ en une partie locale et un domaine, puis vérifie que les deux sont bien formés. Une adresse qui échoue ici s’arrête ici : aucune requête DNS, aucune connexion au serveur de qui que ce soit, et un résultat is_reachable: "invalid" avec le code de raison invalid_syntax et un score de 0.
Deux détails décident si une adresse inhabituelle passe :
- Les domaines internationalisés comme
münchen.desont convertis dans leur forme ASCII (xn--mnchen-3ya.de), et toutes les étapes suivantes utilisent cette forme. - Les parties locales non ASCII comme
josé@example.comsont considérées comme invalides. Leur livrer du courrier exige une extension SMTP que la plupart des serveurs de réception ne proposent pas, si bien qu’en pratique elles rebondissent.
La même étape prépare deux éléments utilisables tout de suite. syntax.normalized_email donne la forme canonique de la boîte : chez Gmail, les points et tout ce qui suit un + ne changent pas la destination, donc [email protected] devient [email protected], ce qui facilite le repérage des doublons dans une liste. Et quand le domaine est à une ou deux lettres d’un fournisseur connu, syntax.suggestion propose la correction probable (gmial.com devient gmail.com) et le code de raison possible_typo est ajouté.
| Champ | Ce qu’il vous apprend |
|---|---|
syntax.is_valid_syntax | Si l’adresse est bien formée |
syntax.username, syntax.domain | Les deux moitiés, telles que vérifiées |
syntax.normalized_email | La boîte canonique, pour dédoublonner |
syntax.suggestion | Une correction de faute probable, ou null |
Étape 2 : enregistrements DNS et MX
Un domaine indique où doit aller son courrier grâce aux enregistrements MX. Le vérificateur les consulte, et la réponse apparaît dans mx.records (les serveurs de messagerie du domaine) et mx.accepts_mail. Un domaine sans enregistrement MX n’a nulle part où livrer, et le résultat porte le code de raison no_mx. Cela suffit à écarter un nombre surprenant de mauvaises adresses : domaines d’entreprise expirés, fautes de frappe qui se trouvent être enregistrées, domaines inventés saisis dans des formulaires d’inscription.
C’est aussi à cette étape que l’adresse est comparée à ce que l’on sait de son domaine et de sa partie locale :
misc.is_disposablesignale les services de boîtes jetables (code de raisondisposable).misc.is_role_accountsignale les adresses partagées commeinfo@ousupport@(role_account).misc.is_spam_trap_domainsignale les domaines connus pour exploiter des pièges à spam (spam_trap).- Les fournisseurs grand public gratuits comme Gmail sont notés avec
free_provider.
L’hôte MX identifie aussi le fournisseur de messagerie derrière le domaine, par exemple Google Workspace ou Microsoft 365. Cela compte pour l’étape suivante, car chaque grand fournisseur répond à la vérification à sa manière.

Étape 3 : la sonde SMTP
C’est l’étape qui distingue une vraie vérification d’un simple contrôle de format. Le vérificateur se connecte à l’un des hôtes MX du domaine sur le port 25 et entame la même conversation que n’importe quel serveur d’envoi :
- Il se présente avec
EHLO. - Il indique un expéditeur avec
MAIL FROM. - Il indique l’adresse à tester avec
RCPT TO. - Il lit la réponse du serveur pour ce destinataire et ferme la connexion.
Le message lui-même, l’étape DATA, n’a jamais lieu. Ce qui compte, c’est la réponse du serveur à l’étape 3 :
- Acceptée (réponse
250) :smtp.is_deliverablevauttrue. - Refusée, utilisateur inconnu :
smtp.is_deliverablevautfalse, avec le code de raisonsmtp_undeliverable. - Refusée car le compte est désactivé :
smtp.is_disabledvauttrue(disabled_mailbox). - Refusée car la boîte est pleine :
smtp.has_full_inboxvauttrue(full_inbox).
Sur la même connexion, BounceIntel interroge ensuite le serveur sur un second destinataire : une adresse aléatoire de 15 caractères sur le même domaine, qui ne peut pas exister. Si le serveur l’accepte aussi, smtp.is_catch_all vaut true. Nous verrons plus bas pourquoi c’est important.
"smtp": {
"can_connect_smtp": true,
"is_deliverable": true,
"is_disabled": false,
"has_full_inbox": false,
"is_catch_all": false
}
Tous les serveurs ne répondent pas franchement. Certains retardent volontairement les expéditeurs inconnus avec un refus temporaire (greylisting), d’autres limitent le débit, d’autres refusent les connexions venant de réseaux qu’ils ne reconnaissent pas, et certains ne répondent tout simplement pas à temps. Rien de tout cela n’est un verdict sur l’adresse, et BounceIntel ne fait pas semblant du contraire. Le résultat devient unknown, et un code de raison nomme ce qui s’est passé : transient_smtp, smtp_policy_block, smtp_timeout, smtp_network, smtp_ambiguous ou smtp_unreachable.
Étape 4 : score et codes de raison
La dernière étape transforme tous les signaux des trois premières en quelque chose d’exploitable. score.score va de 0 à 100 et correspond à une catégorie : 80–100 donne valid, 50–79 risky, 1–49 unknown et 0 invalid. score.confidence et score.confidence_level (high, medium, low ou very_low) indiquent combien d’indices soutiennent ce chiffre, et score.safe_to_send donne la réponse par oui ou non.
La partie sur laquelle construire est score.reason_codes. Elle liste chaque signal ayant influencé le résultat, sous forme de chaînes stables sur lesquelles votre code peut s’appuyer, et score.sub_reason nomme celui qui a été décisif. À côté, bounce_risk.action recommande quoi faire (send, send_with_caution, verify_manually ou do_not_send), et bounce_risk.risk_factors explique cette recommandation, chaque facteur avec son poids.
Voici un résultat réel pour une adresse de support partagée, sur un domaine qui accepte tout le courrier, réduit aux champs de score :
{
"input": "[email protected]",
"is_reachable": "risky",
"score": {
"score": 55,
"category": "risky",
"confidence_level": "low",
"reason_codes": ["catch_all", "role_account", "catch_all_high_risk"],
"sub_reason": "catch_all",
"safe_to_send": false
},
"bounce_risk": {
"action": "verify_manually",
"risk_factors": [
{ "signal": "smtp_is_catch_all", "contribution": 20, "description": "Corporate catch-all mailbox" },
{ "signal": "is_role_account", "contribution": 10, "description": "Role-based mailbox" }
]
}
}
Dans votre code, décidez à partir de la recommandation et conservez les codes de raison pour la personne qui examinera l’adresse plus tard :
const { bounce_risk, score } = await res.json();
if (bounce_risk.action === "do_not_send") {
suppress(email, score.reason_codes);
} else if (bounce_risk.action === "verify_manually") {
queueForReview(email, score.reason_codes);
} else {
accept(email);
}
Le score tient aussi compte de l’historique de votre propre compte avec cette adresse sur les 180 derniers jours, ce qui explique qu’un nouveau test puisse revenir avec plus de confiance que le premier.
L’angle mort du catch-all
L’étape 3 a une limite qu’aucun vérificateur ne peut contourner. Certains domaines sont configurés pour accepter le courrier de toutes les adresses, réelles ou non. Demandez à leur serveur si jane.doe@ existe, il dit oui ; demandez-lui une suite de caractères aléatoires, il dit encore oui. La conversation SMTP prouve que le domaine reçoit du courrier. Elle ne peut pas prouver que la boîte qui vous intéresse existe.
C’est précisément le rôle de la sonde avec une adresse aléatoire. Quand elle est acceptée, BounceIntel classe le résultat risky au lieu de safe, ajoute le code de raison catch_all et évalue le risque avec un code de gravité (catch_all_low_confidence, catch_all_medium_confidence ou catch_all_high_risk) fondé sur des indices comme la configuration du domaine et les formats de nom déjà vérifiés dans cette entreprise. Un vérificateur qui qualifie ces adresses de « valides » décrit la politesse du serveur, pas la boîte.
Ce que signifient « safe / risky / invalid / unknown »
is_reachable résume en un mot tout ce qui précède. Le vérificateur gratuit de ce site affiche ces quatre mêmes valeurs, avec des libellés traduits.
is_reachable | Ce qui s’est passé | Que faire |
|---|---|---|
safe | Le serveur a accepté la boîte et aucun signal de risque n’est apparu | Envoyer |
risky | La boîte semble exister, mais le domaine est catch-all, l’adresse est jetable ou générique, la boîte est pleine ou le domaine exploite des pièges à spam | Lire les codes de raison, puis décider |
invalid | Syntaxe incorrecte, ou boîte refusée ou désactivée par le serveur | La supprimer |
unknown | Le serveur n’a pas donné de réponse exploitable : délai dépassé, greylisting ou blocage | La garder et la tester plus tard |
Deux erreurs sont fréquentes ici. unknown décrit un serveur à un instant donné, pas l’adresse, et supprimer ces adresses revient donc à jeter de bons contacts. Et risky recouvre des situations très différentes : une boîte pleine est souvent temporaire, alors qu’une adresse jetable n’appartiendra jamais à un client. L’étiquette est un résumé. La décision revient à bounce_risk.action et à score.reason_codes.
Temps réel ou vérification en masse
Les quatre mêmes étapes s’exécutent dans les deux cas. Ce qui change, c’est le moment.
La vérification en temps réel, une adresse à la fois avec POST /v1/check_email, a sa place là où une adresse entre dans vos systèmes : formulaires d’inscription, paiement, formulaires de contact commercial, un commercial qui saisit un contact dans le CRM. La personne est encore là, donc une faute repérée par syntax.suggestion peut être corrigée sur le moment au lieu de devenir un rebond la semaine suivante. Appelez l’API depuis votre serveur, jamais depuis du code navigateur contenant votre clé, et traitez unknown comme « accepter et retester plus tard » pour qu’un serveur lent ne bloque jamais une vraie inscription.
La vérification en masse, avec POST /v1/bulk ou un import CSV dans le tableau de bord, a sa place avant un envoi : une newsletter vers une liste restée inutilisée, un import depuis un salon ou un nouveau CRM, ou un passage régulier sur une ancienne base. Chaque ligne revient avec les mêmes champs. Les listes se dégradent à mesure que les gens changent de poste, donc vérifiez tout ce qui n’a pas été testé depuis quelques mois avant de l’utiliser.
| Temps réel | En masse | |
|---|---|---|
| Endpoint | POST /v1/check_email | POST /v1/bulk, puis suivi du job |
| Meilleur moment | Quand l’adresse est collectée | Avant une campagne ou après un import |
| Principal gain | Fautes corrigées tant que la personne est là | Adresses mortes retirées avant de rebondir |
Traitement de unknown | Accepter, retester plus tard | Écarter de cet envoi, retester |
Tester une adresse et lire le résultat
Tout ce qu’affiche le vérificateur provient de la même API que votre code appellerait. La documentation de l’API détaille chaque champ de la réponse, la vérification en masse couvre les listes entières, et les tarifs indiquent le prix d’une offre avec accès à l’API.

