Como Validar E-mail em JavaScript (2026): Regex, HTML5 e Validação Real
Validar e-mail parece trivial — até você receber 30% de cadastros com 'asdf@asdf' e tentar enviar campanha. Este guia cobre as três camadas (sintaxe, DNS, SMTP), mostra regex que funciona, e explica quando cada nível de validação compensa.
Por Vitor Morais
Fundador do MochaLabz ·
Valide e-mails em massa
Cole uma lista, detecte descartáveis e exporte só os endereços válidos.
Usar validador →Validar e-mail em JavaScript é uma daquelas tarefas que parecem simples e têm três níveis de complexidade dependendo do que você chama de “válido”. Formato correto? Regex resolve. Domínio que aceita e-mail? Precisa checar DNS. Mailbox que realmente existe? Aí a conversa é com SMTP. Cada camada cobre um tipo de erro e custa mais que a anterior.
Este guia cobre os três níveis, mostra regex que funciona em 99% dos casos, compara bibliotecas populares e aponta os erros clássicos que fazem você rejeitar e-mails legítimos ou aceitar lixo.
Os três níveis de validação
| Critério | O que testa | Quando usa | Custo |
|---|---|---|---|
| Sintaxe (regex) | Formato correto do endereço | Todo formulário web | Zero |
| Validação HTML5 | Formato básico + UX do navegador | Qualquer input em HTML | Zero |
| DNS (MX record) | Domínio aceita e-mail | Cadastro com alto custo de conta | Baixo |
| SMTP (ping ao servidor) | Mailbox específico existe | Campanhas grandes, cobrança | Médio |
| API comercial | Tudo acima + reputação | E-mail é crítico para receita | Alto |
Validação com regex: o básico que resolve 99% dos casos
Um regex funcional para formulários web precisa aceitar o que é válido na prática — não o que é válido no RFC 5322. Esse regex cobre o caso real:
function isEmailValid(email) {
const regex = /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/;
return regex.test(email.trim().toLowerCase());
}
isEmailValid("joao@exemplo.com"); // true
isEmailValid("joao+tag@gmail.com"); // true
isEmailValid("maria@sub.exemplo.com.br"); // true
isEmailValid("invalido"); // false
isEmailValid("sem@dominio"); // false
isEmailValid("@exemplo.com"); // falseO que esse regex aceita
- Letras, números, ponto, underscore, traço e plus na parte local.
- Domínio com hífen.
- Subdomínios (mail.exemplo.com).
- TLDs compostos (.com.br, .co.uk).
O que esse regex ainda deixa passar
- Espaço em branco (use
.trim()antes). - Maiúsculas/minúsculas (normalize com
.toLowerCase()). - TLD inventado (.xyz, .pizza — são todos TLDs reais).
- Domínio inexistente (precisa DNS para pegar).
Atenção
HTML5 type=email: validação de graça no navegador
Adicionar type="email" ao input habilita três coisas sem uma linha de JavaScript:
- Validação de formato ao submeter o formulário (mensagem nativa do navegador).
- Teclado otimizado no mobile (mostra arroba e ponto em destaque).
- Ícone de e-mail em autofill de senha/contato.
<form>
<label for="email">Seu e-mail</label>
<input
type="email"
id="email"
name="email"
required
placeholder="voce@exemplo.com"
/>
<button type="submit">Enviar</button>
</form>A validação HTML5 usa regex simples internamente — aceita a@b, o que é tecnicamente válido mas raramente útil. Combine com regex próprio para reforçar:
const form = document.querySelector("form");
const input = document.querySelector("#email");
form.addEventListener("submit", (e) => {
if (!isEmailValid(input.value)) {
e.preventDefault();
input.setCustomValidity("Digite um e-mail válido, como voce@exemplo.com");
input.reportValidity();
}
});
input.addEventListener("input", () => {
input.setCustomValidity(""); // limpa mensagem customizada ao digitar
});Validação em React com feedback imediato
Em React, o padrão moderno combina onBlur para validar quando o usuário sai do campo, não a cada tecla (evita mostrar “inválido” enquanto ele ainda está digitando).
import { useState } from "react";
function isEmailValid(email: string): boolean {
return /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/.test(email.trim().toLowerCase());
}
export function EmailInput() {
const [email, setEmail] = useState("");
const [error, setError] = useState<string | null>(null);
const handleBlur = () => {
if (!email) {
setError(null);
return;
}
setError(isEmailValid(email) ? null : "E-mail inválido");
};
return (
<div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onBlur={handleBlur}
required
/>
{error && <p className="text-red-600 text-sm mt-1">{error}</p>}
</div>
);
}Validação em Node.js (backend)
O backend deve revalidar — nunca confie no cliente. Em uma rota API:
// Next.js API route (app router)
import { NextResponse } from "next/server";
const EMAIL_REGEX = /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/;
export async function POST(req: Request) {
const { email } = await req.json();
if (!email || typeof email !== "string") {
return NextResponse.json(
{ error: "Campo e-mail obrigatório" },
{ status: 400 },
);
}
const normalized = email.trim().toLowerCase();
if (!EMAIL_REGEX.test(normalized)) {
return NextResponse.json(
{ error: "Formato de e-mail inválido" },
{ status: 400 },
);
}
// prossiga com inserção no banco, envio de confirmação, etc.
return NextResponse.json({ ok: true });
}Bibliotecas populares comparadas
| Critério | Tamanho | Valida DNS | Melhor para |
|---|---|---|---|
| validator.js | 17 KB | Não | Validação sintática robusta |
| email-validator | 3 KB | Não | Simples, leve, edge-ready |
| deep-email-validator | N/A | Sim | Node.js com verificação SMTP |
| disposable-email-domains | 200 KB | N/A | Lista de domínios descartáveis |
validator.js (exemplo)
import validator from "validator";
validator.isEmail("joao@exemplo.com"); // true
validator.isEmail("joao@exemplo.com", {
allow_utf8_local_part: false,
require_tld: true,
domain_specific_validation: true,
}); // true (com opções)Validação DNS: checar se o domínio recebe e-mail
Regex aceita email@empresainexistente999.com. Só o DNS sabe se essa empresa existe e tem mail server. Em Node.js, use o módulo nativo:
import { resolveMx } from "node:dns/promises";
async function hasMxRecord(domain: string): Promise<boolean> {
try {
const records = await resolveMx(domain);
return records.length > 0;
} catch {
return false;
}
}
async function validateEmailDeep(email: string): Promise<{
valid: boolean;
reason?: string;
}> {
if (!/^[\w.+-]+@[\w-]+(\.[\w-]+)+$/.test(email)) {
return { valid: false, reason: "Formato inválido" };
}
const domain = email.split("@")[1];
const mx = await hasMxRecord(domain);
if (!mx) {
return { valid: false, reason: "Domínio não aceita e-mail" };
}
return { valid: true };
}Contexto
Bloqueando e-mails descartáveis
Lista atualizada mantida pela comunidade (3000+ domínios):
import disposableDomains from "disposable-email-domains";
function isDisposable(email: string): boolean {
const domain = email.split("@")[1]?.toLowerCase();
return disposableDomains.includes(domain);
}
isDisposable("joao@mailinator.com"); // true
isDisposable("joao@gmail.com"); // false
isDisposable("joao@10minutemail.com"); // trueErros clássicos que rejeitam e-mails legítimos
- Bloquear plus (+):
joao+newsletter@gmail.comé RFC válido e usado por milhões. Regex ruim rejeita. - Limitar domínio a 2–3 caracteres após ponto: TLDs modernos têm 6+ caracteres (.museum, .travel, .photography).
- Rejeitar hífen em domínio:
meu-site.com.bré válido. - Não aceitar subdomínios:
joao@mail.empresa.com.brprecisa passar. - Case-sensitivity: e-mails são case-insensitive na parte do domínio. Normalize tudo com
toLowerCase(). - Deixar espaços passarem: trim antes de validar, sempre.
Confirmação por e-mail (double opt-in)
A única forma 100% confiável de validar um e-mail é enviar uma mensagem com link único e esperar o usuário clicar. Requer backend e serviço de envio (Resend, SendGrid, Postmark, AWS SES). Fluxo padrão:
- Usuário submete e-mail no cadastro.
- Regex valida formato.
- Backend cria registro marcado como “pendente”.
- Sistema envia e-mail com token único.
- Usuário clica no link.
- Backend marca registro como “confirmado”.
- Só agora o e-mail é considerado válido.
Dica
Serviços comerciais de validação
Quando e-mail é crítico para o negócio (outbound sales, cobrança, marketing em escala), considere API paga:
- ZeroBounce: verificação SMTP + score de risco + detecção de spam traps. ~US$ 0,008 por e-mail.
- NeverBounce: similar, bulk pricing menor. Boa integração com Mailchimp.
- Hunter Email Verifier: B2B-focused. Integração com CRMs.
- Emailable: preços agressivos, rate limit alto.
Limpeza de lista existente
Se você já tem uma base de e-mails com bounces frequentes, o caminho é limpar antes de enviar de novo:
- Exporte a lista em CSV.
- Valide sintaxe local com regex — descarta erros óbvios.
- Passe por serviço de validação comercial (bulk).
- Segmente resultado: válidos, risky, inválidos.
- Envie só para válidos. Remova inválidos permanentemente.
- Considere re-engajar risky com campanha pequena e monitorar bounce.
Performance: validando grandes listas
Validar 100.000 e-mails com regex é questão de milissegundos. Com DNS, questão de minutos. Com SMTP, questão de horas. Estratégias:
- Cache de DNS: muitos e-mails compartilham domínio (@gmail.com aparece milhares de vezes). Cache o resultado por domínio.
- Paralelização com limite: DNS suporta concorrência, mas excesso fura rate limit. Use Promise.all com batch de 10–50.
- Fila de background: para grandes volumes, use BullMQ/Sidekiq. Não trave o request HTTP.
Segurança: evitando abuso
- Rate limit no cadastro: limite tentativas por IP (ex.: 5 em 10 minutos) para evitar scraper de contas.
- Proteção contra enumeration: nunca revele “e-mail já cadastrado” vs “e-mail inválido” com mensagens diferentes em login público.
- Sanitize antes de exibir: se você ecoa o e-mail no HTML, escape para evitar XSS (React faz automaticamente, PHP e outros não).
- Não log de e-mails completos: em ambiente de produção, mascare ou hash o e-mail nos logs para LGPD/GDPR.
Validação em uma frase
Validação de e-mail em JavaScript é camadas: regex no cliente para UX, regex no servidor como gatekeeper, DNS opcional quando custo de conta importa, e confirmação por e-mail quando você precisa certeza. Use a camada compatível com o valor em jogo — nem de menos, nem pesadão demais.
Perguntas frequentes
Regex é suficiente para validar e-mail?+
Para a maioria dos formulários, sim. Um regex bem escrito filtra 99% das entradas inválidas (vazio, sem @, sem domínio). Mas regex não verifica se o e-mail existe de verdade — só se o formato está correto. Para registro de conta, considere enviar e-mail de confirmação. Para campanhas grandes, valide com API externa (SMTP check, DNS MX). Regex é porta de entrada, não garantia de entregabilidade.
Qual o melhor regex para validar e-mail em JavaScript?+
Depende do rigor desejado. Para formulários web comuns, o regex /^[\w.+-]+@[\w-]+\.[\w.-]+$/ cobre 99% dos casos válidos. Para seguir RFC 5322 completamente, o regex fica quase inutilizável de tão longo. Na prática, use regex simples e valide real existência via API. Evite regex copiado de StackOverflow sem entender — muitos rejeitam e-mails legítimos (plus signs, domínios com hífen).
Devo validar no frontend ou no backend?+
Nos dois. Frontend dá feedback imediato pro usuário (UX); backend é a única validação confiável (segurança). Cliente pode desabilitar JavaScript, manipular DOM ou enviar request direto via curl. Regra de ouro: frontend valida para melhorar UX, backend valida como se frontend não existisse. Nunca confie só em validação cliente.
Qual a diferença entre type=email e regex customizada?+
O atributo HTML5 type=email habilita validação nativa do navegador com regex simples embutida. Vantagem: zero JavaScript necessário, UX padrão (teclado otimizado no mobile, ícone correto). Desvantagem: não controle o regex, mensagens de erro em idioma do navegador, não valida presença de TLD. Para sites modernos, use type=email + regex próprio combinados — redundância barata.
Como validar se o e-mail realmente existe?+
Três camadas. (1) Sintaxe — regex. (2) DNS — verificar se o domínio tem registros MX configurados (existe servidor de e-mail). (3) SMTP — tentar conectar no servidor SMTP e perguntar se o mailbox existe (sem enviar mensagem). Camadas 2 e 3 exigem backend. Bibliotecas como email-validator (Python) e deep-email-validator (Node.js) automatizam. Serviços como ZeroBounce e NeverBounce oferecem API comercial.
Devo bloquear e-mails descartáveis (Mailinator, 10minutemail)?+
Depende. Para SaaS com trial gratuito e custo por conta, sim — descartáveis indicam baixa intenção e fraude. Para newsletter ou download de conteúdo, bloquear é discutível (pode afastar audiência curiosa). Bibliotecas mantêm listas atualizadas de domínios descartáveis (disposable-email-domains em npm tem 4000+ domínios). O trade-off é falso positivo — alguns usuários legítimos usam domínios categorizados como descartáveis.
Por que o e-mail com + (plus) às vezes é rejeitado?+
Plus addressing (joao+newsletter@gmail.com) é recurso oficial do RFC, suportado por Gmail, Outlook, iCloud e outros. Permite ao usuário criar apelidos sem criar conta nova. Muitos sistemas validam erroneamente com regex que rejeita o +, quebrando o recurso e frustrando usuários que usam plus para organizar inboxes. Seu regex deve aceitar + na parte local obrigatoriamente.
E-mails com acentos e UTF-8 são válidos?+
Tecnicamente sim, desde 2012 (RFC 6531). Um endereço como joão@exemplo.com.br é válido no padrão internacional. Na prática, muitos servidores ainda não suportam, e a entregabilidade é irregular. Para formulários no Brasil, aceite ASCII (letras sem acento) e rejeite UTF-8 com mensagem clara (ex.: “use caracteres sem acento”). É compromisso entre padrão e realidade.
Artigos relacionados
O que Torna um E-mail Válido? Regras Técnicas e Validação (2026)
Estrutura conforme RFC 5321/5322, caracteres permitidos, exemplos surpreendentes, regex balanceada vs literal, validação por DNS/SMTP, IDN/Unicode e detecção de e-mails descartáveis.
Como Limpar Lista de E-mails Inválidos (2026): Guia Completo para Evitar Bounce
Guia definitivo de limpeza de lista de e-mails: tipos de bounce, ferramentas de validação em massa, processo passo a passo, reputação de domínio e como manter lista limpa.
Regex para Validação de Formulários (2026): E-mail, CPF, Telefone, CEP
Coleção de regex prontas para campos brasileiros: e-mail, CPF, CNPJ, telefone, CEP, URL, data, senha forte, cartão. Inclui máscara em tempo real, integração React e ReDoS.
Grupos de Captura em Regex (2026): Named Groups, Referências e Lookahead
Guia completo de grupos em regex: capturing, non-capturing, named groups, backreferences, lookahead, lookbehind, replace com substituição e exemplos prontos em JavaScript, Python e PHP.