Skip to content
Comece com 100 créditos de verificação grátis
Qualisend
Todos os artigos
Engenharia / 14 de junho de 2026

Como validar um endereço de e-mail em Java

7 minutes read

Qualisend team
Uma janela de código Java validando um e-mail pelas camadas de sintaxe, DNS e SMTP até um veredito de entregabilidade

Validar um endereço de e-mail em Java são, na verdade, três checagens sob um mesmo nome. A maioria dos tutoriais recorre a uma regex, confirma que a string tem o formato de um endereço e considera pronto — mas o formato é a menos útil das três coisas que você realmente quer saber. A validação de verdade é em camadas: uma checagem barata de formato, uma consulta DNS pela rota de e-mail do domínio e uma sondagem SMTP da caixa postal. A biblioteca padrão do Java e o Jakarta Mail cobrem as duas primeiras de forma limpa; a terceira é um problema de rede que vale a pena delegar. Este guia constrói cada camada com código funcional e mostra exatamente onde cada uma para.

A resposta curta#

Use jakarta.mail.internet.InternetAddress (ou o Apache Commons Validator) para a sintaxe, o provedor DNS JNDI embutido no JDK para a consulta de MX e uma API de verificação para a checagem da caixa postal por SMTP — a mais barata primeiro, interrompendo assim que uma delas for decisiva. Não abra conexões SMTP a partir da sua aplicação para sondar caixas postais por conta própria: a porta 25 de saída é bloqueada na maioria dos hosts, e a resposta depende da reputação do IP de envio e de greylisting que você não vai querer reimplementar. Cada camada descarta endereços de forma mais barata que a anterior; só a última consegue aprovar um endereço.

Camada 1: sintaxe com o Jakarta Mail#

O Jakarta Mail — a biblioteca renomeada de javax.mail quando migrou para o namespace Jakarta EE — traz um parser de endereços em que você pode se apoiar em vez de escrever uma regex na mão. Construa um InternetAddress e chame validate(): o construtor faz o parsing do endereço, e validate() impõe a sintaxe da RFC 822, lançando AddressException em qualquer coisa malformada.

import jakarta.mail.internet.AddressException;
import jakarta.mail.internet.InternetAddress;

public static boolean isValidSyntax(String email) {
    if (email == null || email.length() > 320) {
        return false;
    }
    try {
        InternetAddress address = new InternetAddress(email);
        address.validate();
        return true;
    } catch (AddressException e) {
        return false;
    }
}

Um detalhe importante: validate() é permissivo quanto ao domínio. Ele aceita jane@localhost e jane@example — sem exigir ponto — porque a RFC 822 permite domínios sem ponto. E tudo bem aqui. A camada 1 é um portão de formato, não uma checagem de entregabilidade, e é a consulta DNS da camada 2 que de fato decide se o domínio consegue receber e-mail. Mantenha essa checagem permissiva e deixe o DNS fazer o descarte; perseguir a perfeição do formato com uma regex maior é uma batalha perdida de qualquer forma.

Se você estiver em um jar javax.mail mais antigo, o código é idêntico, exceto pelo nome do pacote. E se você já depende do Apache Commons Validator, o EmailValidator dele é uma boa alternativa para a camada um — é um pouco mais rígido (rejeita domínios sem ponto por padrão):

import org.apache.commons.validator.routines.EmailValidator;

boolean valid = EmailValidator.getInstance().isValid(email);

Prefira o Jakarta Mail se você já o usa para enviar e-mail — uma dependência a menos. Qualquer uma das bibliotecas só responde à pergunta da sintaxe.

Camada 2: o domínio consegue receber e-mail?#

Um domínio sem registros MX não consegue aceitar e-mail para ninguém, então uma única consulta de MX elimina domínios mortos, nomes de empresas com erro de digitação e TLDs inventados. O Java faz isso sem nenhuma dependência externa: o JDK inclui um provedor de serviço DNS para o JNDI, então você resolve o atributo MX através de um DirContext.

import java.util.Hashtable;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public static boolean hasMailRoute(String domain) {
    Hashtable<String, String> env = new Hashtable<>();
    env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory");
    env.put("com.sun.jndi.dns.timeout.initial", "2000"); // don't hang on a slow resolver
    env.put("com.sun.jndi.dns.timeout.retries", "1");

    DirContext ctx = null;
    try {
        ctx = new InitialDirContext(env);
        Attributes attrs = ctx.getAttributes(domain, new String[] { "MX" });
        Attribute mx = attrs.get("MX");
        return mx != null && mx.size() > 0;
    } catch (NamingException e) {
        // NameNotFoundException → domain doesn't exist; no MX attribute → no mail route
        return false;
    } finally {
        if (ctx != null) {
            try { ctx.close(); } catch (NamingException ignored) { }
        }
    }
}

Separe o domínio do endereço no último @ para que partes locais entre aspas não te atrapalhem:

String domain = email.substring(email.lastIndexOf('@') + 1);

hasMailRoute("gmail.com");               // true
hasMailRoute("company-that-folded.com"); // false

Um atributo MX ausente ou vazio significa que o domínio não publica rota de e-mail; uma NameNotFoundException (subclasse de NamingException) significa que ele não resolve de forma alguma. Alguns domínios aceitam e-mail em um registro A com um MX implícito — se você quiser respeitar esse caso extremo, recorra à consulta de "A" quando o conjunto de MX voltar vazio. Para a esmagadora maioria dos endereços reais, uma checagem de MX é o filtro certo. Como a consulta bloqueia esperando um resolver DNS, mantenha os timeouts acima em um fluxo de cadastro e trate uma falha transitória como "verificar depois", não como uma rejeição definitiva — um soluço do DNS não deveria afastar um cliente real.

Camada 3: a caixa postal realmente existe?#

As camadas 1 e 2 só conseguem descartar um endereço. Um domínio pode publicar registros MX perfeitos e ainda assim não ter caixa postal no endereço que você tem em mãos — noreply-9f2x@gmail.com tem sintaxe válida em um domínio com rota de e-mail ativa, e ainda assim é uma caixa postal que nunca foi criada. Confirmar que uma caixa postal específica existe exige a conversa de entrega SMTP: conectar ao host de e-mail, emitir RCPT TO, ler a resposta e desconectar antes de enviar qualquer coisa. Há mais nuances — domínios catch-all aceitam qualquer endereço e derrotam uma sondagem ingênua — como funciona a verificação de e-mail percorre o pipeline completo.

Você pode roteirizar SMTP em Java com um Socket cru, mas não deveria rodá-lo a partir da sua aplicação. A maioria dos provedores de nuvem bloqueia a porta 25 de saída, a resposta depende da reputação do IP a partir do qual você conecta, e os servidores de recebimento aplicam greylisting e limitam a taxa de remetentes desconhecidos — então uma sondagem que passa em um teste local silenciosamente falha, ou te coloca em uma blocklist, em produção. Esta é a camada que vale a pena delegar.

O POST /verify da Qualisend roda o pipeline inteiro — sintaxe, DNS e a sondagem SMTP da caixa postal — a partir de uma infraestrutura com reputação gerenciada, feita para isso, e devolve um veredito. O Java 11+ já traz java.net.http.HttpClient, então você não precisa de nenhuma dependência HTTP; combine-o com o Jackson (ou o Gson) para ler o JSON. Guarde sua chave em uma variável de ambiente e nunca a deixe embutida no código:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Map;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class QualisendClient {
    // Placeholder endpoint — check /developers for the current base URL and shape.
    private static final String ENDPOINT = "https://api.qualisend.com/v1/verify";

    private final HttpClient http = HttpClient.newHttpClient();
    private final ObjectMapper mapper = new ObjectMapper();

    public JsonNode verify(String email) throws IOException, InterruptedException {
        String apiKey = System.getenv("QUALISEND_API_KEY"); // holds YOUR_API_KEY
        String payload = mapper.writeValueAsString(Map.of("email", email));

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(ENDPOINT))
            .header("Authorization", "Bearer " + apiKey)
            .header("Content-Type", "application/json")
            .timeout(Duration.ofSeconds(10))
            .POST(HttpRequest.BodyPublishers.ofString(payload))
            .build();

        HttpResponse<String> response =
            http.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            throw new IOException("Qualisend responded " + response.statusCode());
        }
        // The verdict lives inside a `result` envelope.
        return mapper.readTree(response.body()).get("result");
    }
}

Leia os campos que te interessam a partir do nó result:

JsonNode result = client.verify("jane@example.com");

String  status     = result.get("status").asText();  // deliverable | risky | undeliverable | unknown
int     score      = result.path("score").asInt();    // 0–100 confidence
String  reason     = result.hasNonNull("reason")
                         ? result.get("reason").asText()  // machine-readable reason, may be null
                         : null;
boolean disposable = result.path("sub_flags").path("disposable").asBoolean();

O formato exato da resposta — cada chave de sub_flags e cada código de reason — está na referência da API. Para a validação de cadastro ao vivo, o status geralmente basta para agir: rejeite undeliverable, trate risky e unknown conforme sua política e sinalize endereços disposable já na entrada.

Juntando as camadas para validar um endereço de e-mail em Java#

A mais barata primeiro, pare assim que tiver uma resposta. Um pequeno record guarda o veredito (records são do Java 16+; no 11–15, use uma classe comum):

public record Verdict(String status, String reason) {}

public Verdict validate(String email) throws IOException, InterruptedException {
    if (!isValidSyntax(email)) {
        return new Verdict("undeliverable", "invalid_email");
    }
    String domain = email.substring(email.lastIndexOf('@') + 1);
    if (!hasMailRoute(domain)) {
        return new Verdict("undeliverable", "invalid_domain");
    }
    JsonNode result = client.verify(email); // client is a QualisendClient
    return new Verdict(
        result.get("status").asText(),
        result.hasNonNull("reason") ? result.get("reason").asText() : null);
}

As duas camadas locais não custam nada e pegam a maior parte do lixo na hora; a API roda apenas nos endereços que valem a ida e volta pela rede. Essa ordem é o truque inteiro — o mesmo formato que você encontra nas versões em Node.js, Python e PHP deste guia, porque é o encadeamento das camadas, não a linguagem, que faz a validação funcionar.

Perguntas frequentes#

InternetAddress.validate() basta para validar um e-mail em Java?#

Para a sintaxe, é a ferramenta certa da camada um — o jakarta.mail.internet.InternetAddress com validate() é mais bem testado que uma regex caseira e livra você de reimplementar a RFC 822. Mas ele valida apenas o formato: nunca resolve DNS nem contata um servidor de e-mail, e é permissivo o bastante para aceitar domínios sem ponto, como jane@localhost. Combine-o com uma consulta de MX e uma verificação de caixa postal por SMTP antes de confiar no endereço.

Como consultar registros MX em Java sem uma biblioteca externa?#

Use o provedor DNS JNDI embutido no JDK. Crie um InitialDirContext com java.naming.factory.initial definido como com.sun.jndi.dns.DnsContextFactory, depois chame getAttributes(domain, new String[] {"MX"}) e verifique o atributo MX retornado. Não precisa de nenhuma dependência de terceiros e informa de forma limpa se um domínio publica uma rota de e-mail. Capture NamingException e trate a ausência de MX como não entregável.

Dá para verificar uma caixa postal em Java sem uma API?#

Em parte. O Jakarta Mail e o JNDI confirmam que o endereço está bem formado e que o domínio aceita e-mail — ambos gratuitos e com poucas dependências. Confirmar a própria caixa postal exige uma conversa SMTP, que você pode tentar com um Socket cru, mas não deveria rodar do seu servidor de aplicação: a porta 25 é amplamente bloqueada e o resultado depende da reputação do seu IP de envio. Essa camada final é o que um serviço de verificação cuida.

Devo validar e-mails no cadastro ou ao limpar uma lista?#

Nos dois, com profundidades diferentes. Rode as camadas de sintaxe e MX de forma síncrona no cadastro — elas são rápidas o suficiente para bloquear a requisição e dar feedback instantâneo — e aja sobre o status da API ali também. Reserve o trabalho em lote mais profundo para a limpeza de listas; o guia de cadastro serverless mostra o padrão em tempo real, e o guia de limpeza de listas cobre o lado em lote.


Pronto para adicionar a camada SMTP? Passe qualquer endereço pelo verificador de e-mail gratuito para ver uma string com sintaxe perfeita voltar com um veredito real, ou leia a referência da API para o endpoint /verify, o envelope result completo e exemplos de copiar e colar em todas as linguagens acima.

Your reputation, protected.

Clean your first list in minutes. 100 free credits, no card required.

Get started