Sendkit TeamComo validar endereços de e-mail antes de enviar
Aprenda a validar endereços de e-mail com checagem de sintaxe, lookups de MX, detecção de descartáveis e verificação via SMTP para reduzir bounces e proteger sua reputação de remetente.

Cada e-mail que faz bounce corrói um pouquinho da sua reputação de remetente. Mande o suficiente e os provedores começam a te limitar, rotear suas mensagens pro spam ou bloquear você completamente. A solução é direta: valide os endereços de e-mail antes de enviar qualquer coisa.
Este guia detalha cada camada da validação de e-mail, mostra como implementá-las e passa por código real usando a API de validação de e-mail do Sendkit.
Por que validação importa
Três coisas acontecem quando você envia para endereços ruins.
Sua taxa de bounce sobe. Os ISPs monitoram sua razão de bounces. Qualquer coisa acima de 2% é bandeira vermelha. Se chegar a 5% de forma consistente, você está em apuros sérios. Hard bounces (falhas permanentes) são os piores porque sinalizam que você não está mantendo sua lista.
Sua reputação de remetente cai. Provedores como Gmail e Outlook atribuem scores de reputação a domínios e IPs de envio. Altas taxas de bounce, reclamações de spam e acertos em spam traps derrubam esse score. Uma vez que ele afunda, até seus e-mails legítimos vão parar no spam.
Você desperdiça dinheiro. Todo ESP cobra por e-mail enviado. Enviar para endereços que nunca vão abrir, clicar ou converter é jogar dinheiro fora. Se você está em um plano de e-mail transacional, endereços ruins comem sua cota sem retorno.
Validação não é higiene opcional. É infraestrutura.
As camadas da validação de e-mail
Um único regex não é suficiente. Uma validação adequada é uma pilha de checagens, cada uma pegando problemas que a camada anterior deixa passar.
Validação de sintaxe
A checagem mais básica: o endereço segue as regras definidas nas RFC 5321 e RFC 5322? Você precisa de uma parte local, um símbolo @ e um domínio.
A maioria dos devs apela pro regex aqui. Isso funciona pra pegar lixo óbvio como not-an-email ou user@@domain.com. Mas endereços de e-mail em conformidade com RFC são surpreendentemente complexos. Strings entre aspas, comentários e nomes de domínio internacionalizados tornam um regex completo quase impossível de acertar.
Uma boa checagem de sintaxe pega os erros óbvios. Não tente fazer ela pegar tudo.
const isValidSyntax = email => {
const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return pattern.test(email);
};
// catches the basics
isValidSyntax('[email protected]'); // true
isValidSyntax('broken@@example.com'); // false
isValidSyntax('no-domain@'); // falseEsse é seu primeiro filtro, não o último.
Checagens de DNS e registros MX
Um endereço pode parecer perfeitamente válido sintaticamente e ainda assim ser indeliverável. O domínio pode não existir ou não ter registros MX configurados.
Um lookup de MX consulta o DNS pelos servidores de e-mail responsáveis por um domínio. Sem registros MX, ninguém está aceitando e-mail ali.
import { promises as dns } from 'dns';
const hasMxRecords = async email => {
const domain = email.split('@')[1];
try {
const records = await dns.resolveMx(domain);
return records.length > 0;
} catch {
return false;
}
};
await hasMxRecords('[email protected]'); // true (assuming MX exists)
await hasMxRecords('[email protected]'); // falseIsso pega erros de digitação em domínios (gmial.com em vez de gmail.com) e domínios totalmente inventados.
Detecção de e-mail descartável
Serviços de e-mail descartável como Mailinator, Guerrilla Mail e Temp Mail dão aos usuários endereços descartáveis. As pessoas usam pra passar por formulários de cadastro, pegar trials gratuitos ou evitar e-mails de marketing.
Esses endereços funcionam temporariamente mas ficam inativos em horas ou dias. Enviar pra eles desperdiça recursos e distorce suas métricas de engajamento.
A detecção depende de manter uma lista de provedores de e-mail descartável conhecidos. Existem milhares deles. Manter essa lista atualizada é um peso de manutenção que você provavelmente não quer carregar. É aqui que um serviço de API se paga.
Verificação de caixa postal (checagem SMTP)
Essa é a checagem mais profunda. Uma verificação SMTP se conecta ao servidor de e-mail do destinatário e passa pelo handshake SMTP até o comando RCPT TO sem de fato enviar uma mensagem. Se o servidor rejeitar o destinatário, a caixa postal não existe.
Tem pegadinhas. Alguns servidores aceitam todos os endereços durante o handshake e fazem bounce depois (domínios catch-all). Outros fazem rate-limit ou bloqueiam tentativas de verificação. Você não deve rodar checagens SMTP a partir da sua própria infraestrutura porque isso pode levar seu IP para uma blacklist.
Essa checagem é melhor deixada pra um serviço que mantém um pool de IPs e entende as peculiaridades de diferentes servidores de e-mail.
Detecção de endereços baseados em função
Endereços como admin@, info@, support@ e sales@ são baseados em função. Normalmente são encaminhados a um grupo de pessoas ou a uma caixa compartilhada. Não são invalidos por natureza, mas carregam risco maior:
- Taxas de reclamação mais altas porque várias pessoas leem a caixa
- Engajamento menor porque ninguém sente responsabilidade pessoal
- Alguns são usados como spam traps por organizações testando comportamento de remetentes
Marcar endereços baseados em função permite decidir como tratá-los em vez de tratá-los como endereços pessoais.

Validando com a API do Sendkit
Você pode empilhar todas essas checagens por conta própria ou fazer uma única chamada de API. O endpoint de validação de e-mail do Sendkit roda checagens de sintaxe, DNS, descartável, SMTP e baseada em função em uma única requisição e retorna um resultado estruturado.
Validação de um único e-mail
const validateEmail = async email => {
const response = await fetch('https://api.sendkit.com/v1/email/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
return response.json();
};
const result = await validateEmail('[email protected]');
console.log(result);
// {
// "valid": true,
// "disposable": false,
// "mx_found": true,
// "role_based": false,
// "reason": "accepted_email"
// }A resposta te diz tudo o que você precisa pra tomar uma decisão. valid é o veredito geral. Os outros campos te dão controle granular sobre o quão rígido você quer ser.
Validação em lote
Limpar uma lista existente significa validar milhares ou milhões de endereços. Fazer isso um por um é lento. Processamento em lote permite enviar uma lista e receber os resultados de volta em massa.
const validateBatch = async emails => {
const results = await Promise.allSettled(
emails.map(email =>
fetch('https://api.sendkit.com/v1/email/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_your_api_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
}).then(res => res.json())
)
);
return results.map((r, i) => ({
email: emails[i],
...(r.status === 'fulfilled' ? r.value : { valid: false, reason: 'request_failed' }),
}));
};
const emails = ['[email protected]', '[email protected]', '[email protected]'];
const results = await validateBatch(emails);Para listas grandes, adicione controle de concorrência. Bater na API com 100.000 requisições simultâneas não vai terminar bem. Um limitador simples de concorrência mantém tudo fluindo:
const validateWithConcurrency = async (emails, concurrency = 10) => {
const results = [];
const queue = [...emails];
const worker = async () => {
while (queue.length > 0) {
const email = queue.shift();
const result = await validateEmail(email);
results.push({ email, ...result });
}
};
const workers = Array.from({ length: concurrency }, () => worker());
await Promise.all(workers);
return results;
};Integração em um formulário de cadastro
O lugar de maior valor pra validar é no ponto de coleta. Pegue endereços ruins antes que entrem no seu banco.
Aqui vai um exemplo prático para um backend Node.js lidando com envios de formulário:
import express from 'express';
const app = express();
app.use(express.json());
const validateEmail = async email => {
const response = await fetch('https://api.sendkit.com/v1/email/validate', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SENDKIT_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
return response.json();
};
app.post('/signup', async (req, res) => {
const { email, name } = req.body;
const validation = await validateEmail(email);
if (!validation.valid) {
return res.status(400).json({
error: 'Invalid email address',
reason: validation.reason,
});
}
if (validation.disposable) {
return res.status(400).json({
error: 'Disposable email addresses are not allowed',
});
}
if (validation.role_based) {
// allow but flag for review
console.warn(`Role-based email signup: ${email}`);
}
// proceed with account creation
// ...
return res.status(201).json({ message: 'Account created' });
});Isso pega endereços ruins já na porta. Os usuários recebem feedback imediato. Seu banco continua limpo.
O que fazer com os resultados de validação
Nem todo resultado é binário entre aceitar/rejeitar. Construa uma matriz de decisão:
Aceitar quando valid for true, disposable for false e role_based for false. Esse é um endereço pessoal limpo. Envie à vontade.
Rejeitar quando valid for false. O endereço é indeliverável. Não envie. Se for um formulário de cadastro, peça ao usuário pra tentar um endereço diferente.
Rejeitar quando disposable for true. Esses endereços são temporários. Para apps transacionais pode não importar, mas pra qualquer coisa que exija comunicação contínua, bloqueie.
Marcar para revisão quando role_based for true. O endereço funciona, mas carrega risco. Você pode aceitá-lo pra e-mail transacional mas excluí-lo de campanhas de marketing.
const categorizeResult = result => {
if (!result.valid) return 'reject';
if (result.disposable) return 'reject';
if (result.role_based) return 'review';
return 'accept';
};Mantenha simples. Três baldes. Automatize os dois primeiros, revise o terceiro manualmente.

Validação em tempo real vs limpeza em lote
Essas não são abordagens concorrentes. Você precisa das duas.
Validação em tempo real no ponto de entrada (formulários de cadastro, páginas de checkout, formulários de contato) impede que dados ruins entrem no seu sistema. É proativa. O custo de latência é mínimo, já que uma única chamada de API adiciona talvez 200-500ms, o que é invisível para o usuário quando você valida no blur em vez do submit.
Limpeza em lote trata dos endereços que já estão no seu banco. Listas se deterioram em cerca de 2-3% ao mês. As pessoas mudam de emprego, abandonam caixas e domínios expiram. Rode validação em lote trimestralmente no mínimo, mensalmente se você envia em volume alto.
Uma abordagem sólida fica assim:
- Validar cada endereço na coleta em tempo real
- Revalidar sua lista completa mensalmente
- Suprimir qualquer endereço que falhe na revalidação
- Acompanhar taxas de bounce após envios e alimentar esses dados de volta na sua lista de supressão
As duas abordagens se reforçam. Tempo real mantém a porta da frente limpa. Limpeza em lote lida com a deterioração inevitável.
Fechando
Validação de e-mail não é um diferencial bom de ter. Cada endereço na sua lista que não pode receber e-mail está ativamente prejudicando sua entregabilidade. A solução é validação em camadas: sintaxe, DNS, detecção de descartável, verificação SMTP e checagens baseadas em função.
Você pode construir partes disso sozinho, mas as camadas de verificação SMTP e detecção de descartável são genuinamente difíceis de manter. Uma API cuida da complexidade e fica atualizada enquanto provedores de descartável se multiplicam e comportamentos de servidores mudam.
Valide no ponto de coleta. Limpe suas listas existentes regularmente. Aja com base nos resultados com regras claras. Suas taxas de bounce vão cair, sua reputação de remetente vai se manter e seus e-mails vão realmente chegar nas pessoas que você está tentando alcançar.
Compartilhar este artigo