Anleitung · JavaScript & Node.js

E-Mail-Validierung in JavaScript: vom Formularfeld bis zum Postfach

Fünf Ebenen der E-Mail-Validierung für eine JavaScript-Anwendung: die Prüfung des Browsers, eine getestete Regex, Hinweise auf Tippfehler, eine MX-Abfrage in Node.js und eine Postfachprüfung per API, zusammengeführt in einer Express-Route.

Aktualisiert am 29. Oktober 2026 · 12 Min. Lesezeit

E-Mail-Adresse in JavaScript mit einem regulären Ausdruck validieren

Die E-Mail-Validierung in JavaScript hat zwei Aufgaben: Nutzern beim Tippen sofort Feedback geben und Adressen, die zurückkommen würden, aus Ihrer Datenbank fernhalten. Die erste Aufgabe erledigen der Browser und eine Regex. Die zweite kann nur Ihr Server übernehmen, indem er prüft, ob die Domain E-Mails empfängt und ob das Postfach existiert. Diese Anleitung zeigt jede Ebene mit Code, den wir ausgeführt haben: Chrome 156 für die Prüfungen im Browser, Node.js 26 für alles andere und eine lokale Nachbildung der API für die Postfachprüfung.

1. Das Format zuerst vom Browser prüfen lassen

<input type="email"> ist die günstigste Prüfung, die es gibt. Mobilgeräte zeigen eine Tastatur mit @-Taste, und der Browser blockiert das Formular, wenn der Wert nicht wie eine Adresse aussieht:

<input type="email" id="email" name="email" required autocomplete="email" maxlength="254">

Mit der Constraint Validation API ersetzen Sie die Meldung des Browsers durch Ihre eigene:

const input = document.querySelector("#email");

input.addEventListener("input", () => {
  input.setCustomValidity(""); // zuerst zurücksetzen, sonst bleibt das Feld ungültig
  if (input.validity.typeMismatch) {
    input.setCustomValidity("Bitte geben Sie eine E-Mail-Adresse wie name@example.com ein.");
  }
});

Der Browser wendet die Regel aus dem HTML-Standard an, und die ist absichtlich großzügig. In unserem Test (Chrome 156, Werte per Skript gesetzt) bestanden jane@example ohne Top-Level-Domain, jane..doe@example.com und ein lokaler Teil mit 65 Zeichen, und input.value lieferte die Adresse ohne Leerzeichen und Zeilenumbrüche am Rand zurück. Der englische Leitfaden zum HTML-E-Mail-Validator erklärt die Regel, das Attribut pattern und die Unterschiede zwischen Browsern.

2. E-Mail-Validierung in JavaScript mit einer Regex

Eine Regex schließt die Lücken, die der Browser lässt, und derselbe Code läuft im Browser und in Node.js. Das ist das getestete Muster aus unserem englischen Leitfaden zur E-Mail-Regex:

// email.js: läuft im Browser und in Node.js
const EMAIL_REGEX =
  /^(?=.{1,254}$)(?=.{1,64}@)[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+(?:[A-Za-z]{2,63}|xn--[A-Za-z0-9-]{2,59})$/;

export function isValidEmail(value) {
  return typeof value === "string" && EMAIL_REGEX.test(value);
}

Die beiden Lookaheads prüfen die Längengrenzen (254 Zeichen insgesamt, 64 vor dem @). Der Rest erlaubt Plus-Tags und Apostrophe und lehnt Punkte am Anfang oder Ende des lokalen Teils, zwei Punkte hintereinander, Bindestriche am Rand eines Domain-Labels und Domains ohne Top-Level-Domain ab.

Zwei Details sind in JavaScript wichtig. Ohne das Flag m passen ^ und $ nur am Anfang und Ende des ganzen Strings, "jane@example.com\n" fällt also durch. Und setzen Sie nie das Flag g: Eine globale Regex merkt sich, wo der letzte Treffer endete, und zweimal test() mit derselben Adresse liefert erst true, dann false.

Leerzeichen entfernen und internationale Domains umwandeln

Das Muster kennt internationale Domains nur in Punycode (xn--…). Entfernen Sie auf dem Server deshalb Leerzeichen am Rand und wandeln Sie die Domain mit domainToASCII aus dem Node-Modul url um, bevor Sie validieren:

// normalize.js: Node.js
import { domainToASCII } from "node:url";

// Entfernt Leerzeichen am Rand und wandelt eine internationale Domain in Punycode um.
export function normalizeEmail(input) {
  const email = String(input).trim();
  const at = email.lastIndexOf("@");
  const domain = email.slice(at + 1);
  // Nur reine Domainnamen umwandeln; alles andere lehnt isValidEmail ab.
  if (at < 1 || !/^[\p{L}\p{M}\p{N}.-]+$/u.test(domain)) return email;
  return email.slice(0, at + 1) + domainToASCII(domain);
}

normalizeEmail(" jane@bücher.example ") liefert jane@xn--bcher-kva.example, und das besteht die Prüfung. Die Zeichenprüfung vor der Umwandlung ist wichtig: domainToASCII("example.com/x") liefert example.com, ohne sie würde aus jane@example.com/x also eine gültige Adresse.

3. validator.js und Zod

Wenn Ihr Projekt schon eine Validierungsbibliothek nutzt, bringt sie eine E-Mail-Prüfung mit:

import isEmail from "validator/lib/isEmail.js"; // npm install validator
import { z } from "zod"; // npm install zod

isEmail("jane@example.com"); // true

const Email = z.email(); // Zod 4; in Zod 3: z.string().email()
Email.safeParse("jane@example").success; // false

Jede Adresse unten lief durch alle vier Prüfungen. ✓ heißt, die Prüfung nimmt die Adresse an, ✗, dass sie sie ablehnt.

AdresseSoll bestehen?type="email"Regexvalidator.jsZod
jane@example.comJa✓✓✓✓
jane.doe+news@example.comJa✓✓✓✓
o'brien@example.ieJa✓✓✓✓
jane@example.photographyJa✓✓✓✓
jane@xn--bcher-kva.exampleJa✓✓✓✓
jane.@example.comNein✓✗✗✗
.jane@example.comNein✓✗✗✗
jane..doe@example.comNein✓✗✗✗
jane@exampleNein✓✗✗✗
jane@example.cNein✓✗✗✗
jane@-example.comNein✗✗✗✗
jane@exa_mple.comNein✗✗✗✗
jane@example..comNein✗✗✗✗
jane doe@example.comNein✗✗✗✗
"jane doe"@example.comNein (laut RFC gültig)✗✗✓✗
jane@[192.0.2.10]Nein (laut RFC gültig)✗✗✗✗
josé@example.comNein (braucht SMTPUTF8)✗✗✓✗
jane@bücher.exampleNach IDN-Umwandlung✗✗✓✗
aaa…a@example.com (65 a)Nein✓✗✗✓
jane@example.com mit Leerzeichen am RandNach dem Trimmen✓✗✗✗
jane@example.com + ZeilenumbruchNein✓✗✗✗

Getestet mit Chrome 156, Node.js 26.12, validator 13.15.35 und Zod 4.6.7. Das ✓ des Browsers in den letzten beiden Zeilen kommt von seiner Wertbereinigung: Er entfernt Leerzeichen und Zeilenumbruch, bevor er prüft. Was die Bibliotheken anders machen:

Für welche Prüfung Sie sich auch entscheiden: Führen Sie dieselbe im Browser und auf dem Server aus, damit der Server nie eine Adresse ablehnt, die das Formular angenommen hat.

4. Korrekturen für Tippfehler vorschlagen

Viele fehlerhafte Anmeldungen sind Tippfehler in einer bekannten Domain: gmial.com, hotmial.com, yaho.com. Sie bestehen jede Formatprüfung. Schlagen Sie die wahrscheinliche Adresse vor, statt abzulehnen:

// suggest.js: läuft im Browser und in Node.js
const DOMAINS = [
  "gmail.com", "googlemail.com", "yahoo.com", "hotmail.com", "outlook.com", "live.com",
  "icloud.com", "aol.com", "mail.com", "gmx.com", "gmx.de", "gmx.at", "gmx.net", "web.de", "proton.me",
];

// Levenshtein-Distanz: wie viele Änderungen einzelner Zeichen aus a b machen
function distance(a, b) {
  let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
  for (let i = 1; i <= a.length; i++) {
    const row = [i];
    for (let j = 1; j <= b.length; j++) {
      row[j] = Math.min(prev[j] + 1, row[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
    }
    prev = row;
  }
  return prev[b.length];
}

// Liefert eine korrigierte Adresse für einen wahrscheinlichen Tippfehler in einer bekannten Domain, sonst null.
export function suggestEmail(email) {
  const at = email.lastIndexOf("@");
  const domain = email.slice(at + 1).toLowerCase();
  if (at < 1 || DOMAINS.includes(domain)) return null;
  let best = null;
  for (const candidate of DOMAINS) {
    const d = distance(domain, candidate);
    if (d <= 2 && (!best || d < best.d)) best = { candidate, d };
  }
  return best ? `${email.slice(0, at)}@${best.candidate}` : null;
}

In unserem Test machte die Funktion aus anna@gmial.com den Vorschlag anna@gmail.com, aus anna@gmail.con ebenfalls anna@gmail.com und aus anna@outlok.com den Vorschlag anna@outlook.com; anna@mail.com, anna@gmx.de und anna@example.com ließ sie unverändert. Echte Domains, die einer Domain in der Liste ähneln, etwa mail.com neben gmail.com, müssen selbst in der Liste stehen; bevor wir gmx.at ergänzt hatten, schlug die Funktion dafür gmx.de vor. Zeigen Sie das Ergebnis deshalb als Frage an („Meinten Sie anna@gmail.com?“), sobald das Feld den Fokus verliert, und korrigieren Sie nie automatisch. Die E-Mail-Validierungs-API liefert einen eigenen Vorschlag im Feld did_you_mean.

5. Die MX-Einträge der Domain in Node.js prüfen

Ein gültiges Format sagt nichts über die Domain aus. Das Modul dns von Node.js fragt die Mailserver ab:

// mx.js: Node.js
import { Resolver } from "node:dns/promises";

const resolver = new Resolver({ timeout: 3000, tries: 2 });

// true: die Domain nimmt E-Mails an; false: nicht; null: DNS gab keine klare Antwort
export async function acceptsMail(domain) {
  try {
    const mx = await resolver.resolveMx(domain);
    if (mx.length === 1 && mx[0].exchange === "") return false; // Null-MX (RFC 7505)
    if (mx.length > 0) return true;
  } catch (err) {
    if (err.code === "ENOTFOUND") return false; // die Domain existiert nicht
    if (err.code !== "ENODATA") return null; // Zeitüberschreitung, SERVFAIL: unbekannt, nicht ablehnen
  }
  // Kein MX-Eintrag: Absender stellen an den A- oder AAAA-Eintrag der Domain zu (impliziter MX).
  const results = await Promise.allSettled([resolver.resolve4(domain), resolver.resolve6(domain)]);
  if (results.some((r) => r.status === "fulfilled" && r.value.length > 0)) return true;
  return results.every((r) => r.reason?.code === "ENODATA") ? false : null;
}

Für den Test haben wir den Resolver mit resolver.setServers() auf einen lokalen Test-DNS-Server gerichtet:

Domain eingerichtet mitresolveMx lieferteacceptsMail
Zwei MX-Einträgenbeide Einträgetrue
Null-MX (0 .)einen Eintrag mit exchange: ""false
Nur A-EintragFehler ENODATAtrue
Nur AAAA-EintragFehler ENODATAtrue
Domain existiert nichtFehler ENOTFOUNDfalse
SERVFAILFehler ESERVFAILnull
Keine AntwortFehler ETIMEOUT nach Ablauf der Zeitnull

Eine Domain, die keine E-Mails empfängt, veröffentlicht einen einzigen MX-Eintrag mit dem Host . (RFC 7505); Node.js liefert ihn mit leerem exchange. example.com ist so eine Domain, deshalb kommen Testmails an Adressen dort immer zurück. Behandeln Sie null als „unbekannt“: Ein langsamer DNS-Server ist kein Grund, einen Kunden abzuweisen. Mit dem MX-Lookup prüfen Sie eine Domain von Hand.

6. Prüfen, ob das Postfach existiert

Die MX-Abfrage zeigt, dass die Domain E-Mails annimmt, nicht, dass anna@example.org existiert. Das weiß nur der empfangende Mailserver, und ein Browser kann ihn nicht fragen. Von Ihrem eigenen Server aus brauchen Sie dafür ausgehenden Port 25, den die meisten Cloud-Anbieter sperren, und Catch-all-Domains nehmen ohnehin jede Adresse an. Die E-Mail-Validierungs-API führt Syntax-, DNS-, MX- und Postfachprüfung in einer Anfrage aus, ohne eine E-Mail zu senden:

// check-mailbox.js: Node.js 18 oder neuer (eingebautes fetch)
const API_URL = "https://api.emailvalidation.io/v1/info";

export async function checkMailbox(email) {
  const key = process.env.EMAILVALIDATION_KEY;
  if (!key) throw new Error("EMAILVALIDATION_KEY is not set");

  // timeout=8: Die API antwortet innerhalb von 8 Sekunden, der Client wartet 2 Sekunden länger.
  const params = new URLSearchParams({ email, timeout: "8" });
  const res = await fetch(`${API_URL}?${params}`, {
    headers: { apikey: key },
    signal: AbortSignal.timeout(10_000),
  });
  if (!res.ok) {
    throw new Error(`email validation API: HTTP ${res.status} ${await res.text()}`);
  }
  return res.json();
}

Der Schlüssel kommt aus einer Umgebungsvariablen und steht im Header apikey, er erscheint also nie im Frontend-Code, in URLs oder Logs. URLSearchParams kodiert das + in jane+news@example.org als %2B, damit der Tag unverändert bei der API ankommt. Der API-Parameter timeout (3 bis 60 Sekunden, Standard 30) begrenzt, wie lange die API auf einen langsamen Mailserver wartet; laut Dokumentation (Englisch) sollte Ihr HTTP-Client ein paar Sekunden länger warten. Ein falscher Schlüssel führt zu 401, ein aufgebrauchtes Kontingent oder zu viele parallele Prüfungen zu 429, und in beiden Fällen wirft die Funktion einen Fehler.

Die Antwort hat 21 Felder. Entscheiden Sie anhand von status oder, wenn Ihnen die Aktion reicht, anhand von recommended_action:

statusBeispiele für sub_statusrecommended_actionIm Anmeldeformular
validnull, role_based, possible_typosend, send_with_cautionAnnehmen. did_you_mean anzeigen, wenn es nicht leer ist.
invalidmailbox_not_found, no_dns_entries, failed_syntax_checksuppressAblehnen und um Prüfung der Adresse bitten.
catch_allaccept_allsend_with_cautionAnnehmen. Die Domain nimmt jede Adresse an, das Postfach lässt sich nicht bestätigen.
riskymailbox_fullretry_laterAnnehmen; das Postfach existiert, ist aber gerade voll.
do_not_maildisposablesuppressNach einer dauerhaften Adresse fragen.
unknowntimeout_exceeded, greylistedretry_laterAnnehmen. Der Mailserver gab keine klare Antwort.

Die älteren Felder state und reason liefern dasselbe Urteil in drei Zuständen (deliverable, undeliverable, unknown); die Seite Result Statuses (Englisch) ordnet sie einander zu. Warum sich Catch-all-Domains nicht Postfach für Postfach prüfen lassen, erklärt Catch-all-E-Mail-Adressen.

Das offizielle SDK, npm install @everapi/emailvalidation-js, sendet dieselbe Anfrage: new Emailvalidation(key).info(email, {}). In Version 1.0.6 ist das zweite Argument Pflicht (übergeben Sie {}), es gibt keine Zeitbegrenzung, und eine Fehlerantwort wie 401 kommt als normales Ergebnisobjekt zurück. Prüfen Sie also, ob das Ergebnis ein Feld state hat, bevor Sie es verwenden.

7. Alles zusammen in einer Express-Route

Auf dem Server läuft zuerst die Formatprüfung und antwortet sofort. Danach folgt die API-Prüfung, die im Zweifel durchlässt: Ist die API langsam, nicht erreichbar oder das Kontingent aufgebraucht, geht die Anmeldung trotzdem durch.

// server.js: npm install express
import express from "express";
import { isValidEmail } from "./email.js";
import { normalizeEmail } from "./normalize.js";
import { checkMailbox } from "./check-mailbox.js";

const app = express();
app.use(express.urlencoded({ extended: false }));

app.post("/signup", async (req, res) => {
  const email = normalizeEmail(req.body?.email ?? "");
  if (!isValidEmail(email)) {
    return res.status(422).json({ error: "Bitte geben Sie eine gültige E-Mail-Adresse ein." });
  }

  let result = null;
  try {
    result = await checkMailbox(email);
  } catch (err) {
    console.warn("email check skipped:", err.message); // API ausgefallen oder langsam: Anmeldung nicht blockieren
  }
  if (result?.status === "invalid") {
    return res.status(422).json({ error: "Diese E-Mail-Adresse existiert nicht. Bitte prüfen Sie sie." });
  }
  if (result?.status === "do_not_mail") {
    return res.status(422).json({ error: "Bitte verwenden Sie eine dauerhafte E-Mail-Adresse." });
  }

  // Konto anlegen ...
  res.status(201).json({ email, didYouMean: result?.did_you_mean || null });
});

app.listen(3000);

Wir haben den Server mit Express 5.3 gegen eine lokale Nachbildung der API gestartet, die das dokumentierte Antwortformat liefert, und Formulardaten an /signup gesendet:

Gesendetes emailAntwort
anna@example.org201
anna@example.org mit Leerzeichen am Rand201, gespeichert als anna@example.org
jane@bücher.example.com201, an die API gesendet als jane@xn--bcher-kva.example.com
jane@example422, „Bitte geben Sie eine gültige E-Mail-Adresse ein.“
Eine Adresse, die die API als invalid meldet422, „Diese E-Mail-Adresse existiert nicht. Bitte prüfen Sie sie.“
Eine Adresse, die die API als do_not_mail meldet422, „Bitte verwenden Sie eine dauerhafte E-Mail-Adresse.“
Eine Adresse auf einer Catch-all-Domain201
anna@gmial.com201 mit "didYouMean": "anna@gmail.com"
Beliebige Adresse, während die API 429 antwortet201, Prüfung übersprungen und protokolliert
Kein Feld email oder das Feld doppelt422

Dasselbe Muster funktioniert in Route Handlers von Next.js, in Fastify oder in einer Serverless-Funktion: Formatprüfung, API-Aufruf mit Zeitbegrenzung, nur invalid und do_not_mail blockieren.

Empfohlener Aufbau

  1. Im Formular: type="email", required und autocomplete="email", dazu isValidEmail für eine Meldung beim Tippen.
  2. Wenn das Feld den Fokus verliert: suggestEmail, als Frage angezeigt.
  3. Auf dem Server: normalizeEmail, dann erneut isValidEmail.
  4. Beim Absenden: die API-Prüfung. Blockieren Sie invalid und Wegwerf-Adressen, nehmen Sie den Rest an, und nehmen Sie alles an, wenn die API nicht erreichbar ist.
  5. Für eine bestehende Liste nutzen Sie den Bulk-E-Mail-Validator oder den Bulk-Endpunkt, statt /v1/info in einer Schleife aufzurufen. Der kostenlose Tarif enthält 100 Prüfungen im Monat mit bis zu 10 Anfragen pro Minute und 5 gleichzeitigen Prüfungen; bezahlte Tarife haben kein Minutenlimit und führen 25 Prüfungen gleichzeitig aus (Preise der E-Mail-Validierungs-API).

Um die Antwort der API für eine Adresse zu sehen, bevor Sie Code schreiben, geben Sie sie in den kostenlosen E-Mail-Validator ein. Dieselben Prüfungen in anderen Sprachen: E-Mail-Validierung in Python und E-Mail-Validierung in PHP.

Quellen

Geprüft am 29. Oktober 2026: HTML-Standard: valid email address; MDN, Constraint Validation; Node.js-Dokumentation: dns, url.domainToASCII; READMEs von validator.js und Zod; RFC 7505 (Null-MX); API-Dokumentation von emailvalidation.io: Validierungs-Endpunkt, Rate Limits. Code ausgeführt mit Node.js 26.12, Chrome 156, validator 13.15.35, Zod 4.6.7 und Express 5.3.0, gegen einen lokalen DNS-Server und eine lokale Nachbildung der API.

E-Mail-Validierung in anderen Sprachen

Häufig gestellte Fragen

Wie validiere ich eine E-Mail-Adresse in JavaScript?

Entfernen Sie Leerzeichen am Rand und prüfen Sie die Eingabe mit einer Regex, die den Formatregeln folgt, zum Beispiel mit dem Muster auf dieser Seite und EMAIL_REGEX.test(value). Im Formular sorgt type="email" für sofortiges Feedback. Ob die Adresse existiert, verrät keine Formatprüfung. Prüfen Sie das Postfach bei Anmeldungen deshalb auf Ihrem Server, etwa mit einer E-Mail-Validierungs-API.

Welche Regex eignet sich für die E-Mail-Validierung in JavaScript?

Eine, die Plus-Tags und Apostrophe erlaubt, Punkte am Rand des lokalen Teils, doppelte Punkte und Domains ohne Top-Level-Domain ablehnt und die Grenzen von 64 und 254 Zeichen einhält. Das Muster in dieser Anleitung tut das; es stammt aus unserem englischen Leitfaden zur E-Mail-Regex, wo es in sechs Sprachen getestet ist. Geben Sie ihm kein g-Flag.

Soll ich validator.js oder Zod statt einer Regex verwenden?

Beide sind brauchbare Formatprüfungen. In unserem Test nahm isEmail() von validator.js lokale Teile in Anführungszeichen, Nicht-ASCII-Zeichen vor dem @ und Unicode-Domains an, und z.email() von Zod akzeptierte einen lokalen Teil mit 65 Zeichen. Keine der beiden prüft, ob die Domain E-Mails empfängt oder das Postfach existiert.

Kann JavaScript prüfen, ob eine E-Mail-Adresse existiert?

Im Browser nicht, denn er kann keine Verbindung zu einem Mailserver öffnen. Node.js kann den empfangenden Server per SMTP fragen, aber ausgehender Port 25 ist bei den meisten Cloud-Anbietern gesperrt, und Catch-all-Domains nehmen jede Adresse an. Eine E-Mail-Validierungs-API führt die DNS-, MX- und Postfachprüfung aus und liefert ein Ergebnis pro Adresse.

Reicht eine Validierung im Browser?

Nein. Jeder kann das Formular abschicken, ohne Ihr JavaScript auszuführen. Wiederholen Sie deshalb jede Prüfung auf dem Server. Die Validierung im Browser ist für schnelles Feedback da; entscheiden muss der Server.

E-Mail-Validierungs-API

E-Mail-Adressen in Ihrer Anwendung prüfen

emailvalidation.io prüft Syntax, MX-Einträge und das Postfach per SMTP, markiert Wegwerf-, Rollen- und Freemail-Adressen und liefert einen Qualitätswert, alles in einer Anfrage.

/v1/info E-Mail-Validierungs-API Zur Dokumentation

100 kostenlose Prüfungen pro Monat. Keine Kreditkarte nötig.

GET https://api.emailvalidation.io/v1/info?email=support@emailvalidation.io

{
  "email": "support@emailvalidation.io",
  "user": "support",
  "tag": "",
  "domain": "emailvalidation.io",
  "format_valid": true,
  "mx_found": true,
  "smtp_check": true,
  "catch_all": null,
  "role": true,
  "disposable": false,
  "free": false,
  "score": 0.64,
  "state": "deliverable",
  "reason": "low_quality",
  "did_you_mean": "",
  "catch_all_resolution": null,
  "bounce_probability": null,
  "status": "valid",
  "sub_status": "role_based",
  "explanation": "The mailbox exists, but it is a role address (such as info@ or support@), usually read by a team rather than one person.",
  "recommended_action": "send_with_caution"
}

Weiterlesen

Starten Sie noch heute mit unserer E-Mail-Validierung!

Kostenlos starten