Si è tentati di considerare la validazione di un indirizzo email in Laravel una questione
da una riga: aggiungi email a un array di validazione e passi oltre. Quella regola è un buon inizio, ma
risponde solo alla prima delle tre domande che pone una vera validazione. L'indirizzo
ha la forma corretta? Il suo dominio può ricevere posta? La casella esiste davvero?
Laravel ha la particolarità che la sua regola integrata email può rispondere alle
prime due in una sola riga; la terza è un problema di rete che conviene delegare.
Questa guida costruisce ogni livello sopra il validatore di Laravel e mostra
esattamente dove si ferma il framework. Estende la
guida alla validazione delle email in PHP: Laravel
racchiude gli stessi elementi di base di PHP (e filter_var è a una parola chiave di
distanza) in un'API molto più comoda.
In breve#
Usa la regola email:rfc,dns di Laravel per sintassi e ricerca MX in un solo
passaggio, poi un'API di verifica per il controllo SMTP della casella: si parte dal
più economico e ci si ferma con bail non appena un livello è risolutivo. Non provare
ad aprire una sessione SMTP dalla tua app per testare direttamente le caselle: la
porta 25 in uscita è bloccata dalla maggior parte degli host e la risposta dipende
dalla reputazione dell'IP di invio e dal greylisting, cose che non vuoi reimplementare.
Ogni livello esclude indirizzi a un costo minore del successivo; solo l'ultimo può
confermarne uno.
Livelli 1 e 2: sintassi e DNS in una sola regola#
La regola email si appoggia al pacchetto egulias/email-validator e accetta degli
stili che ne decidono il rigore. Per impostazione predefinita applica lo stile rfc
(grammatica RFC 5321/5322). Quello che conta per la validazione è dns, che aggiunge
una ricerca in tempo reale e conferma che il dominio si risolva in un instradamento della
posta: un record MX, con un record A come ripiego. Chiedili entrambi e Laravel controlla
sintassi e dominio in una sola regola:
public function store(Request $request)
{
$validated = $request->validate([
'email' => ['required', 'email:rfc,dns'],
]);
// $validated['email'] is well-formed AND its domain can receive mail.
}
Vale la pena conoscere anche gli altri stili. email:filter esegue
filter_var($email, FILTER_VALIDATE_EMAIL) di PHP, lo stesso identico controllo della
guida PHP, e filter_unicode ammette alcune parti
locali Unicode. strict rifiuta gli avvisi su punti finali e consecutivi che il parser
RFC tollera. E spoof protegge dai caratteri omografi ingannevoli, quindi per un
modulo di iscrizione pubblico email:rfc,dns,spoof è un default sensato. In una
form request si scrive così:
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreSubscriberRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => ['required', 'email:rfc,dns,spoof'],
];
}
}
Perché email:rfc,dns non è ancora un via libera#
Superare email:rfc,dns significa che la stringa è ben formata e che il dominio può
ricevere posta. Non dice nulla sull'esistenza della casella specifica.
noreply-9f2x@gmail.com passa. Passa anche definitely-fake@gmail.com. Entrambi sono
non recapitabili, perché il record MX è un fatto che riguarda il dominio e la casella
è un fatto che puoi scoprire solo chiedendolo al server di posta. È lo stesso muro che
fa sì che la validazione delle email con le regex non funzioni:
nessun pattern matching e nessuna ricerca DNS permettono di passare da "il dominio
accetta posta" a "questo indirizzo la accetta".
Se vuoi vedere questo divario con i tuoi occhi, incolla un indirizzo sintatticamente
perfetto nella verifica email gratuita e guarda una stringa
approvata dalla regola tornare undeliverable.
Livello 3: la casella esiste davvero?#
Confermare una casella specifica richiede la conversazione SMTP di consegna:
connettersi all'host di posta, inviare RCPT TO, leggere la risposta e disconnettersi
prima di spedire qualsiasi cosa. In linea di principio potresti scriverlo in PHP, ma
non dovresti eseguirlo dal tuo server applicativo: la maggior parte dei provider cloud
blocca la porta 25 in uscita, la risposta dipende dalla reputazione dell'IP da cui ti
connetti e i server riceventi applicano il greylisting e limitano la frequenza dei
mittenti sconosciuti. E non è tutto:
come funziona la verifica email illustra l'intera
pipeline, compresi i domini catch-all che accettano qualsiasi indirizzo e vanificano un
test ingenuo. Questo è il livello da delegare.
Chiamare Qualisend da una regola di validazione personalizzata#
Laravel rende pulita la delega: racchiudi la chiamata API in un oggetto regola e inseriscilo nello stesso array di regole. Generane uno con Artisan:
php artisan make:rule DeliverableEmail
Tieni la chiave fuori dal codice collegandola tramite config/services.php, che la
legge dal tuo .env:
// config/services.php
'qualisend' => [
'key' => env('QUALISEND_API_KEY'),
],
Poi la regola chiama l'endpoint di verifica con la facade Http, legge l'involucro
result e fallisce solo quando l'esito è undeliverable:
namespace App\Rules;
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Support\Facades\Http;
class DeliverableEmail implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
try {
$response = Http::withToken(config('services.qualisend.key'))
->timeout(10)
->post('https://app.qualisend.com/api/v1/verify', ['email' => $value]);
} catch (ConnectionException $e) {
// A timeout or network error: let the signup through, verify later.
return;
}
// On our own outage or a rate limit, don't block a real signup.
if ($response->failed()) {
return;
}
$result = $response->json('result');
if (($result['status'] ?? null) === 'undeliverable') {
$fail('This email address appears to be undeliverable.');
}
}
}
Http::withToken() imposta l'intestazione di autenticazione bearer, ->post() invia
il corpo JSON e $response->json('result') estrae l'oggetto annidato result con
l'accesso a notazione puntata. Un timeout o un errore di connessione solleva una
ConnectionException invece di restituire una risposta, quindi la regola intercetta
anche quella e lascia passare l'iscrizione. Il riferimento API contiene
la forma completa della richiesta, e la prima risposta si presenta così:
{
"job_id": "5b1f3c2a-8d4e-4f6a-9b7c-2e1d0a9f8c71",
"result": {
"status": "unknown",
"score": 61,
"reason": null,
"smtp": "pending",
"sub_flags": { "role": false, "disposable": false, "free_mail": false, "catch_all": false }
}
}
status è uno tra deliverable, risky, undeliverable e unknown. La regola qui
sopra fa fallire solo undeliverable e lascia passare risky e unknown, così puoi
decidere a valle cosa farne (filtrare in base a score o cambiare comportamento in base a una voce di
sub_flags come disposable) invece di trasformare un indirizzo dubbio in un errore
del modulo. Considera il JSON qui sopra come la forma, non come il contratto; l'elenco
completo dei campi si trova nella documentazione per sviluppatori.
Quel primo status è l'esito immediato. Quando result.smtp è "pending", come qui
sopra, il test della casella è ancora in corso e l'esito definitivo arriva su
GET https://app.qualisend.com/api/v1/jobs/{job_id} appena termina. Non tenere il
modulo in attesa e non richiamare /verify: conserva il job_id, interrogalo da un
job in coda (fuori dal percorso della richiesta) e agisci lì su un risultato
undeliverable. Quando smtp è "cached" o "skipped", result è già definitivo.
Mettere insieme i livelli per validare un indirizzo email in Laravel#
Componi tutti e tre in una sola form request, partendo dal più economico, e lascia che
bail interrompa tutto al primo errore, così la regola API viene eseguita solo sugli indirizzi
che hanno già superato sintassi e controllo MX:
namespace App\Http\Requests;
use App\Rules\DeliverableEmail;
use Illuminate\Foundation\Http\FormRequest;
class StoreSubscriberRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => [
'bail',
'required',
'email:rfc,dns',
new DeliverableEmail(),
],
];
}
public function messages(): array
{
return [
'email.email' => 'Enter a valid email address on a real domain.',
];
}
}
Tutto il segreto sta in bail. Un indirizzo malformato o un dominio inattivo falliscono
in locale e non spendono mai un credito API; al livello SMTP arrivano solo gli
indirizzi che meritano il round trip di rete. Specifica il tipo della request nel tuo
controller e Laravel esegue la pipeline prima ancora che parta il corpo del metodo:
public function store(StoreSubscriberRequest $request)
{
// Every layer has passed — safe to persist.
$subscriber = Subscriber::create($request->validated());
return redirect()->route('subscribers.index');
}
A rendere affidabile la validazione è la stratificazione, non il framework: è la stessa struttura della versione PHP, con Laravel che riunisce i primi due livelli in una sola regola. Esegui la pipeline veloce e sincrona all'iscrizione e riserva il passaggio più lento, confermato via SMTP, al lavoro di back office: la guida all'iscrizione serverless mostra lo schema in tempo reale e come pulire una lista email copre il lato batch.
Domande frequenti
01La regola email di Laravel controlla se il dominio esiste?
Solo se glielo chiedi. La semplice regola email valida la sintassi con il pacchetto egulias/email-validator (lo stile rfc). Aggiungi lo stile dns, cioè email:rfc,dns, e Laravel conferma anche che il dominio si risolva in un instradamento della posta, quindi un dominio inventato o inattivo fallisce nello stesso passaggio. Nessuno dei due stili contatta la casella, quindi superare il controllo significa comunque "sembra recapitabile", non "recapitabile".
02Qual è la differenza tra email:rfc, email:filter ed email:dns?
rfc valida rispetto alle RFC 5321/5322 tramite egulias ed è il valore predefinito di Laravel. filter esegue filter_var($email, FILTER_VALIDATE_EMAIL) di PHP, lo stesso identico controllo della guida PHP, mentre filter_unicode ammette alcuni caratteri Unicode. dns aggiunge una ricerca MX in tempo reale e spoof rifiuta i caratteri omografi ingannevoli. Li combini con le virgole, quindi email:rfc,dns è il filtro pratico per sintassi più dominio.
03Come verifico che una casella esista in Laravel?
Non con una regola integrata: la conferma della casella richiede una conversazione SMTP che non dovresti eseguire dal tuo server applicativo, perché la porta 25 è bloccata quasi ovunque e il risultato dipende dalla reputazione del tuo IP di invio. Racchiudi un'API di verifica in un oggetto ValidationRule personalizzato, chiamala con la facade Http, leggi l'involucro result e fai fallire la regola su undeliverable. Mettila dopo email:rfc,dns con bail, così viene eseguita solo sugli indirizzi che hanno già superato i livelli locali. Se result.smtp torna pending, il test della casella è ancora in corso: leggi l'esito definitivo da GET /api/v1/jobs/{job_id} in un job in coda, non dentro il validatore.
04La regola dns rallenterà l'invio dei miei moduli?
Può succedere. Lo stile dns esegue una ricerca DNS in tempo reale a ogni validazione, quindi un resolver lento o irraggiungibile blocca la richiesta. Per un singolo modulo di iscrizione va bene, ma evitalo nelle importazioni in blocco e non combinarlo con una chiamata API sincrona senza aver impostato un timeout sul client Http, come fa la regola DeliverableEmail qui sopra con ->timeout(10).
Vuoi aggiungere il livello della casella? Inserisci un indirizzo nella
verifica email gratuita per vedere un indirizzo approvato dalla
regola risultare non recapitabile, poi collega lo stesso esito alla tua ValidationRule
con gli esempi pronti da copiare e incollare nel riferimento API.



