Como validar email em JavaScript: do regex simples à análise completa por baixo dos panos
\n\nTodo desenvolvedor já se deparou pelo menos uma vez com a pergunta: «How can I validate an email address in JavaScript?». Esta pergunta no Stack Overflow acumulou milhares de visualizações e centenas de respostas, porque o tema é um verdadeiro emaranhado de nuances. Hoje não vamos apenas fornecer um código pronto, mas vamos olhar por baixo dos panos: analisar por que uma verificação simples pode deixar passar a@b ou bloquear "test@[IPv6:2001:db8::1]". Vamos nessa!
Por que «apenas regex» é uma má ideia?
\n\nA solução mais popular na internet é copiar uma expressão regular. Mas sejamos honestos: endereços de email são um caos. A especificação RFC 5321 e RFC 5322 permite o uso de caracteres como +, -, ., % e até comentários entre parênteses. Além disso, existem domínios como museum ou @[192.168.1.1]. Tente colocar tudo isso em uma única linha de regex — e você ou deixará passar um endereço válido ou bloqueará um usuário real.
Aqui está um exemplo que aparece com frequência no Stack Overflow:
\n\nconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nEste código funciona para 90% dos casos, mas:
\n- \n
- Deixa passar
test@localhost(válido para rede local) \n - Bloqueia
"test@[192.168.1.1]"(válido segundo RFC) \n - Não verifica o comprimento do domínio ou a presença de pontos \n
Moral da história: não tente escrever um regex perfeito. É melhor usar uma combinação de verificação simples + validação no servidor.
\n\nAnatomia de um endereço de email: o que saber antes de escrever o código
\n\nAntes de escrever um validador, vamos analisar a estrutura de um email de acordo com a especificação:
\n\n- \n
- Parte local (antes do @): pode conter letras, números, pontos, sinais de mais, hífens, mas não pode começar ou terminar com ponto. Aspas são permitidas para caracteres especiais. \n
- Domínio (após o @): consiste em rótulos separados por pontos. Cada rótulo tem de 1 a 63 caracteres. O domínio pode ser um endereço IP entre colchetes. \n
- Comprimento total: não mais que 254 caracteres. \n
Sabendo disso, podemos escrever uma verificação mais significativa.
\n\nPasso 1: Validação simples, mas funcional (para 99% dos casos)
\n\nVamos começar com o código usado em projetos reais (por exemplo, em Angular ou React). Não é perfeito, mas é suficiente para a maioria dos formulários:
\n\nfunction isEmailSimple(email) {\n // Remove espaços\n const trimmed = email.trim();\n \n // Verifica se é string vazia\n if (!trimmed) return false;\n \n // Estrutura básica: algo @ algo . algo\n const atIndex = trimmed.lastIndexOf('@');\n if (atIndex < 1 || atIndex === trimmed.length - 1) return false;\n \n const localPart = trimmed.slice(0, atIndex);\n const domain = trimmed.slice(atIndex + 1);\n \n // Domínio deve conter pelo menos um ponto\n const dotIndex = domain.lastIndexOf('.');\n if (dotIndex < 1 || dotIndex === domain.length - 1) return false;\n \n // Verificação de comprimento\n if (trimmed.length > 254) return false;\n if (localPart.length > 64) return false;\n \n return true;\n}\n\n// Exemplos:\nconsole.log(isEmailSimple('user@example.com')); // true\nconsole.log(isEmailSimple('a@b.c')); // true (formalmente válido)\nconsole.log(isEmailSimple('user@localhost')); // false (sem ponto)\nconsole.log(isEmailSimple('@example.com')); // false\n\n\nEste código já é melhor do que um regex cego. Ele verifica a estrutura, o comprimento e a presença de @ com ponto. Mas ele deixa passar user@[192.168.1.1] — para a maioria dos formulários web, isso não é crítico.
Passo 2: Validação avançada considerando RFC (quase como no navegador)
\n\nNavegadores modernos usam validação embutida através do atributo type="e