On pense souvent qu’un bon plugin de formulaire suffit à filtrer les adresses email invalides. C’est faux dans la majorité des configurations par défaut : Gravity Forms, WPForms ou Contact Form 7 vérifient une syntaxe sans confirmer qu’une boîte existe réellement derrière. Trois familles de méthodes coexistent sur un site WordPress pour traiter ce champ : la fonction native is_email(), la couche de validation embarquée dans le plugin de formulaire ou une API tierce branchée sur le hook de soumission. Aucune des trois ne couvre le même périmètre. Les confondre finit par polluer la base d’emails.
Ce que la fonction native is_email() vérifie réellement
is_email() est la fonction que WordPress utilise en interne pour les comptes utilisateurs et les commentaires. Elle sert aussi à la plupart des champs email natifs du core. Elle contrôle la structure de la chaîne : présence d’un arobase, domaine composé d’au moins un point, absence de caractères interdits. Rien de plus. Elle n’interroge jamais le DNS du domaine, ne teste aucun enregistrement MX et n’ouvre aucune connexion SMTP vers le serveur destinataire. Une adresse syntaxiquement correcte mais pointant vers un domaine qui n’existe plus ou vers une boîte supprimée depuis 2 ans passe le contrôle sans encombre.
C’est un filtre de premier niveau : il valide un format, jamais une délivrabilité réelle. La référence développeur du core WordPress signale d’ailleurs ses limites. Elle ne gère pas les domaines internationalisés (IDN) et n’est pas strictement conforme à la RFC 5322 (référence développeur WordPress). Le filtre is_email permet de surcharger le comportement. Rares sont pourtant les sites qui l’utilisent.
Les plugins de formulaire ajoutent une couche, rarement une vérification d’existence
Les plugins de formulaire les plus utilisés (Gravity Forms, WPForms, Fluent Forms) reproduisent la logique de is_email() avec une regex parfois légèrement plus stricte, puis exposent un hook pour aller plus loin. Gravity Forms fournit le filtre gform_email_field_rejectable_values, documenté officiellement pour rejeter des motifs précis. Aucune liste de domaines jetables n’est intégrée par défaut : la détection du disposable email passe par une extension dédiée ou un snippet qui interroge une liste externe. WPForms déclenche wpforms_process_validate_email à la soumission, un point d’entrée propre mais vide de logique anti-jetable native. Fluent Forms expose fluentform/validate_input_item_input_email, dont la documentation officielle couvre aussi bien la restriction de domaines autorisés que le branchement d’une API de vérification tierce.
Résultat : la plupart des formulaires en production filtrent une syntaxe deux fois, une fois côté navigateur en HTML5, une fois côté serveur dans le plugin, sans jamais confirmer que la boîte existe. Une adresse en @yopmail.com ou @tempmail.io passe sans problème tant que la chaîne respecte le format attendu.
Brancher une API de vérification sur le hook de soumission
La 3e famille consiste à appeler un service de vérification en temps réel au moment précis du POST de soumission, avant l’enregistrement en base. Ce service interroge la chaîne SMTP du domaine destinataire (existence du serveur, réponse du mail exchanger) pour rendre un verdict. Le statut renvoyé est soit valide soit invalide dans la majorité des cas. 2 statuts intermédiaires complètent la grille : risquée pour un domaine en catch-all ou une adresse à rôle, indéterminée quand le serveur distant ne répond pas à temps. C’est la seule des 3 familles capable de distinguer une adresse syntaxiquement propre mais morte d’une adresse réellement joignable. Le choix se mesure au taux de hard bounce réellement observé sur le formulaire concerné et à l’écart constaté avec les 2 premières familles.

L’implémentation suit toujours le même schéma, quel que soit le plugin de formulaire ciblé :
- Accrocher la vérification au hook de validation du plugin (
wpcf7_validate_email*pour Contact Form 7,gform_field_validationpour Gravity Forms,wpforms_process_validate_emailpour WPForms). - Appeler l’API avec un timeout court, 2 à 3 secondes maximum, via
wp_remote_get(). - Définir explicitement le comportement en cas d’échec réseau ou de réponse anormale : laisser passer (fail-open) ou bloquer (fail-closed).
- Ne rejeter que le statut réellement invalide, jamais un statut risqué ou indéterminé, pour éviter de bloquer un prospect légitime.
Voici un exemple fonctionnel branché sur Contact Form 7, avec CaptainVerify comme API de référence côté hook :
add_filter( 'wpcf7_validate_email*', 'mw_verify_email_on_submit', 20, 2 );
function mw_verify_email_on_submit( $result, $tag ) {
$email = isset( $_POST[ $tag->name ] ) ? sanitize_email( $_POST[ $tag->name ] ) : '';
// La regex native a déjà éliminé les formats invalides, inutile de la refaire
if ( empty( $email ) || ! is_email( $email ) ) {
return $result;
}
$endpoint = add_query_arg(
array(
'apikey' => defined( 'CAPTAINVERIFY_API_KEY' ) ? CAPTAINVERIFY_API_KEY : '',
'email' => rawurlencode( $email ),
),
'https://api.captainverify.com/v2/verify'
);
$response = wp_remote_get( $endpoint, array( 'timeout' => 3 ) );
// Fail-open : timeout, DNS injoignable, 5xx -> on laisse passer le formulaire
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
return $result;
}
$body = json_decode( wp_remote_retrieve_body( $response ), true );
// Quota du compte atteint ou clé invalide : la même logique fail-open s'applique
if ( empty( $body['success'] ) ) {
return $result;
}
if ( 'invalid' === $body['result'] ) {
$result->invalidate( $tag, 'Cette adresse email semble injoignable. Vérifiez la saisie.' );
}
return $result;
}
Ce snippet ne bloque volontairement que le statut invalid. Un domaine catch-all ou une adresse à rôle (contact@, info@) remonte en statut risky et passe le formulaire : les rejeter systématiquement produirait des faux positifs sur des prospects B2B légitimes qui utilisent une adresse générique.
Un hook de validation ajouté dans functions.php n’est jamais totalement à l’abri d’une montée de version majeure. Le core WordPress tient une politique de compatibilité ascendante stricte. Les changements de comportement d’une version majeure à l’autre ont pourtant déjà cassé du code maison mal isolé. Le même risque plane sur un hook rangé dans un fichier de fonctions partagé avec d’autres customisations client.
Le tableau comparatif : trois méthodes, six critères
| Critère | is_email() natif | Plugin de formulaire | API en hook (temps réel) |
|---|---|---|---|
| Faux positifs | Rares (contrôle permissif) | Faibles à modérés selon la regex du plugin | Présents si le statut « risky » est bloqué à tort ; résiduels si seul « invalid » est rejeté |
| Temps ajouté au submit | Nul, calcul local instantané | Nul à négligeable, calcul local | Quelques centaines de ms, dépend du timeout fixé |
| Détection disposable / catch-all | Aucune | Aucune en natif, extension dédiée requise | Oui pour le disposable connu, dans la limite des listes tenues à jour ; catch-all signalé mais jamais tranché avec certitude |
| RGPD et hébergement UE | Non concerné, aucune donnée transmise à un tiers | Non concerné en natif, dépend des add-ons tiers ajoutés | Dépend du prestataire choisi ; vérifier le lieu d’hébergement dans les conditions du fournisseur |
| Hooks et filtres disponibles | Filtre is_email unique |
1 hook par plugin et par type de champ (voir liste ci-dessus) | S’accroche sur les mêmes hooks que les plugins, en aval de leur propre validation |
| Comportement si le service tombe | Sans objet, aucune dépendance réseau | Sans objet en natif | Dépend du code du hook : fail-open si les erreurs réseau et les réponses anormales sont explicitement laissées passer |
Catch-all et panne de service : deux angles morts qu’aucune méthode n’élimine
Un domaine en catch-all accepte tous les emails envoyés, y compris ceux dont la boîte n’existe pas, ce qui rend la vérification SMTP structurellement incapable de trancher. Aucune API ne lèvera cette indécision : la question devient de savoir si le formulaire accepte ou refuse un statut risqué. Sur des domaines d’entreprise, où la configuration catch-all reste courante, un refus systématique revient à fermer la porte à des contacts parfaitement valides.
« […] the unknown status will always be returned, so as not to block your application. » CaptainVerify, documentation API
Cette phrase documente précisément le comportement fail-open par défaut : plutôt que de casser un formulaire de contact quand le quota d’appels d’un compte est atteint, le fournisseur renvoie un statut neutre qui laisse passer la soumission. C’est un choix de conception délibéré. Il vaut la peine de vérifier que le prestataire choisi documente la même logique avant de brancher un hook en production.
L’objection RGPD : une question de sous-traitance à vérifier au cas par cas
Envoyer l’email saisi dans un formulaire à un service tiers pour vérification pose une vraie question de sous-traitance de données au sens du RGPD, distincte de celle posée par un simple champ natif ou un plugin sans add-on externe. Avant tout branchement, deux éléments concrets comptent dans les conditions générales du prestataire, au-delà de sa promesse marketing : le lieu d’hébergement des serveurs de traitement et l’existence d’un accord de sous-traitance (DPA) conforme à l’article 28 du RGPD. Un prestataire hébergé hors UE sans clauses contractuelles types complique l’analyse d’impact, même si le service fonctionne techniquement à l’identique.
Le hook de validation s’exécute uniquement sur le POST de soumission, jamais sur le chargement de la page : aucun impact sur le LCP ou l’INP mesurés par les Core Web Vitals. La requête sortante ne passe ni par le cache full-page ni par le CDN edge qui sert le reste du site. Sur un hébergement mutualisé bas de gamme, en revanche, les connexions sortantes vers une API tierce sont parfois bridées par le fournisseur ; un hébergement managé les autorise plus largement.
Verdict par cas d’usage
Pour un formulaire de contact simple, sans enjeu de délivrabilité derrière, le filtre natif suffit : le volume de spam généré par des adresses invalides reste marginal et ne justifie pas une dépendance réseau supplémentaire.
Pour un formulaire d’inscription à une liste email, la question change de nature. Depuis février 2024, Google applique des exigences renforcées au-delà de 5 000 messages par jour vers Gmail. Yahoo impose les mêmes règles à ses expéditeurs en volume : authentification SPF, DKIM et DMARC, désabonnement en un clic, taux de plaintes maintenu sous 0,3 % avec 0,1 % comme cible recommandée. Aucun des deux ne publie de seuil de bounce officiel. Les adresses inexistantes dégradent malgré tout la réputation d’expédition et alimentent des rejets au niveau SMTP. Chaque adresse jetable ou inexistante qui entre en base aujourd’hui redevient un hard bounce dans les semaines suivantes. C’est le cas où l’API en hook justifie sa complexité de mise en œuvre et sa latence ajoutée.
Pour un formulaire de lead B2B à fort enjeu commercial, où chaque contact généré pèse lourd dans le pipeline commercial, ce choix d’architecture mérite d’être posé explicitement avec le client avant le lancement du formulaire. Un réglage laissé par défaut au plugin se découvre souvent 6 mois plus tard, dans un rapport de bounce rate.
Questions fréquentes
is_email() vérifie-t-il que le domaine existe vraiment ?
Non. La fonction contrôle uniquement la syntaxe de la chaîne. Elle n’effectue aucune requête DNS et ne sait pas si le domaine ou la boîte destinataire existent réellement.
Faut-il aussi valider le champ email côté JavaScript ?
La validation HTML5 native (type="email") améliore l’expérience utilisateur en signalant une erreur avant l’envoi. Elle reste contournable et ne remplace jamais un contrôle serveur : elle sert l’ergonomie, jamais la sécurité.
Que se passe-t-il si l’API de vérification tombe en panne pendant un pic de trafic ?
Avec un hook fail-open correctement écrit, le formulaire continue d’accepter les soumissions en se rabattant sur la validation native. Ce comportement vient du code du hook : il faut avoir explicitement codé le timeout et le traitement des réponses en erreur pour que la validation native prenne le relais si le fournisseur ne répond pas, plutôt que de compter sur un comportement implicite.
Ce comparatif s’arrête à la vérification au moment de la saisie. Une base d’emails collectée aujourd’hui se dégrade avec le temps, un domaine racheté change de statut, une boîte abandonnée finit fermée, ce qui pose la question distincte de la revérification périodique d’une liste déjà constituée.


