Por que a validação de e-mail é mais difícil do que você pensa

O formato de endereço de e-mail é definido pela RFC 5322 e seus predecessores. A especificação completa permite alguns endereços de aparência surpreendentemente estranha que são tecnicamente válidos:

  • "spaces in quotes"@example.com — strings entre aspas na parte local
  • user+tag@example.com — endereçamento plus (amplamente usado para filtros no Gmail)
  • user@subdomain.example.co.uk — múltiplos subdomínios e ccTLDs
  • user@[192.168.1.1] — literais de endereço IP como domínio
  • very.unusual."@".unusual.com@example.com — tecnicamente válido mas quase nunca visto
  • user@xn--nxasmq6b.com — nomes de domínio internacionalizados (Punycode)

Um regex totalmente compatível com a RFC 5322 precisaria lidar com todos esses, enquanto também rejeita endereços que não cumprem as regras básicas de formato. O resultado é um padrão de 1000 caracteres que é essencialmente impossível de manter. Na prática, o objetivo não é a conformidade total com a RFC — é detectar erros de digitação sem bloquear endereços reais.

O regex simples (suficiente para 99% dos casos)

Para a maioria das aplicações, este padrão mínimo é a escolha certa. Ele valida a estrutura essencial — algo antes de um @, um domínio e um TLD — sem falsos negativos em endereços legítimos:

/^[^\s@]+@[^\s@]+\.[^\s@]+$/

Detalhamento:

  • ^ — início da string
  • [^\s@]+ — um ou mais caracteres que não são espaço em branco nem @ (a parte local)
  • @ — arroba literal
  • [^\s@]+ — um ou mais caracteres que não são espaço em branco nem @ (o domínio)
  • \. — um ponto literal
  • [^\s@]+ — um ou mais caracteres (o TLD)
  • $ — fim da string

O que ele aceita e rejeita corretamente:

Válidos (aceitos):

✓ user@example.com
✓ first.last@company.co.uk
✓ user+tag@gmail.com
✓ 123@numbers.org

Inválidos (rejeitados):

✗ plainstring
✗ @nodomain.com
✗ user @example.com (espaço)
✗ user@

A principal fraqueza é que ele aceita user@@example.com e a@b.c (tecnicamente válido mas suspeito). Para a maioria dos formulários de cadastro e inputs de API, esse é um trade-off aceitável.

O regex completo (compatível com RFC 5322)

Quando você precisa de uma validação mais rigorosa — por exemplo, em um sistema de envio de e-mails onde endereços inválidos causam bounces e danificam a reputação do remetente — um padrão mais completo é justificado. Este é um padrão derivado da RFC 5322 amplamente citado:

/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

Este padrão é mais longo mas lida com significativamente mais casos. Detalhamento das partes principais:

  • Parte local (antes do @): Ou uma sequência de caracteres permitidos com segmentos opcionais separados por pontos [^<>()...]+(\.[^<>()...]+)*, ou uma string entre aspas ".+" para endereços como "john doe"@example.com.
  • Domínio (depois do @): Ou um literal de endereço IP entre colchetes \[[0-9]{1,3}...\], ou um hostname padrão com um TLD de pelo menos 2 caracteres ([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}.
  • TLD mínimo de 2 caracteres: Rejeita TLDs de um único caractere enquanto aceita os longos como .museum ou .technology.

Casos adicionais que este padrão lida corretamente:

✓ "quoted string"@example.com
✓ user@[192.168.1.1]
✓ user@subdomain.long-domain.co.uk

Ainda rejeitados corretamente:

✗ user@example (sem TLD)
✗ user @example.com (espaço antes do @)
✗ user@@example.com (duplo @)

Validação de e-mail em JavaScript

Aqui estão implementações práticas em JavaScript prontas para copiar e colar usando ambos os padrões:

Função de validação simples

/**
 * Valida formato de e-mail para a maioria dos casos de uso.
 * Rápido, legível, muito poucos falsos negativos.
 */
function isValidEmail(email) {
  const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return pattern.test(email.trim());
}

// Uso
isValidEmail("user@example.com");      // true
isValidEmail("not-an-email");          // false
isValidEmail("user+tag@gmail.com");    // true

Validação mais rigorosa com feedback detalhado

function validateEmail(email) {
  const trimmed = email.trim();

  if (!trimmed) {
    return { valid: false, error: "O e-mail é obrigatório" };
  }

  if (trimmed.length > 254) {
    return { valid: false, error: "Endereço de e-mail muito longo (máximo 254 caracteres)" };
  }

  if (!trimmed.includes("@")) {
    return { valid: false, error: "Falta o símbolo @" };
  }

  const [local, ...domainParts] = trimmed.split("@");
  const domain = domainParts.join("@");

  if (!local || local.length > 64) {
    return { valid: false, error: "Parte local inválida (antes do @)" };
  }

  if (!domain || !domain.includes(".")) {
    return { valid: false, error: "Domínio inválido (falta TLD)" };
  }

  const rfcPattern = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

  if (!rfcPattern.test(trimmed)) {
    return { valid: false, error: "Formato de e-mail inválido" };
  }

  return { valid: true, email: trimmed.toLowerCase() };
}

// Uso
const result = validateEmail("  User@Example.COM  ");
// { valid: true, email: "user@example.com" }

Validação de e-mail com HTML5

Antes de recorrer ao JavaScript, considere o que o navegador te oferece de graça. O elemento input type="email" tem validação embutida que é executada ao submeter o formulário:

<!-- Validação embutida básica -->
<input type="email" name="email" required>

<!-- Com padrão personalizado para validação mais rigorosa -->
<input
  type="email"
  name="email"
  required
  pattern="[^\s@]+@[^\s@]+\.[^\s@]+"
  title="Por favor, insira um endereço de e-mail válido"
>

O algoritmo embutido do navegador para type="email" segue a especificação HTML5 (um subconjunto simplificado da RFC 5322). Ele rejeita não-e-mails óbvios, exibe um tooltip de validação nativo e funciona sem JavaScript. O atributo pattern permite adicionar restrições adicionais.

Limitações a considerar: a validação embutida só é acionada ao submeter o formulário, não enquanto o usuário digita. Para feedback em tempo real, você precisa de JavaScript. Além disso, a pseudo-classe CSS :invalid permite estilizar inputs inválidos, mas é acionada mesmo em campos vazios não tocados a menos que você também use :not(:placeholder-shown):

/* Só mostrar borda vermelha depois que o usuário interagiu */
input[type="email"]:not(:placeholder-shown):invalid {
  border-color: #ef4444;
  outline-color: #ef4444;
}

input[type="email"]:not(:placeholder-shown):valid {
  border-color: #34d399;
}

Casos extremos comuns

Estes são os casos que fazem falhar a maioria das implementações de validação de e-mail:

Endereçamento plus (subaddressing)

user+tag@gmail.com é válido e amplamente usado. Gmail, Outlook e a maioria dos provedores de e-mail modernos suportam isso para filtragem. Sua regex não deve rejeitar o caractere + na parte local. Muitos padrões excessivamente restritivos falham nisso.

Subdomínios

first.last@mail.company.co.uk é um e-mail válido com pontos tanto na parte local quanto no domínio. O domínio tem três níveis. Um bom padrão deve lidar com múltiplos rótulos separados por pontos no domínio.

TLDs longos

TLDs não são mais restritos a dois ou três caracteres. .museum, .photography, .technology e centenas de outros gTLDs são válidos. Qualquer regex que imponha um comprimento máximo de TLD de 4 ou 6 caracteres produzirá falsos negativos. Imponha apenas um mínimo (2 caracteres) e nenhum máximo.

Domínios internacionais (IDN)

Nomes de domínio podem conter caracteres não-ASCII codificados como Punycode. user@münchen.de é válido — o domínio real é xn--mnchen-3ya.de na forma ASCII. A maioria dos padrões regex não consegue validar Punycode diretamente; confie em uma biblioteca dedicada de validação de e-mail se for necessário suporte a IDN.

Literais de endereço IP

user@[192.168.1.1] é tecnicamente válido segundo a RFC 5321 mas quase nunca é usado na prática. A menos que você esteja construindo uma implementação SMTP, pode ignorar este caso com segurança.

Não valide demais

Este é o conselho prático mais importante deste artigo: o propósito da validação de e-mail no lado do cliente é detectar erros de digitação, não verificar a capacidade de entrega.

Nenhum regex pode dizer se um endereço de e-mail realmente existe ou se sua caixa de entrada está aceitando mensagens. Somente entregar na caixa de entrada pode confirmar isso. Validar demais (rejeitar endereços que seu regex incorretamente marca como inválidos) perde usuários reais. Validar de menos (aceitar endereços mal formatados) te custa um bounce.

A abordagem correta é uma estratégia de duas camadas:

  1. Use um regex simples para detectar erros óbvios de formato (falta o @, falta o TLD, espaços).
  2. Envie um e-mail de confirmação ou verificação para confirmar que o endereço é real e o usuário o controla.

Um e-mail de confirmação é a única porta confiável. Todo o resto é uma heurística. Se você se encontrar debatendo se deve rejeitar user@localhost ou a@b.io, dê um passo atrás — envie o e-mail e deixe a camada SMTP lidar com isso.

Comparação de padrões regex populares para e-mail

Aqui está uma comparação prática dos padrões mais comumente usados, incluindo seus trade-offs:

Padrão Tipo Vantagens Desvantagens Cobertura
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ Simples Legível, mínimos falsos negativos, rápido Aceita a@@b.c, muito permissivo ~95%
/^[\w.+-]+@[\w-]+\.[\w.]{2,}$/ Comum Curto, lida com a maioria dos e-mails do mundo real Rejeita caracteres especiais válidos na parte local ~92%
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ Equilibrado Amplamente usado, bom equilíbrio de rigor e cobertura Rejeita alguns locais válidos com strings entre aspas ~97%
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}...)/ RFC 5322 Lida com strings entre aspas, literais IP, TLDs longos Longo, difícil de ler, ainda não 100% compatível com RFC ~99%

O padrão "equilibrado" completo

O terceiro padrão na tabela acima é a escolha mais prática para uso em produção quando você quer mais do que o padrão simples mas não a complexidade completa da RFC 5322:

/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/

Detalhamento:

  • [a-zA-Z0-9._%+-]+ — parte local: alfanuméricos mais ., _, %, +, -
  • @ — arroba obrigatório
  • [a-zA-Z0-9.-]+ — domínio: alfanuméricos, hífens, pontos (lida com subdomínios)
  • \. — ponto separador antes do TLD
  • [a-zA-Z]{2,} — TLD: pelo menos 2 letras, sem máximo (lida com TLDs longos)

Usar uma biblioteca em vez de criar a sua própria

Para aplicações onde a validade do e-mail é crítica (sistemas de e-mail transacional, fluxos de cadastro B2B SaaS), considere uma biblioteca de validação dedicada em vez de escrever regex você mesmo:

// Node.js — validator.js (a mais popular)
import validator from 'validator';
validator.isEmail('user@example.com'); // true

// Node.js — email-validator (leve)
import { validate } from 'email-validator';
validate('user@example.com'); // true

// Python — email-validator (compatível com RFC)
# pip install email-validator
from email_validator import validate_email, EmailNotValidError
try:
    info = validate_email("user@example.com")
except EmailNotValidError as e:
    print(str(e))

Teste sua regex de e-mail

A melhor forma de entender qualquer regex é executá-la contra um conjunto abrangente de entradas de teste — tanto endereços válidos que você espera aceitar quanto inválidos que precisa rejeitar. Nosso Regex Tester permite colar qualquer um dos padrões acima, construir um conjunto de testes e ver resultados de matching destacados em tempo real.

Teste sua regex de e-mail ao vivo

Cole qualquer padrão regex de e-mail e teste contra suas próprias entradas. Suporta flags, grupos de captura e matching multilinha. Roda inteiramente no seu navegador.

Abrir Regex Tester →

Ferramentas de desenvolvimento relacionadas