Quatro perguntas que compartilham uma palavra
“Este é um endereço de e-mail válido?” não é uma pergunta só. São quatro, ficam mais difíceis em ordem, e a última é a única que alguém realmente queria ver respondida — por isso tanto código de validação é elaborado sobre a primeira e silencioso sobre o resto.
Aqui estão elas, na ordem em que um formulário de cadastro as encontra.
- Tem o formato de um endereço?
- Uma verificação de sintaxe. Roda no navegador, não custa nada, e pega a vírgula digitada por engano e o
@ausente. É a única camada que consegue rejeitar algo honestamente por conta própria — e mesmo assim deveria rejeitar bem menos do que a maioria dos padrões rejeita. - Aquele domínio consegue receber e-mail?
- Uma verificação de DNS. Uma consulta diz se alguma coisa, em algum lugar, está disposta a aceitar e-mail para a parte depois do
@. Ela pega um nome de domínio com uma letra faltando e um domínio que expirou no ano passado, e não consegue te dizer absolutamente nada sobre a caixa de entrada. - Aquela caixa de entrada existe?
- Uma verificação SMTP — e a que este guia vai passar mais tempo dizendo para você não confiar nela. Dá para perguntar. A resposta é frequentemente um sim educado de um servidor que aceita qualquer nome, ou uma falha temporária proposital, ou uma aceitação seguida de um bounce minutos depois.
- É o endereço dela?
- Nada do lado técnico consegue responder isso. Um endereço pode ser perfeito, entregável e de outra pessoa — digitado errado por um caractere, ou digitado de propósito para passar por você. Só uma mensagem que chega e é usada resolve essa questão.
As três primeiras são baratas e provam pouco. A quarta é a única que merece o nome, e é a que custa uma mensagem. Tudo abaixo é sobre gastar bem as três baratas para que a cara não seja desperdiçada.
Camada um: o padrão, e as quatro coisas que ele não pode saber
Não existe uma expressão regular oficial para um endereço de e-mail, e não pode existir. A RFC 5322 define uma gramática, não um padrão, e essa gramática permite comentários entre parênteses, espaços em branco quebrados e strings entre aspas contendo quase qualquer caractere — nada disso um formulário de cadastro de verdade deveria aceitar, e tudo isso um padrão fiel é obrigado a aceitar.
O que existe é uma definição deliberadamente mais restrita que os navegadores já implementam: a que a especificação HTML dá para um campo <input type="email">. É um meio-termo escolhido de propósito, não uma transcrição do padrão, é o que já se exige do seu formulário antes de qualquer linha do seu código rodar, e é curto o bastante para ler de uma vez:
/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/Use essa, ou use a que a sua plataforma já traz pronta. As quatro abaixo são a mesma camada, e escolher uma é uma decisão menor do que o que você faz depois:
| Onde você está | A verificação que você já tem | O que ela faz que talvez você não espere |
|---|---|---|
| No navegador, sem nenhum código | <input type="email" required> | Aplica o padrão acima antes de o seu JavaScript sequer ver o campo, e mostra a mensagem no idioma do próprio visitante. |
| Em PHP, sem instalar nada | filter_var($a, FILTER_VALIDATE_EMAIL) | Mais rigorosa do que a do HTML: insiste em um ponto no domínio, então recusa um endereço que só funcionaria dentro de uma única máquina. |
| Em Python, com um pacote pequeno | email_validator.validate_email(a) | Faz a sintaxe e, se você deixar, a consulta de domínio da camada dois — as duas camadas baratas atrás de uma única chamada. |
| Em Java ou Kotlin, por meio do Bean Validation | @Email | Muito permissiva de propósito. É uma anotação feita para pegar o obviamente errado, e aceita sem problema nenhum um domínio que nunca existiu. |
Qualquer uma que você use, o que importa é sobre o que ela fica em silêncio. Um padrão que retorna verdadeiro te contou uma coisa e quatro não-coisas.
- Não que o domínio existe
- Um endereço em um domínio que ninguém jamais registrou passa em todos os padrões desta seção. Nada foi consultado e nada foi contatado; nenhuma expressão regular jamais fez uma requisição de rede.
- Não que a caixa de entrada existe
- Mesmo em um domínio real, o padrão não tem opinião nenhuma sobre a parte antes do
@. Essa parte pertence só ao servidor de recebimento, e é exatamente a coisa que o DNS nunca vai te contar. - Não que é entregável
- Um domínio pode ter um registro perfeito e um servidor de e-mail que está desligado há um mês. Sintaxe é uma propriedade de uma string; capacidade de entrega é uma propriedade do mundo no momento em que você aperta enviar.
- Não que pertence a quem está digitando
- O endereço ruim mais comum em qualquer banco de dados é um endereço real, entregável, que pertence a alguém que nunca se cadastrou — porque uma letra foi digitada errado, ou porque o formulário foi preenchido com uma mentira que parecia plausível.
O que é legal, e o que é rejeitado por engano
A maioria dos bugs de validação não são endereços ruins que entraram. São pessoas que não conseguiram se cadastrar, e elas nunca aparecem em nenhum log que alguém lê — o formulário disse não, e elas foram para outro lugar. Estes seis são os que fazem isso com mais frequência.
| O que formulários rejeitam | É legal? | O que realmente é |
|---|---|---|
Um sinal de mais, como em name+shop@example.com | Legal, e amplamente usado | Endereçamento com sinal de mais: uma caixa de entrada, com um rótulo que o dono escolheu para conseguir ver quem vazou o endereço. Recusá-lo diz a um visitante cuidadoso exatamente que tipo de formulário é esse. |
Um apóstrofo, como em o'brien@example.com | Legal, e o sobrenome de alguém | Uma de uma dúzia de marcas de pontuação que a parte local permite. Quando um formulário o recusa, o motivo quase nunca é o endereço — é um bug de escape em algum lugar mais adiante que ninguém queria encontrar. |
Uma terminação que ninguém nunca ouviu falar, como .dev ou .photography | Legal, e existem bem mais de mil | Um padrão com uma lista de terminações escrita nele já estava desatualizado no dia em que foi escrito, e piora a cada ano sem que ninguém perceba. |
| Um domínio sem nenhum ponto nele | Legal, e inútil para você | Um endereço como root@localhost é válido dentro de uma máquina e sem sentido nenhum em um formulário público. Este é o único caso em que os verificadores rigorosos da plataforma têm razão em recusar. |
Letras não latinas, como em 用户@例子.广告 | Legal, com uma ressalva | Endereços internacionalizados existem e estão se espalhando devagar. Se a sua própria infraestrutura de e-mail consegue enviar para um deles é uma pergunta separada — mas um campo que se recusa a aceitar os caracteres já respondeu isso por todo mundo, permanentemente. |
Letras maiúsculas antes do @ | Legal, e não é você quem decide | O padrão deixa a caixa da parte local a critério do servidor de recebimento. Quase todo servidor ignora isso; os que não ignoram são os que você nunca vai saber que existem. |
E três números, que vale a pena escrever no seu código porque eles não mudam:
- 64 caracteres
- O máximo que a parte antes do
@pode ter. Qualquer coisa mais longa não é um endereço longo, não é um endereço. - 255 caracteres
- O máximo que o domínio pode ter, pontos incluídos. Nada legítimo jamais chegou perto disso, e o limite existe principalmente para que você tenha um.
- 254 caracteres
- O máximo que o endereço inteiro pode ter quando um servidor o transporta — o que é menos do que os dois números acima somados. Este é o que você deve usar na coluna do banco de dados e no
maxlengthdo campo.
Camada dois: uma consulta, e o que ela resolve
A parte depois do @ é um domínio, e um domínio ou tem para onde colocar e-mail, ou não tem. Uma consulta DNS responde isso em poucos milissegundos, e é a verificação de maior valor deste guia inteiro — porque o erro que ela pega, um nome de domínio digitado um pouco errado, é de longe a falha real mais comum que existe.
$ dig +short MX example.comUma resposta significa que um host foi nomeado. Nenhuma resposta não significa nenhum e-mail: um domínio sem registro MX mas com um registro A ainda recebe, porque remetentes recorrem a ele. Existem quatro resultados possíveis, e só dois deles são falhas.
| O que a consulta retorna | Consegue receber? | O que o formulário deveria fazer |
|---|---|---|
| Um ou mais registros MX | Sim | Aceite. Esta é a esmagadora maioria dos endereços, e não vale a pena fazer mais nada antes de enviar. |
Sem MX, mas com um registro A ou AAAA | Sim, como alternativa | Aceite. Isso é incomum e totalmente legal, e remetentes vão entregar ali. Recusá-lo transforma um endereço que funciona em um cliente perdido. |
Um único registro cujo valor inteiro é 0 . | Não, e de propósito | Recuse, e diga o motivo. Isso é um MX nulo: o dono do domínio publicou, da única forma que existe para publicar isso, que nada ali recebe e-mail. |
| O domínio não resolve de jeito nenhum | Não | Recuse, e ofereça a opção mais parecida. Um NXDOMAIN em um nome que um humano digitou há trinta segundos é quase sempre uma letra errada. |
Onde essa verificação dá errado nunca é a consulta em si. É onde a consulta foi colocada — no caminho crítico, a cada tecla digitada, com uma falha que bloqueia o envio. Seis regras mantêm ela útil:
- Rode quando o campo estiver terminado, não enquanto ele está sendo digitado. Uma consulta quando o foco sai do campo, ou uma no envio. Uma consulta a cada tecla é uma consulta a cada tecla.
- Converta o domínio para minúsculas primeiro. O DNS não liga, mas o seu cache liga: duas grafias do mesmo domínio são uma consulta, não duas.
- Pergunte por MX, e recorra a
Ase precisar. Duas consultas, das quais só a segunda é condicional. Uma biblioteca que confere só o MX vai rejeitar domínios que funcionam. - Guarde a resposta em cache por alguns minutos. Um punhado de domínios responde pela maioria dos cadastros em qualquer lugar, então a maioria das consultas vira consulta nenhuma.
- Falhe de forma permissiva. Se o resolvedor expirar, aceite o endereço. Um minuto ruim no seu provedor de DNS nunca deve virar um formulário que afasta todo mundo.
- Sugira uma correção; nunca aplique uma. Quando o domínio está a uma letra de um domínio comum, ofereça a correção como algo para clicar. Reescrever em silêncio o que alguém digitou é assim que um link de confirmação vai parar na mão de um estranho.
A consulta tem um custo que vale a pena conhecer: é o primeiro momento em que o seu formulário fala com o mundo exterior sobre algo que um visitante digitou. Onde isso importa, a alternativa é pular essa camada por completo e deixar a própria mensagem ser a verificação inteira.
Camada três: perguntar ao servidor, e por que a resposta não é uma resposta
Existe uma forma de perguntar a um servidor de e-mail se ele vai aceitar um endereço específico sem enviar nada para ele. Abra a conversa, nomeie um remetente, nomeie o destinatário, leia a resposta a esse único comando, e desligue antes da mensagem:
220 mx1.example.com ESMTP ready
EHLO checker.example.net
250 mx1.example.com
MAIL FROM:<probe@example.net>
250 2.1.0 Ok
RCPT TO:<someone@example.com>
250 2.1.5 Ok
QUIT
221 2.0.0 ByeO 250 depois de RCPT TO é o que todo serviço de verificação de endereço no mundo está, no fundo, vendendo. Vale a pena ser preciso sobre o quão pouco isso vale.
- Um domínio catch-all diz sim para tudo
- Um domínio configurado para aceitar qualquer nome — que é o que este serviço faz, e o que uma quantidade enorme de domínios de empresas faz — responde
250para um endereço que ninguém jamais usou. A resposta é verdadeira, e não é informação. - Um servidor cuidadoso diz
450de propósito - Greylisting recusa a primeira tentativa de um remetente desconhecido e pede para ele voltar daqui a pouco. Um remetente de verdade volta; uma sondagem nunca volta. Essa falha temporária é uma não-resposta proposital, e interpretá-la como “essa caixa não existe” é exatamente o erro que ela foi projetada para provocar.
- Alguns servidores aceitam primeiro e recusam depois
- Grandes provedores rotineiramente pegam a mensagem durante a conversa e decidem sobre ela depois, o que transforma uma recusa em um bounce que chega minutos depois de a sua sondagem ter voltado limpa.
- Alguns servidores dizem não a todo mundo que não reconhecem
- Um servidor que decidiu que o seu endereço é um estranho pode recusar o destinatário por motivos que não têm nada a ver com o destinatário. O que você mediu foi a sua própria reputação, não a caixa de entrada dele.
- E ela gasta a reputação que você estava protegendo
- Uma conexão que nomeia destinatários e nunca envia nada tem exatamente o formato de uma coleta de diretório, porque é uma. Fazer isso em volume a partir do seu próprio endereço é o caminho mais rápido para uma lista de bloqueio — e um remetente bloqueado é aquele cujas mensagens de verdade param de chegar.
Existe um caso bem específico em que a sondagem é genuinamente útil: um único endereço, verificado manualmente, em um domínio que você administra ou tem permissão para mexer. Como uma etapa dentro de um formulário de cadastro, ela é lenta, frequentemente errada, e ocasionalmente prejudicial à própria coisa que foi adicionada para proteger.
Endereços de função, domínios descartáveis, e a lista que você está prestes a comprar
Entre a consulta de domínio e a mensagem de verdade fica uma família de verificações que não têm nada a ver com validade. Elas são sobre se você quer este endereço, o que é uma decisão de negócio vestida de decisão técnica — e vale a pena separá-la das três camadas ao redor só por esse motivo.
- Endereços de função
- Nomes como
info@,support@eadmin@. Eles são reais, e geralmente são uma caixa de entrada compartilhada em vez de uma pessoa, o que os torna um mau lugar para qualquer coisa com senha por trás. Vale a pena sinalizar. Raramente vale a pena recusar. - Domínios descartáveis
- Endereços como os que este site distribui, em domínios que existem para serem descartados. Conferir contra uma lista pública deles é razoável, desde que você admita que toda lista assim é incompleta e um pouco desatualizada no dia em que você a baixa.
- Endereços de provedor gratuito
- Alguns formulários corporativos recusam qualquer coisa que não seja um domínio de empresa. Isso é uma política, às vezes é a certa, e merece ser escrita como uma política — uma frase que o visitante consegue ler — em vez de escondida dentro de uma coisa chamada validação.
- Domínios quase certos
- O nome de um provedor conhecido com uma letra errada. Este é diferente dos outros três: não é uma política, pega um erro genuíno, e a pessoa sempre fica contente. É o único item aqui que vale a pena construir.
As três primeiras compartilham uma característica que torna difícil julgá-las: você consegue medir o que elas deixam passar e não consegue medir o que elas custam.
Nós temos um interesse óbvio aqui, então aqui está a versão honesta. Se o que está por trás do seu formulário é um teste grátis com algo caro atrelado, recusar domínios descartáveis vai economizar seu dinheiro e você deveria fazer isso. Se é uma newsletter, um download, ou uma conta que alguém paga, você está principalmente penalizando os cautelosos — e os cautelosos são os que leem o que você envia.
Camada quatro: a mensagem que é a verificação
Tudo acima reduz o campo. Nada disso estabelece o único fato que importa — que este endereço alcança a pessoa na sua frente — e exatamente uma coisa faz isso: enviar algo para lá, e observar se é usado.
Este é o loop que quase todo cadastro já tem e que metade deles trata como uma formalidade:
- Aceite o endereço com uma verificação permissiva. O padrão do navegador, e nada mais entre o visitante e o botão.
- Crie a conta não verificada. Nem uma retenção no formulário, nem uma tela de “pendente”: a pessoa já está dentro, e o que ela ainda não pode fazer é o punhado de coisas para as quais o endereço é realmente necessário.
- Envie uma mensagem carregando um link ou código de uso único. Uma só, com uma expiração, vinculada àquela conta e àquele endereço, e a nenhum outro.
- Deixe o link ser a prova. Um clique, ou um código digitado de volta, é a verificação inteira. Nada mais neste guia produz uma resposta nem perto de tão sólida.
- Dê a elas um caminho de volta. Um “reenviar” visível, e uma forma de mudar o endereço sem perder a conta — porque o motivo mais comum de um link nunca ser clicado é um erro de digitação que a pessoa agora finalmente consegue ver.
- Expire as que ninguém confirmou. Uma limpeza silenciosa depois de um período fixo impede que os erros de digitação e os endereços descartáveis se acumulem em uma lista em que ninguém confia.
O que cria um problema prático, e é o motivo pelo qual este site existe. Esse loop agora é o caminho mais importante do produto, e testá-lo significa receber e-mail de verdade em um endereço que você controla — repetidas vezes, dentro de um pipeline, sem um humano abrindo uma caixa de entrada.
Um endereço em um dos domínios públicos não precisa de cadastro nem de chave, e o que quer que chegue nele é legível por HTTP um segundo depois:
$ curl -sG https://grabmail.io/api/v1/mailbox \
--data-urlencode "address=signup-42@grabmail.io"A partir daí, um fluxo de verificação inteiro pode ser conduzido de ponta a ponta por uma suíte de testes, ou um domínio que você possui pode ser apontado para cá para que cada execução ganhe um endereço que nunca existiu antes. As mensagens são mantidas por 5 dias e depois apagadas, o que é o tempo de vida certo para um fixture de teste e o errado para uma caixa de entrada.
O que realmente colocar no formulário
Resumido, na ordem em que o código roda:
- Corte os espaços, e só isso. Espaço em branco em qualquer ponta é um resíduo de colar e nunca é intencional. Mais nada na string é seu para mudar.
- Confira com um padrão permissivo. O do navegador, ou o da sua plataforma. Recuse o
@ausente e a vírgula digitada por engano, e não recuse mais nada. - Limite o tamanho em 254. Um número, na coluna e no campo, e uma classe inteira de entrada com a qual você pode parar de se preocupar.
- Consulte o domínio, fora do caminho crítico, falhando de forma permissiva. MX e depois
A, em cache, e nunca um motivo para bloquear um envio que de outra forma teria funcionado. - Ofereça uma correção; não faça uma. Estar a uma letra de um domínio comum é uma pergunta a fazer, não uma constatação para agir sozinho.
- Envie a mensagem. Essa é a validação. Tudo acima disso foi triagem.
- Diga o que está errado, em palavras. Que é a parte que decide se alguém termina:
| O que aconteceu | O que formulários costumam dizer | O que dizer em vez disso |
|---|---|---|
A string não tem @ nela | “Insira um endereço de e-mail válido” | “Um endereço de e-mail precisa de um @ — você quis dizer name@example.com?” |
| O domínio não resolve | “Insira um endereço de e-mail válido” | “Não conseguimos encontrar esse domínio. A grafia está certa?” |
| O domínio está a uma letra de um domínio comum | Absolutamente nada; o formulário é enviado | “Você quis dizer … ?”, com o endereço corrigido como um botão para clicar |
| Está em uma lista de bloqueio que você escolheu usar | “Insira um endereço de e-mail válido” | “Para isso precisamos de um endereço que você ainda vai conseguir ler no mês que vem.” |
| A mensagem foi enviada e nunca foi confirmada | Absolutamente nada; a conta fica ali parada | “Enviamos um link para esse endereço. Não chegou? Reenvie, ou mude o endereço.” |
Repare quantas linhas dizem a mesma coisa errada. “Insira um endereço de e-mail válido” é o padrão em todo lugar porque é verdadeiro em todos os casos e útil em nenhum deles: em três das cinco linhas o endereço era válido, e a pessoa que o digitou não tem como descobrir em qual linha ela está.
A versão resumida
- Corte os espaços da string. Não mude mais nada nela.
- Confira com um padrão permissivo — o do navegador ou o da sua plataforma — e pare por aí. Não escreva o seu próprio.
- Rejeite qualquer coisa acima de 254 caracteres, e armazene uma coluna desse tamanho.
- Consulte o MX do domínio, recorra a
Ase precisar, guarde em cache, faça isso fora do caminho crítico, e aceite o endereço quando a consulta falhar. - Recuse um domínio que não resolve e um domínio que publica um MX nulo. Aceite tudo o mais que o DNS te der.
- Ofereça uma sugestão de grafia quando o domínio estiver quase certo. Nunca a aplique sozinho.
- Decida separadamente, e por escrito, se você vai bloquear endereços descartáveis ou de função — e por quê.
- Envie uma mensagem com um link de uso único, trate o clique como a verificação, e facilite reenviar e corrigir o endereço.
- Teste esse loop contra uma caixa de entrada de verdade, incluindo os caminhos em que ele falha, e apague contas não confirmadas em um cronograma.
Nove linhas, e as duas últimas são as únicas que estabelecem alguma coisa. As outras sete existem para que a mensagem no final delas valha a pena ser enviada.
Perguntas
Existe uma expressão regular oficial para endereços de e-mail?
Não, e não pode existir. A RFC 5322 dá uma gramática, não um padrão, e um padrão fiel a ela aceitaria espaços entre aspas e comentários entre parênteses que nenhum provedor emite. Use a que a especificação HTML define para um campo de e-mail, ou qualquer verificador que a sua plataforma já traga pronto, e gaste o esforço que você economizou na mensagem de confirmação.
Dá para conferir se um endereço de e-mail existe sem enviar nada?
Dá para perguntar; não dá para saber. Um domínio catch-all aceita qualquer nome, greylisting responde com uma falha temporária proposital, grandes provedores aceitam durante a conversa e dão bounce depois, e um servidor que não te reconhece pode recusar por motivos que são sobre você, não sobre o destinatário. Sondar em massa também coloca o seu endereço de envio em listas de bloqueio.
name+tag@example.com é um endereço válido?
Sim. O sinal de mais é um caractere comum e permitido na parte local, e na maioria dos grandes provedores ele também roteia para a caixa de entrada antes dele, que é o que torna o endereçamento com sinal de mais útil. Um formulário que o recusa está recusando endereços legais e revelando algo sobre si mesmo ao fazer isso.
Endereços de e-mail diferenciam maiúsculas de minúsculas?
O domínio nunca diferencia. A parte antes do @, pelo padrão, fica a critério do servidor de recebimento — e na prática todo grande provedor ignora isso. Guarde uma cópia em minúsculas para detectar duplicatas, e envie para a string exatamente como foi digitada.
Qual é o tamanho máximo de um endereço de e-mail?
64 caracteres antes do @, 255 para o domínio, e 254 para o endereço inteiro conforme um servidor o transporta. O último desses três é o número para usar: coloque na coluna do banco de dados e no campo, e uma classe inteira de entrada deixa de ser problema seu.
Devo bloquear endereços de e-mail descartáveis?
Se há algo caro por trás de um teste grátis, sim — e aceite que qualquer lista que você use é incompleta. Para uma newsletter, um download ou uma conta paga, as pessoas que você afasta são principalmente as cautelosas, e você nunca vai vê-las em um log. A troca completa vale a pena ler antes de instalar um pacote que toma a decisão por você.
Como testar um fluxo de verificação de cadastro sem uma caixa de entrada de verdade?
Envie para um endereço em um domínio descartável público e leia de volta pela API — sem cadastro, sem chave, e um endereço novo a cada execução. Para uma suíte que precisa de centenas, aponte um domínio que você possui para uma caixa catch-all e invente um endereço por teste. O passo a passo completo está em testar um fluxo de verificação de e-mail de ponta a ponta.


