Skip to content
Comece com 100 créditos de verificação grátis
Qualisend
Todos os artigos
Engenharia / 12 de junho de 2026

Validar um endereço de e-mail no Laravel, da regra à caixa de entrada

8 min de leitura

Qualisend team
Validar um endereço de e-mail no Laravel, da regra à caixa de entrada

Validar um endereço de e-mail no Laravel dá vontade de tratar como uma linha só — adicionar email a um array de validação e seguir em frente. Essa regra é um bom começo, mas responde apenas à primeira das três perguntas que a validação de verdade faz. O endereço tem o formato correto? O domínio dele consegue receber e-mail? A caixa de entrada realmente existe? O Laravel é peculiar porque sua regra email nativa consegue responder às duas primeiras em uma única linha; a terceira é um problema de rede que vale a pena delegar. Este guia constrói cada camada sobre o próprio validador do Laravel e mostra exatamente onde o framework para. Ele amplia o guia de validação de e-mail em PHP: o Laravel envolve os mesmos blocos de construção do PHP — e filter_var está a uma palavra-chave de distância — em uma API muito mais agradável.

A resposta curta#

Use a regra email:rfc,dns do Laravel para a sintaxe e a consulta MX em uma única passagem e, depois, uma API de verificação para a checagem SMTP da caixa de entrada — o mais barato primeiro, encerrando cedo com bail assim que uma camada for decisiva. Não tente abrir uma sessão SMTP a partir da sua aplicação para sondar caixas de entrada por conta própria: a porta 25 de saída é bloqueada na maioria dos hosts, e a resposta depende da reputação do IP de envio e do greylisting que você não vai querer reimplementar. Cada camada elimina endereços de forma mais barata que a anterior; só a última consegue aprovar um endereço.

Camadas 1 e 2: sintaxe e DNS em uma só regra#

A regra email é sustentada pelo pacote egulias/email-validator, e ela aceita estilos que decidem o quão rígida ela é. Por padrão, aplica o estilo rfc (gramática das RFC 5321/5322). O estilo que importa para a validação é o dns, que adiciona uma consulta ao vivo e confirma que o domínio resolve uma rota de e-mail — um registro MX, com um registro A como alternativa. Peça os dois e o Laravel faz a sintaxe e a checagem de domínio em uma única regra:

public function store(Request $request)
{
    $validated = $request->validate([
        'email' => ['required', 'email:rfc,dns'],
    ]);

    // $validated['email'] is well-formed AND its domain can receive mail.
}

Os outros estilos vale a pena conhecer. email:filter executa o filter_var($email, FILTER_VALIDATE_EMAIL) do PHP — exatamente a checagem do guia de PHP — e filter_unicode permite algumas partes locais em Unicode. strict rejeita os avisos de ponto final e pontos consecutivos que o parser da RFC tolera. E spoof protege contra caracteres homógrafos enganosos, então, para um formulário de cadastro público, email:rfc,dns,spoof é um padrão sensato. Em um form request fica assim:

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreSubscriberRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'email' => ['required', 'email:rfc,dns,spoof'],
        ];
    }
}

Por que email:rfc,dns ainda não é sinal verde#

Passar em email:rfc,dns significa que a string está bem formada e que o domínio consegue receber e-mail. Não diz nada sobre a existência daquela caixa de entrada específica. noreply-9f2x@gmail.com passa. definitely-fake@gmail.com também. Ambos são inentregáveis, porque o registro MX é um fato sobre o domínio e a caixa de entrada é um fato que você só descobre perguntando ao servidor de e-mail. Essa é a mesma parede que faz a validação de e-mail por regex falhar: nenhuma dose de correspondência de padrões, e nenhuma consulta DNS, atravessa de "o domínio aceita e-mail" para "este endereço aceita".

Se quiser ver a diferença você mesmo, cole um endereço sintaticamente perfeito no verificador de e-mail gratuito e observe uma string aprovada pela regra voltar como undeliverable.

Camada 3: a caixa de entrada realmente existe?#

Confirmar uma caixa de entrada específica significa a conversa de entrega SMTP: conectar ao host de e-mail, emitir RCPT TO, ler a resposta e desconectar antes de enviar qualquer coisa. Em princípio, você poderia programar isso em PHP, mas não deveria executá-lo a partir do seu servidor de aplicação — a maioria dos provedores de nuvem bloqueia a porta 25 de saída, a resposta depende da reputação do IP de onde você conecta, e os servidores de recebimento fazem greylisting e limitam a taxa de remetentes desconhecidos. E tem mais: como funciona a verificação de e-mail percorre o pipeline completo, incluindo domínios catch-all que aceitam todo endereço e derrotam uma sondagem ingênua. Esta é a camada que vale a pena delegar.

Chamando a Qualisend a partir de uma regra de validação personalizada#

O Laravel deixa a delegação limpa: envolva a chamada de API em um objeto de regra e coloque-o no mesmo array de regras. Gere um com o Artisan:

php artisan make:rule DeliverableEmail

Mantenha a chave fora do seu código configurando-a através de config/services.php, que a lê do seu .env:

// config/services.php
'qualisend' => [
    'key' => env('QUALISEND_API_KEY'),
],

Então a regra chama o endpoint de verificação com a facade Http, lê o envelope result e falha apenas quando o veredito é 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() define o cabeçalho de autenticação bearer, ->post() envia o corpo JSON, e $response->json('result') extrai o objeto result aninhado com acesso por ponto. Um timeout ou erro de conexão lança uma ConnectionException em vez de devolver uma resposta, então a regra também a captura e deixa o cadastro passar. A referência da API traz o formato completo da requisição, e a primeira resposta é lida de volta assim:

{
  "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 é um dentre deliverable, risky, undeliverable ou unknown. A regra acima falha de forma dura apenas em undeliverable e deixa risky e unknown passarem, para que você decida mais adiante o que fazer com eles — condicionar pelo score, ou ramificar em uma entrada de sub_flags como disposable — em vez de transformar um endereço limítrofe em um erro de formulário. Trate o JSON acima como o formato, não como o contrato; a lista completa de campos vive na documentação para desenvolvedores.

Esse primeiro status é o veredito instantâneo. Quando result.smtp vem como "pending", como acima, a sondagem da caixa de entrada ainda está rodando, e o veredito final chega em GET https://app.qualisend.com/api/v1/jobs/{job_id} quando ela termina. Não segure o formulário esperando por ele nem chame /verify de novo: guarde o job_id, consulte-o a partir de um job em fila (fora do caminho da requisição) e trate ali um resultado undeliverable. Quando smtp vem como "cached" ou "skipped", o result já é final.

Juntando as camadas para validar um endereço de e-mail no Laravel#

Componha as três em um único form request, o mais barato primeiro, e deixe o bail parar na primeira falha para que a regra de API só rode em endereços que já passaram pela sintaxe e pela checagem 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.',
        ];
    }
}

bail é o truque todo. Um endereço malformado ou um domínio inativo falha localmente e nunca gasta um crédito de API; só os endereços que valem a ida e volta pela rede chegam à camada SMTP. Faça o type-hint do request no seu controller e o Laravel roda o pipeline antes mesmo de o corpo do seu método executar:

public function store(StoreSubscriberRequest $request)
{
    // Every layer has passed — safe to persist.
    $subscriber = Subscriber::create($request->validated());

    return redirect()->route('subscribers.index');
}

É a estratificação, não o framework, que torna a validação confiável — o mesmo formato da versão em PHP, com o Laravel colapsando as duas primeiras camadas em uma só regra. Rode o pipeline síncrono rápido no cadastro e reserve a passagem mais lenta, confirmada por SMTP, para o trabalho de bastidores: o guia de cadastro serverless mostra o padrão em tempo real, e como limpar uma lista de e-mails cobre o lado do processamento em lote.

Perguntas frequentes

01A regra email do Laravel verifica se o domínio existe?

Só se você pedir. A regra email simples valida a sintaxe com o pacote egulias/email-validator (o estilo rfc). Adicione o estilo dns - email:rfc,dns - e o Laravel também confirma que o domínio resolve uma rota de e-mail, então um domínio inventado ou inativo falha na mesma passagem. Nenhum dos estilos contata a caixa de entrada, então uma aprovação ainda significa "com cara de entregável", não "entregável".

02Qual é a diferença entre email:rfc, email:filter e email:dns?

rfc valida contra as RFC 5321/5322 via egulias e é o padrão do Laravel. filter executa o filter_var($email, FILTER_VALIDATE_EMAIL) do PHP - exatamente a checagem do guia de PHP - enquanto filter_unicode permite algum Unicode. dns adiciona uma consulta MX ao vivo, e spoof rejeita caracteres homógrafos enganosos. Você os combina com vírgulas, então email:rfc,dns é o portão prático de sintaxe mais domínio.

03Como verifico se uma caixa de entrada existe no Laravel?

Não com uma regra nativa - a confirmação da caixa de entrada exige uma conversa SMTP que você não deveria executar a partir do seu servidor de aplicação, porque a porta 25 é amplamente bloqueada e o resultado depende da reputação do seu IP de envio. Envolva uma API de verificação em um objeto ValidationRule personalizado, chame-a com a facade Http, leia o envelope result e falhe em undeliverable. Coloque-a depois de email:rfc,dns com bail para que ela só rode em endereços que já passaram pelas camadas locais. Se result.smtp vier como pending, a sondagem da caixa de entrada ainda está rodando: leia o veredito final em GET /api/v1/jobs/{job_id} a partir de um job em fila, não dentro do validador.

04A regra dns vai deixar o envio dos meus formulários mais lento?

Pode deixar. O estilo dns realiza uma consulta DNS ao vivo a cada validação, então um resolvedor lento ou inacessível trava a requisição. Tudo bem para um único formulário de cadastro, mas mantenha-o fora de importações em massa, e não o empilhe com uma chamada de API síncrona a menos que você tenha definido um timeout no cliente Http - como a regra DeliverableEmail acima faz com ->timeout(10).


Pronto para adicionar a camada da caixa de entrada? Jogue um endereço no verificador de e-mail gratuito para ver um endereço aprovado pela regra voltar como inentregável, e depois conecte o mesmo veredito à sua ValidationRule com os exemplos de copiar e colar da referência da API.

Sua reputação, protegida.

Limpe sua primeira lista em minutos. 100 créditos grátis, sem cartão.

Começar