Eine E-Mail-Adresse in Java zu validieren, sind eigentlich drei Prüfungen, die sich einen Namen teilen. Die meisten Tutorials greifen zu einer Regex, bestätigen, dass die Zeichenkette wie eine Adresse geformt ist, und erklären es damit für erledigt — doch die Form ist das am wenigsten nützliche der drei Dinge, die Sie eigentlich wissen wollen. Echte Validierung ist geschichtet: eine günstige Formatprüfung, ein DNS-Lookup für die Mail-Route der Domain und eine SMTP-Postfachprüfung. Javas Standardbibliothek und Jakarta Mail decken die ersten beiden sauber ab; die dritte ist ein Netzwerkproblem, das man besser auslagert. Dieser Leitfaden baut jede Schicht mit lauffähigem Code auf und zeigt genau, wo jede von ihnen aufhört.
Die kurze Antwort#
Verwenden Sie jakarta.mail.internet.InternetAddress (oder Apache Commons
Validator) für die Syntax, den in das JDK integrierten JNDI-DNS-Provider für den
MX-Lookup und eine Verifizierungs-API für die SMTP-Postfachprüfung — das
Günstigste zuerst, mit Kurzschluss, sobald eine Prüfung entscheidend ist. Öffnen
Sie keine SMTP-Verbindungen von Ihrer Anwendung aus, um Postfächer selbst zu
prüfen: Der ausgehende Port 25 ist auf den meisten Hosts blockiert, und die
Antwort hängt von der Reputation der Sende-IP und vom Greylisting ab, das Sie
nicht neu implementieren wollen. Jede Schicht schließt Adressen günstiger aus
als die vorherige; nur die letzte kann eine Adresse einschließen.
Schicht 1: Syntax mit Jakarta Mail#
Jakarta Mail — die Bibliothek, die von javax.mail umbenannt wurde, als sie in
den Namensraum von Jakarta EE wechselte — liefert einen Adress-Parser, auf den
Sie sich statt auf eine selbst gebastelte Regex stützen können. Konstruieren Sie
eine InternetAddress und rufen Sie validate() auf: Der Konstruktor parst die
Adresse, und validate() erzwingt die RFC-822-Syntax und wirft bei allem
Fehlerhaften eine AddressException.
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;
}
}
Eines sollten Sie wissen: validate() ist bei der Domain nachsichtig. Es
akzeptiert jane@localhost und jane@example — kein Punkt erforderlich — weil
RFC 822 punktlose Domains erlaubt. Das ist hier in Ordnung. Schicht 1 ist ein
Formattor, keine Zustellbarkeitsprüfung, und der DNS-Lookup von Schicht 2 ist
das, was tatsächlich entscheidet, ob die Domain Mail empfangen kann. Halten Sie
diese Prüfung nachsichtig und lassen Sie DNS das Aussortieren übernehmen; der
formalen Perfektion mit einer größeren Regex hinterherzujagen, ist ohnehin
ein aussichtsloses Spiel.
Wenn Sie eine ältere javax.mail-JAR verwenden, ist der Code identisch bis auf
den Paketnamen. Und wenn Sie ohnehin bereits von Apache Commons Validator
abhängen, ist dessen EmailValidator eine gute Alternative für Schicht eins —
er ist eine Spur strenger (er lehnt punktlose Domains standardmäßig ab):
import org.apache.commons.validator.routines.EmailValidator;
boolean valid = EmailValidator.getInstance().isValid(email);
Bevorzugen Sie Jakarta Mail, wenn Sie es ohnehin zum Versenden von Mail nutzen — eine Abhängigkeit weniger. Beide Bibliotheken beantworten immer nur die Syntaxfrage.
Schicht 2: Kann die Domain überhaupt Mail empfangen?#
Eine Domain ohne MX-Einträge kann für niemanden Mail annehmen, also eliminiert
ein einziger MX-Lookup tote Domains, falsch geschriebene Firmennamen und
erfundene TLDs. Java erledigt das ganz ohne externe Abhängigkeit: Das JDK bringt
einen DNS-Service-Provider für JNDI mit, sodass Sie das MX-Attribut über einen
DirContext auflösen.
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) { }
}
}
}
Trennen Sie die Domain am letzten @ von der Adresse ab, damit Sie
zitierte lokale Teile nicht aus dem Tritt bringen:
String domain = email.substring(email.lastIndexOf('@') + 1);
hasMailRoute("gmail.com"); // true
hasMailRoute("company-that-folded.com"); // false
Ein fehlendes oder leeres MX-Attribut bedeutet, dass die Domain keine
Mail-Route veröffentlicht; eine NameNotFoundException (eine Unterklasse von
NamingException) bedeutet, dass sie sich überhaupt nicht auflöst. Manche
Domains nehmen Mail über einen A-Eintrag mit implizitem MX an — wenn Sie diesen
Sonderfall berücksichtigen wollen, greifen Sie ersatzweise auf eine Abfrage von
"A" zurück, wenn das MX-Set leer zurückkommt. Für die überwältigende Mehrheit
echter Adressen ist eine MX-Prüfung der richtige Filter. Da der Lookup auf einem
DNS-Resolver blockiert, behalten Sie die obigen Timeouts in einem Anmeldepfad
bei und behandeln Sie einen vorübergehenden Fehler als „später erneut prüfen",
nicht als harte Ablehnung — ein DNS-Schluckauf sollte einen echten Kunden nicht
abweisen.
Schicht 3: Existiert das Postfach tatsächlich?#
Die Schichten 1 und 2 können eine Adresse nur ausschließen. Eine Domain kann
perfekte MX-Einträge veröffentlichen und trotzdem kein Postfach unter der
Adresse haben, die Sie in Händen halten — noreply-9f2x@gmail.com ist
syntaktisch gültig auf einer Domain mit aktiver Mail-Route, und es ist trotzdem
ein Postfach, das nie angelegt wurde. Die Bestätigung, dass ein bestimmtes
Postfach existiert, erfordert die SMTP-Zustellkonversation: Verbindung zum
Mail-Host aufbauen, RCPT TO ausgeben, die Antwort lesen und die Verbindung
trennen, bevor irgendetwas gesendet wird. Es steckt mehr dahinter — Catch-all-
Domains akzeptieren jede Adresse und hebeln eine naive Prüfung aus —
wie E-Mail-Verifizierung funktioniert
durchläuft die gesamte Pipeline.
Sie können SMTP in Java mit einem rohen Socket skripten, aber Sie sollten es
nicht aus Ihrer Anwendung heraus ausführen. Die meisten Cloud-Anbieter
blockieren den ausgehenden Port 25, die Antwort hängt von der Reputation der IP
ab, von der aus Sie sich verbinden, und empfangende Server greylisten
unbekannte Absender und drosseln deren Rate — sodass eine Prüfung, die in einem
lokalen Test besteht, in der Produktion still fehlschlägt oder Sie auf eine
Blockliste bringt. Das ist die Schicht, die es sich zu delegieren lohnt.
Qualisends POST /verify durchläuft die gesamte Pipeline —
Syntax, DNS und die SMTP-Postfachprüfung — von einer reputationsgeführten
Infrastruktur, die genau dafür gebaut ist, und liefert ein Urteil zurück. Java
11+ bringt java.net.http.HttpClient mit, sodass Sie keine HTTP-Abhängigkeit
brauchen; kombinieren Sie es mit Jackson (oder Gson), um das JSON zu lesen.
Bewahren Sie Ihren Schlüssel in einer Umgebungsvariablen auf und codieren Sie
ihn niemals fest:
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");
}
}
Lesen Sie die Felder, die Sie interessieren, aus dem result-Knoten heraus:
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();
Die genaue Struktur der Antwort — jeder sub_flags-Schlüssel und jeder
reason-Code — steht in der API-Referenz. Für die
Live-Validierung bei der Anmeldung reicht der status meist aus, um zu handeln:
undeliverable ablehnen, risky und unknown nach Richtlinie behandeln und
disposable-Adressen am Eingabefeld kennzeichnen.
Die Schichten zusammensetzen, um eine E-Mail-Adresse in Java zu validieren#
Das Günstigste zuerst, aufhören, sobald Sie eine Antwort haben. Ein kleines Record hält das Urteil (Records gibt es ab Java 16; auf 11–15 verwenden Sie eine einfache Klasse):
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);
}
Die beiden lokalen Schichten kosten nichts und fangen den meisten Müll sofort ab; die API läuft nur auf Adressen, die den Netzwerk-Roundtrip wert sind. Diese Reihenfolge ist der ganze Trick — dieselbe Form finden Sie auch in den Versionen dieses Leitfadens für Node.js, Python und PHP, denn es ist die Schichtung, nicht die Sprache, die Validierung funktionieren lässt.
Häufig gestellte Fragen#
Reicht InternetAddress.validate() aus, um eine E-Mail in Java zu validieren?#
Für die Syntax ist es das richtige Werkzeug der ersten Schicht —
jakarta.mail.internet.InternetAddress mit validate() ist besser getestet als
eine selbst geschriebene Regex und erspart Ihnen die Neuimplementierung von
RFC 822. Aber es prüft nur die Form: Es löst niemals DNS auf und kontaktiert
keinen Mailserver, und es ist nachsichtig genug, um punktlose Domains wie
jane@localhost zu akzeptieren. Kombinieren Sie es mit einem MX-Lookup und einer
SMTP-Postfachprüfung, bevor Sie der Adresse vertrauen.
Wie prüfe ich MX-Einträge in Java ohne externe Bibliothek?#
Verwenden Sie den in das JDK integrierten JNDI-DNS-Provider. Erstellen Sie einen
InitialDirContext, bei dem java.naming.factory.initial auf
com.sun.jndi.dns.DnsContextFactory gesetzt ist, rufen Sie dann
getAttributes(domain, new String[] {"MX"}) auf und prüfen Sie das zurückgegebene
MX-Attribut. Es benötigt keine Drittanbieter-Abhängigkeit und sagt Ihnen
sauber, ob eine Domain eine Mail-Route veröffentlicht. Fangen Sie
NamingException ab und behandeln Sie einen fehlenden MX-Eintrag als nicht
zustellbar.
Kann ich in Java ein Postfach ohne API verifizieren?#
Teilweise. Jakarta Mail und JNDI bestätigen, dass die Adresse wohlgeformt ist
und die Domain Mail annimmt — beides kostenlos und mit geringem
Abhängigkeitsaufwand. Die Bestätigung des Postfachs selbst erfordert eine
SMTP-Konversation, die Sie mit einem rohen Socket versuchen können, aber nicht
von Ihrem Anwendungsserver aus ausführen sollten: Port 25 ist weithin blockiert
und das Ergebnis hängt von der Reputation Ihrer Sende-IP ab. Genau diese letzte
Schicht übernimmt ein Verifizierungsdienst.
Sollte ich E-Mails bei der Anmeldung oder beim Bereinigen einer Liste validieren?#
Beides, in unterschiedlicher Tiefe. Führen Sie die Syntax- und MX-Schichten bei
der Anmeldung synchron aus — sie sind schnell genug, um die Anfrage zu
blockieren und sofortiges Feedback zu geben — und handeln Sie auch dort nach dem
status der API. Reservieren Sie tiefergehende Batch-Arbeit für die
Listenbereinigung; der
Leitfaden zur serverlosen Anmeldung
zeigt das Echtzeit-Muster und der
Leitfaden zur Listenbereinigung behandelt die
Batch-Seite.
Bereit, die SMTP-Schicht hinzuzufügen? Lassen Sie eine beliebige Adresse durch
den kostenlosen E-Mail-Checker laufen, um zuzusehen, wie
eine syntaktisch perfekte Zeichenkette mit einem echten Urteil zurückkommt, oder
lesen Sie die API-Referenz für den /verify-Endpunkt, das
vollständige result-Envelope und Copy-Paste-Beispiele in jeder oben genannten
Sprache.