Che cos'è la verifica delle email? Guida per sviluppatori
Quando qualcuno scrive un indirizzo email nel tuo modulo di registrazione, che cosa ne sai davvero? Se controlli solo la sintassi — ha la forma di un'email? — non ne sai quasi niente. La verifica delle email è il processo con cui si stabilisce se un indirizzo è reale, raggiungibile e degno di essere tenuto.
Questa guida spiega che cosa controlla davvero la verifica, come funziona ogni strato e in quale punto del tuo stack va inserita.
Che cosa la verifica delle email non è
La validazione della sintassi non è verifica delle email. Controllare che un indirizzo combaci con /^[^\s@]+@[^\s@]+\.[^\s@]+$/ ti dice soltanto che la stringa ha una chiocciola e un punto. Non intercetta:
test@mailinator.com— indirizzo usa e getta, cancellato in 10 minutinoreply@example.com— indirizzo di ruolo che nessuno leggeuser@nonexistent-domain.com— dominio senza server di postaghost@real-company.com— indirizzo la cui casella è stata eliminata
Una catena di verifica completa ha cinque strati distinti. Ognuno elimina una classe diversa di indirizzi cattivi.
Strato 1: validazione della sintassi
Il primo controllo normalizza e valida il formato dell'indirizzo secondo l'RFC 5321 e l'RFC 5322. Oltre all'espressione regolare di base, intercetta casi limite come:
- Punti doppi (
user..name@domain.com) - Punti all'inizio o alla fine della parte locale
- Caratteri non validi nella parte locale
- Indirizzi troppo lunghi (limite dell'RFC: 254 caratteri in tutto, 64 nella parte locale)
La maggior parte degli indirizzi che cadono qui cade per un refuso dell'utente, e questo passaggio si conclude in microsecondi.
Strato 2: interrogazione del dominio e dei record MX
Una sintassi valida non significa che il dominio esista né che accetti posta. Il secondo strato fa interrogazioni DNS:
- Interrogazione dei record MX — il dominio ha record di scambio posta che puntano a un server SMTP?
- Ripiego sul record A — se non c'è un record MX, il dominio si risolve almeno?
- Esistenza del dominio — è registrato e non scaduto?
Un dominio come emai.com (refuso comune di email.com) supera la validazione della sintassi ma non ha record MX, e non lo avrà mai. Questo controllo elimina categorie intere di refusi e di domini scaduti di recente.
# Controllo manuale: interrogare i record MX di un dominio
dig MX gmail.com
# ;; ANSWER SECTION:
# gmail.com. 3600 IN MX 5 gmail-smtp-in.l.google.com.Strato 3: verifica SMTP
Il controllo di maggior valore è un dialogo SMTP con il server di posta. Il verificatore si collega al server MX, avvia una conversazione e chiede se la casella esiste, senza mai inviare alcun messaggio.
Lo scambio è così:
→ EHLO verifier.mailbeam.dev
← 250-smtp.gmail.com Hello
→ MAIL FROM:<probe@mailbeam.dev>
← 250 2.1.0 OK
→ RCPT TO:<user@gmail.com>
← 250 2.1.5 OK ← la casella esiste
Se il server risponde con un 550 o un 551 al comando RCPT TO, la casella non esiste. Il verificatore emette allora un RSET per interrompere prima di mandare qualsiasi cosa.
Questo intercetta indirizzi che superano sintassi e record MX ma che non hanno una casella vera: cosa frequente dopo il ricambio dei dipendenti, la chiusura di account o la creazione massiva di account falsi.
Limiti dell'SMTP
Alcuni server di posta non collaborano. Rispondono 250 OK a qualsiasi indirizzo (comportamento catch-all) per non rivelare quali caselle esistono. Altri limitano il ritmo dei sondaggi di verifica SMTP. È qui che conta il quarto strato.
Strato 4: assegnare un punteggio ai casi ambigui
Quando l'SMTP dà un risultato ambiguo — di solito un dominio catch-all — ti serve qualcosa di diverso da un sì o da un no. Alcuni servizi applicano un modello di apprendimento automatico addestrato su dati storici di invio. Mailbeam usa invece un punteggio additivo: un insieme fisso di segnali con pesi e limiti pubblicati, in cui un indirizzo catch-all non può mai superare 70 perché nessun sondaggio può confermarlo.
Il compromesso è deliberato. Una griglia di regole non batterà un buon modello sugli indirizzi genuinamente ambigui, ma ogni punto è tracciabile fino a un controllo, quindi quando il numero sorprende si può capire perché. L'uscita va da 0 a 100 invece di essere un risultato binario, il che permette di applicare soglie diverse secondo il caso d'uso:
const result = await verifyEmail(email);
if (result.catchAll) {
// Email aziendale: accetta con fiducia alta, marca quella media, rifiuta la bassa
if (result.score >= 70) return "accept";
if (result.score >= 40) return "flag_for_review";
return "reject";
}Strato 5: controlli sui metadati
Al di là della recapitabilità, le API di verifica espongono metadati utili:
disposable— è un dominio di posta temporanea noto (Mailinator, 10MinuteMail, eccetera)?role— è un indirizzo di ruolo comeinfo@,noreply@oadmin@?suggestion— l'utente voleva scriveregmail.cominvece digmai.com?free— è un provider gratuito (Gmail, Outlook)?
Questi segnali ti permettono di applicare regole diverse a tipi di indirizzo diversi: per esempio accettare gli indirizzi di ruolo per i contatti di fatturazione e rifiutarli nelle liste di marketing.
Quando usare la verifica delle email
In registrazione (in tempo reale)
Il punto di integrazione di maggior valore. Verifica l'indirizzo prima di creare l'account, mentre la persona è ancora davanti al modulo.
// Server Action di Next.js
async function createAccount(formData: FormData) {
const email = formData.get("email") as string;
const result = await verifyEmail(email);
if (!result.valid) {
return { error: result.suggestion
? `Intendevi ${result.suggestion}?`
: "Quell'indirizzo email non sembra valido." };
}
if (result.disposable) {
return { error: "Gli indirizzi email temporanei non sono ammessi." };
}
// prosegui con la creazione dell'account
}La verifica in tempo reale ha bisogno di un'API sotto i 100 ms: qualsiasi cosa più lenta blocca l'invio del modulo in modo percepibile.
Prima di un invio massivo
Prima di importare un CSV o di scrivere a una lista fredda, lancia un lavoro di verifica in blocco. Così proteggi la tua reputazione da mittente prima che il danno sia fatto.
const auth = { Authorization: `Bearer ${process.env.MAILBEAM_KEY}` };
// Invia la lista; la risposta è un id di lavoro, non i risultati.
const job = await fetch("https://api.mailbeam.dev/v1/verify/batch", {
method: "POST",
headers: { ...auth, "Content-Type": "application/json" },
body: JSON.stringify({ emails }),
}).then((r) => r.json());
// Aspetta il webhook batch.completed, oppure interroga /v1/jobs/:id fino alla fine.
const { results } = await fetch(
`https://api.mailbeam.dev/v1/jobs/${job.job_id}/results?format=json`,
{ headers: auth }
).then((r) => r.json());
const deliverable = results
.filter((r) => r.status === "deliverable" && r.score >= 60)
.map((r) => r.email);Pulizia periodica delle liste
Gli indirizzi email si degradano a un ritmo fra il 20% e il 30% l'anno. Indirizzi che erano validi 18 mesi fa possono rimbalzare oggi. Pulire la lista ogni 6 mesi tiene a bada il tasso di bounce senza toccare il frontend.
Che cosa fare con il risultato
Un errore comune è trattare la verifica come una porta binaria. Il modello migliore è un trattamento a livelli:
| Risultato | Azione |
|---|---|
valid: true, score >= 70 | Accettare subito |
valid: true, score 40–69 | Accettare, ma sorvegliare l'interazione |
valid: true, score < 40, catchAll: true | Accettare nei flussi ad alta intenzione; rifiutare nel contatto a freddo |
valid: false, suggestion | Mostrare il suggerimento all'utente |
disposable: true | Bloccare con un messaggio |
valid: false, senza suggerimento | Mostrare un errore di validazione generico |
In sintesi
La verifica delle email è una catena, non un controllo unico:
- Sintassi — il formato è valido?
- DNS/MX — il dominio accetta posta?
- SMTP — quella casella precisa esiste?
- Punteggio — sui domini catch-all, quanta fiducia resta?
- Metadati — è usa e getta, di ruolo o un refuso?
Eseguire tutti e cinque gli strati — con un'API oppure costruendo la tua catena — è ciò che separa un indirizzo reale da uno che gli somiglia.