Um eine E-Mail-Adresse in Express zu validieren, verdrahten Sie Middleware, keine
einzelne Prüfung — und die Middleware muss der Reihe nach drei verschiedene Fragen
beantworten. Ist die Adresse korrekt geformt? Kann ihre Domain Mail empfangen? Existiert
das Postfach tatsächlich? Express selbst liefert nichts davon mit, aber das Ökosystem
darum herum macht jede einzelne zu einer Sache von wenigen Zeilen: express-validator
für die Syntax, Nodes eingebautes dns/promises für die Domain und eine
Verifizierungs-API für das Postfach. Dieser Leitfaden baut alle drei als Validatoren auf
einer einzigen POST-Route auf und zeigt genau, wo das Framework aufhört und eine echte
Prüfung beginnt. Es ist die Express-geformte Variante des
Node.js-Leitfadens zur E-Mail-Validierung,
sodass die dortige Argumentation zu DNS und SMTP unverändert übernommen wird.
Die kurze Antwort#
Verketten Sie drei Validatoren auf dem email-Feld, den günstigsten zuerst, und lassen
Sie das .bail() von express-validator einen Kurzschluss auslösen, sobald einer
entscheidend ist: Verwenden Sie body('email').isEmail() für die Syntax, einen
asynchronen benutzerdefinierten Validator, der dns/promises resolveMx für die Domain
kapselt, und einen zweiten asynchronen benutzerdefinierten Validator, der eine
Verifizierungs-API für das Postfach aufruft — mit Rückgabe eines 422, wenn das Urteil
undeliverable lautet. Versuchen Sie nicht, aus Ihrem Express-Prozess selbst
SMTP-Verbindungen zu öffnen, um Postfächer zu prüfen: Der ausgehende Port 25 ist auf den
meisten Hosts blockiert, und die Antwort hängt von der Reputation der sendenden IP und
von Greylisting ab, das Sie nicht selbst nachbauen wollen. Jede Schicht schließt Adressen
günstiger aus als die letzte; nur die API kann eine einschließen.
Schicht 1: Syntax mit express-validator#
express-validator ist die De-facto-Validierungs-Middleware für Express — ein dünner,
Express-nativer Wrapper um die
validator.js-Bibliothek. Seine isEmail()-Prüfung ist das isEmail von
validator.js, sodass Sie denselben kampferprobten Syntax-Parser bekommen, auf den sich
jedes Node-Projekt bereits stützt, bereitgestellt als verkettbare Middleware. Deklarieren
Sie eine Regel auf dem Feld, und sie läuft vor Ihrem Handler:
import { body } from "express-validator";
const validateEmail = body("email")
.trim()
.isEmail()
.withMessage("Enter a valid email address.")
.bail();
.trim() bereinigt führende und nachgestellte Leerzeichen, .isEmail() validiert die
Form, .withMessage() legt den Fehlertext fest, und .bail() stoppt die Kette für dieses
Feld in dem Moment, in dem die Syntax scheitert — sodass die teureren Schichten weiter
unten niemals auf einer fehlerhaften Zeichenkette laufen. Dieses .bail() ist das
Express-Äquivalent dazu, bei der günstigstmöglichen Prüfung anzuhalten.
Machen Sie sich genau klar, was Ihnen das einbringt. isEmail() liest die
Zeichenkette — es löst niemals DNS auf und öffnet niemals einen Socket.
definitely-fake@gmail.com besteht. info@company-that-folded.com besteht.
typo@gmial.com besteht. Alle drei sind nicht zustellbar, und kein Validator, der nur die
Zeichenkette inspiziert, wird Ihnen das jemals sagen — aus demselben Grund, aus dem
Regex-E-Mail-Validierung scheitert.
Syntax und Zustellbarkeit sind unterschiedliche Fragen: Die eine ist eine Tatsache über
die Zeichenkette, die andere eine Tatsache über das Internet.
Schicht 2: Kann die Domain Mail empfangen?#
Dies ist die erste Schicht, die Express Ihnen nicht in die Hand gibt, und sie lässt sich
günstig anflanschen. Eine Domain ohne MX-Einträge kann für niemanden Mail annehmen, sodass
ein einziges DNS-Lookup tote Domains, falsch geschriebene Firmennamen und erfundene TLDs
eliminiert, bevor Sie irgendetwas im Netzwerk aufwenden. Nodes eingebautes
node:dns/promises löst MX-Einträge ohne Abhängigkeiten auf, und das .custom() von
express-validator akzeptiert eine asynchrone Funktion — werfen Sie darin, um das Feld
scheitern zu lassen, geben Sie true zurück, um zu bestehen:
import { resolveMx } from "node:dns/promises";
async function hasMailRoute(email) {
const domain = email.slice(email.lastIndexOf("@") + 1);
let records = [];
try {
records = await resolveMx(domain);
} catch {
// ENOTFOUND / ENODATA — the domain doesn't exist or publishes no MX
throw new Error("This domain cannot receive email.");
}
if (records.length === 0) {
throw new Error("This domain cannot receive email.");
}
return true;
}
Weil das eine schlichte asynchrone Funktion ist, fügt sie sich direkt als
benutzerdefinierter Validator in die Kette ein, abgesichert durch ein weiteres .bail(),
sodass die Postfach-Schicht nur auf einer Domain läuft, die tatsächlich eine Mail-Route
auflöst:
body("email")
.isEmail()
.bail()
.custom(hasMailRoute)
.bail();
await hasMailRoute("jane@gmail.com"); // true
await hasMailRoute("jane@company-that-folded.com"); // throws — no MX
Manche Domains nehmen Mail über einen A-Eintrag ohne MX an (implizites MX). Wenn Sie
diesen Sonderfall berücksichtigen wollen, greifen Sie auf resolve4 zurück, wenn
resolveMx leer zurückkommt — aber für die überwältigende Mehrheit echter Adressen ist
eine MX-Prüfung der richtige Filter.
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
gerade halten — noreply-9f2x@gmail.com ist gültige Syntax auf einer aktiven Mail-Route,
und es ist trotzdem ein Postfach, das nie angelegt wurde. Ein bestimmtes Postfach zu
bestätigen bedeutet den SMTP-Zustelldialog: Verbindung zum Mail-Host aufbauen, RCPT TO
absetzen, die Antwort lesen und die Verbindung trennen, bevor irgendetwas gesendet wird.
Im Prinzip könnten Sie das aus Express mit dem net-Modul skripten. In der Praxis sollten
Sie es nicht von Ihrem Anwendungsserver aus ausführen: Die meisten Cloud-Hosts blockieren
den ausgehenden Port 25, die Antwort hängt von der Reputation der IP ab, von der aus Sie
sich verbinden, und empfangende Server betreiben Greylisting und Rate-Limiting bei
unbekannten Absendern — sodass eine Prüfung, die in einem lokalen Test funktioniert, in
der Produktion stillschweigend scheitert oder Sie auf eine Blockliste bringt.
Wie E-Mail-Verifizierung funktioniert
geht die gesamte Pipeline durch, Catch-All-Domains und alles. Dies ist die Schicht, die es
wert ist, delegiert zu werden.
Qualisend aus einem asynchronen benutzerdefinierten Validator aufrufen#
Die Delegation ist einfach ein weiterer benutzerdefinierter Validator. Der
Verify-Endpunkt von Qualisend führt die gesamte Pipeline — Syntax, DNS und die
SMTP-Postfachprüfung — von reputationsverwalteter Infrastruktur aus durch und gibt ein
Urteil zurück. Rufen Sie ihn mit dem globalen fetch auf (ab Node 18+ eingebaut), lesen
Sie Ihren Schlüssel aus einer Umgebungsvariablen und werfen Sie nur, wenn das Urteil
undeliverable lautet:
async function isDeliverable(email) {
const res = await fetch("https://api.qualisend.com/v1/verify", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.QUALISEND_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
});
// On our own outage or a rate limit, don't block a real signup.
if (!res.ok) return true;
const { result } = await res.json();
if (result.status === "undeliverable") {
throw new Error("We couldn't confirm a mailbox at this address.");
}
return true;
}
Der Endpunkt oben ist ein Platzhalter — prüfen Sie die API-Referenz für die
genaue Basis-URL und die Anfrageform — aber die Antwort kommt als Umschlag
{ "result": { ... } } zurück:
{
"result": {
"status": "deliverable",
"score": 95,
"reason": null,
"sub_flags": { "role": false, "disposable": false, "free": false, "catch_all": false }
}
}
status ist einer von deliverable, risky, undeliverable oder unknown. Der
Validator oben lässt hart nur undeliverable scheitern und lässt risky und unknown
durch, sodass Sie nachgelagert entscheiden können, was Sie mit ihnen tun — anhand des
score filtern oder auf einen sub_flags-Eintrag wie disposable verzweigen — anstatt
eine Grenzfall-Adresse in einen Formularfehler zu verwandeln. Behandeln Sie das obige JSON
als die Form, nicht als den Vertrag; die vollständige Feldliste steht in den
Entwicklerdokumenten.
Die Schichten zusammenfügen, um eine E-Mail-Adresse in Express zu validieren#
Setzen Sie alle drei auf einer body("email")-Kette zusammen, die günstigste zuerst, mit
einem .bail() zwischen jeder, sodass ein Fehler einen Kurzschluss auslöst, bevor die
nächste Schicht läuft. Der API-Validator feuert nur bei einer Adresse, die bereits Syntax
und die MX-Prüfung bestanden hat:
import { body } from "express-validator";
const validateEmail = [
body("email")
.trim()
.isEmail()
.withMessage("Enter a valid email address.")
.bail()
.custom(hasMailRoute)
.bail()
.custom(isDeliverable),
];
Verdrahten Sie dieses Array vor Ihrem Route-Handler und lesen Sie dann die gesammelten
Fehler mit validationResult. Wenn die Kette scheitert, antworten Sie mit einem 422 und
dem Fehler-Array; andernfalls hat jede Schicht bestanden und die Adresse kann gefahrlos
persistiert werden:
import express from "express";
import { validationResult } from "express-validator";
const app = express();
app.use(express.json());
app.post("/signup", validateEmail, (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
// Every layer passed — safe to create the account.
const { email } = req.body;
return res.status(201).json({ email });
});
Diese Reihenfolge ist der ganze Trick: isEmail() schließt Müll kurz, bevor Ihr Code
läuft, die lokale MX-Prüfung schließt tote Domains kostenlos aus, und die API wird nur für
Adressen aufgerufen, die beides bestanden haben. Eine Validierung in falscher Reihenfolge
— oder das Überspringen der günstigen Schichten — verbraucht bei jedem Tippfehler ein
API-Guthaben. Die Schichtung, nicht das Framework, ist es, was die Validierung zuverlässig
macht; sie hat dieselbe Form wie die Node.js-Variante,
wobei die Middleware-Kette von Express an die Stelle der Pipeline tritt.
Eine Entscheidung, die Sie vorab treffen müssen: was passiert, wenn der API-Aufruf selbst
scheitert. Ein Netzwerk-Timeout oder ein geworfenes fetch innerhalb von isDeliverable
sollte einem echten Kunden keinen 422 bescheren, den er nicht beheben kann. Der Validator
oben mildert diesen Fall bereits ab, indem er bei einer nicht-OK-Antwort true zurückgibt
— er behandelt einen nicht erreichbaren Dienst als unknown statt als undeliverable,
lässt die Anmeldung durch und überlässt die erneute Verifizierung einem späteren Zeitpunkt.
Die Syntax- und MX-Schichten liefen bereits lokal, sodass Sie nur die Schicht lockern, die
vom Netzwerk abhängt.
Führen Sie diese schnelle synchrone Pipeline am Erfassungspunkt aus und reservieren Sie die schwerere Batch-Verifizierung für die Listenbereinigung. Der Serverless-Anmelde-Leitfaden zeigt das Echtzeit-Muster von Anfang bis Ende, und wenn Sie auswählen, welcher Dienst Schicht drei untermauert, stellt der API-Vergleich die Optionen gegenüber.
Häufig gestellte Fragen#
Reicht das isEmail von express-validator aus, um eine E-Mail-Adresse zu validieren?#
Für die Syntax ja — body("email").isEmail() kapselt das isEmail von validator.js und
ist die richtige Prüfung für die erste Schicht, weit besser als eine selbst gebaute Regex.
Aber es validiert die Form, nicht die Zustellbarkeit: Es löst niemals DNS auf und
kontaktiert keinen Mailserver, sodass ein bestandener Check bedeutet, dass etwas "wie eine
E-Mail aussieht", nicht dass es "zugestellt wird". Kombinieren Sie es mit einem MX-Lookup
und einer Postfachprüfung, bevor Sie der Adresse vertrauen.
Wie schreibe ich einen asynchronen benutzerdefinierten Validator in Express?#
Übergeben Sie eine asynchrone Funktion an das .custom() von express-validator. Die
Funktion erhält den Feldwert; geben Sie true zurück (oder resolve), um zu bestehen, und
throwen Sie einen Error (oder reject), um zu scheitern — die geworfene Nachricht wird
zum Validierungsfehler. So klinken sich die Funktionen hasMailRoute und isDeliverable
oben in dieselbe body("email")-Kette ein. Setzen Sie vor jede ein .bail(), damit eine
gescheiterte Schicht die Kette stoppt, anstatt die nächste auszuführen.
Kann ich in Express ohne API prüfen, ob ein Postfach existiert?#
Teilweise. node:dns/promises bestätigt, dass die Domain Mail annimmt, was tote Domains
kostenlos ausschließt und keine Abhängigkeit benötigt. Das Postfach zu bestätigen bedeutet
einen SMTP-Dialog, den Sie mit dem net-Modul versuchen können, aber nicht von Ihrem
App-Server aus ausführen sollten — Port 25 ist weitgehend blockiert und das Ergebnis hängt
von der Reputation Ihrer IP ab. Genau diese Schicht existiert, damit ein Verifizierungsdienst
sie übernimmt; was E-Mail-Verifizierung ist erklärt die
Begriffe.
Sollte ich einen 422 zurückgeben oder die Anmeldung bei einem unbekannten Ergebnis durchlassen?#
Weisen Sie undeliverable mit einem 422 ab — das ist eine bestätigt fehlerhafte Adresse,
die der Nutzer korrigieren kann. Aber lassen Sie es nicht am eigenen Ausfall Ihres
Verifizierungsdienstes scheitern: Behandeln Sie eine nicht-OK-Antwort, ein Timeout oder
einen unknown-Status als "durchlassen und später erneut prüfen", sodass ein vorübergehendes
Netzwerkproblem niemals eine echte Registrierung blockiert. Der isDeliverable-Validator
tut genau dies, indem er true zurückgibt, wenn die Antwort nicht OK ist.
Bereit, die Postfach-Schicht hinzuzufügen? Werfen Sie eine syntaktisch einwandfreie Adresse
in den kostenlosen E-Mail-Checker, um zuzusehen, wie eine von
isEmail freigegebene Zeichenkette als undeliverable zurückkommt, und verdrahten Sie dann
dasselbe Urteil mit den Copy-and-Paste-Beispielen in der API-Referenz in Ihre
Express-Middleware.