Regex für E-Mail-Validierung: ein praxistaugliches Muster und seine Grenzen

Kein Regex kann Ihnen sagen, ob eine Adresse funktioniert. Ein kurzes Muster fängt Tippfehler ab, eine Bestätigungsmail beweist den Rest.

Direkt ausprobieren: Regex-Tester

Wer nach einem Regex für E-Mail-Adressen sucht, findet alles zwischen acht Zeichen und mehreren Tausend. Die langen Muster versuchen, den Standards exakt zu folgen, und können trotzdem nicht sagen, ob ein Postfach existiert. Die kurzen sind leicht zu lesen und reichen für die richtige Aufgabe völlig aus. Diese Aufgabe lautet: offensichtliche Fehler wie ein fehlendes @ oder ein Leerzeichen abfangen, bevor Sie eine Bestätigungsmail verschicken, die die eigentliche Prüfung übernimmt.

Warum die vollständige RFC-5322-Grammatik das falsche Ziel ist

RFC 5322 legt die Syntax von Adressen in E-Mail-Nachrichten fest und erlaubt weit mehr, als sich irgendein Registrierungsformular wünscht. Alle folgenden Adressen sind syntaktisch gültig:

  • "john doe"@example.com: ein lokaler Teil in Anführungszeichen, der ein Leerzeichen enthält.
  • john(comment)@example.com: ein Kommentar innerhalb der Adresse.
  • user@[192.168.0.1]: eine IP-Adresse statt eines Domainnamens.
  • admin@localhost: eine Domain ohne Punkt.

Ein Regex, der die gesamte Grammatik umsetzt, samt Kommentaren und Folding Whitespace, ist riesig, schwer zu prüfen und akzeptiert Adressen, die viele Mailsysteme ablehnen. jane@gmial.com lässt er trotzdem durch. SMTP (RFC 5321) ergänzt Längengrenzen: 64 Oktette für den Teil vor dem @ und 255 für die Domain, was zusammen mit der Pfadsyntax eine praktische Obergrenze von 254 Zeichen ergibt. Eine Längenprüfung ist als Code einfacher als als Regex.

Ein pragmatisches Muster

Dieses Muster brauchen die meisten Anwendungen tatsächlich: etwas ohne Leerzeichen und ohne @, genau ein @, danach eine Domain mit mindestens einem Punkt.

^[^\s@]+@[^\s@]+\.[^\s@]+$

Eine Schwäche sollten Sie beheben. Weil [^\s@] auch Punkte trifft, akzeptiert das Muster leere Domain-Labels wie in user@example..com. Schließt man den Punkt aus jedem Label aus, ist diese Lücke geschlossen:

^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$

So haben die Muster in Node 24 auf eine Reihe von Testadressen reagiert, daneben das Muster aus der HTML-Spezifikation, das der nächste Abschnitt beschreibt:

AdresseKurzes MusterLabel-MusterHTML type=email
first.last+news@example.co.ukAkzeptiertAkzeptiertAkzeptiert
o'brien@example.ieAkzeptiertAkzeptiertAkzeptiert
user@bücher.deAkzeptiertAkzeptiertAbgelehnt
δοκιμή@παράδειγμα.δοκιμήAkzeptiertAkzeptiertAbgelehnt
"john doe"@example.comAbgelehntAbgelehntAbgelehnt
admin@localhostAbgelehntAbgelehntAkzeptiert
user @example.comAbgelehntAbgelehntAbgelehnt
user@@example.comAbgelehntAbgelehntAbgelehnt
user@example..comAkzeptiertAbgelehntAbgelehnt
user@example.com.AkzeptiertAbgelehntAbgelehnt
us..er@example.comAkzeptiertAkzeptiertAkzeptiert
user@-example.comAkzeptiertAkzeptiertAbgelehnt
user@example.cAkzeptiertAkzeptiertAkzeptiert

Keines der drei Muster ist perfekt, und das muss auch keines sein. Aufeinanderfolgende Punkte im lokalen Teil und einbuchstabige Top-Level-Domains kommen durch alle drei; die fängt eine Bestätigungsmail ab. Entscheidend ist, dass keine echte, gebräuchliche Adresse abgelehnt wird.

Für die Label-Variante spricht auch die Performance. Bei einer präparierten Eingabe von 40.000 Zeichen, die mit einem Leerzeichen endet, brauchte das kurze Muster in Node wegen Backtracking etwa 2,9 Sekunden, das Label-Muster war in unter einer Millisekunde fertig. Prüfen Sie die Grenze von 254 Zeichen, bevor überhaupt ein Muster läuft, ist das Problem für beide erledigt.

Das Muster von HTML5 input type=email

Ein <input type="email"> prüft der Browser anhand einer Definition im HTML-Standard der WHATWG. Die Spezifikation bezeichnet sie selbst als bewusste Verletzung („willful violation“) von RFC 5322 und gibt diesen regulären JavaScript-Ausdruck als Implementierung an:

/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/

Er erlaubt die üblichen Satzzeichen vor dem @, verlangt Domain-Labels aus höchstens 63 Buchstaben, Ziffern und Bindestrichen, die nicht mit einem Bindestrich beginnen oder enden, und verlangt keinen Punkt, weshalb admin@localhost durchgeht. Jedes Nicht-ASCII-Zeichen lehnt er ab. Die Browserprüfung lässt sich im Skript mit input.checkValidity() oder input.validity.typeMismatch wiederverwenden. Alles, was ein Browser prüft, lässt sich aber umgehen, validieren Sie deshalb auf dem Server erneut.

Internationale Adressen

Domains dürfen Nicht-ASCII-Zeichen enthalten. bücher.de wandert als xn--bcher-kva.de durch das DNS, und new URL('http://bücher.de').hostname in JavaScript, idn_to_ascii() in PHP sowie 'bücher.de'.encode('idna') in Python liefern alle genau diese Form. Auch der Teil vor dem @ darf Nicht-ASCII-Zeichen enthalten, an solche Adressen zustellen können aber nur Mailserver, die SMTPUTF8 (RFC 6531) unterstützen.

Entscheiden Sie anhand Ihres Mailanbieters, nicht anhand eines Regex. Die Muster auf Basis von [^\s@] akzeptieren internationale Adressen, das HTML-Muster lehnt sie ab. Ebenso PHPs filter_var($email, FILTER_VALIDATE_EMAIL): In unseren Tests lehnte es sowohl user@bücher.de als auch δοκιμή@example.com ab. Mit dem Flag FILTER_FLAG_EMAIL_UNICODE akzeptierte es die zweite Adresse, lehnte die Unicode-Domain aber weiterhin ab.

Dieselbe Prüfung in JavaScript, Python und PHP

Jede Funktion entfernt umgebenden Leerraum, erzwingt die Längengrenze und verlangt, dass der gesamte String passt. Alle drei lieferten identische Ergebnisse für die Adressen oben und einige Grenzfälle: umgebender Leerraum, ein Zeilenumbruch mitten im Wert, ein geschütztes Leerzeichen im lokalen Teil und eine Adresse mit 256 Zeichen.

// JavaScript
function isValidEmail(value) {
  const email = value.trim();
  return email.length <= 254 && /^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/.test(email);
}

# Python
import re
EMAIL_RE = re.compile(r"[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+")

def is_valid_email(value: str) -> bool:
    email = value.strip()
    return len(email) <= 254 and EMAIL_RE.fullmatch(email) is not None

// PHP
function isValidEmail(string $value): bool
{
    $email = trim($value);
    return strlen($email) <= 254
        && preg_match('/^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$/Du', $email) === 1;
}

Zwei Details in diesen Snippets verhindern echte Bugs. In Python akzeptierte re.match() mit $ den Wert "user@example.com\n", weil $ auch vor einem abschließenden Zeilenumbruch passt; re.fullmatch() lehnte ihn ab. PHP verhält sich genauso, solange Sie den Modifikator D nicht setzen. Auch der Modifikator u zählt in PHP: Ohne ihn traf \s kein geschütztes Leerzeichen, und user\u{00A0}x@example.com wurde akzeptiert. In JavaScript lassen Sie das Flag g weg, wenn Sie nur test() aufrufen.

Die eigentliche Validierung ist eine Bestätigungsmail

Ein Muster kann nur sagen, dass eine Adresse plausibel aussieht. Ob das Postfach existiert, ob es Mails annimmt und ob es der Person gehört, die die Adresse eintippt, kann es nicht feststellen. Eine Abfrage der MX-Einträge zeigt, dass eine Domain für den Mailempfang eingerichtet ist, aber nicht, dass ein bestimmtes Postfach existiert. Der einzig verlässliche Test ist, eine Nachricht zu senden:

  1. Speichern Sie die Adresse als unbestätigt.
  2. Schicken Sie per E-Mail einen Link mit einem zufälligen Einmal-Token, das abläuft, zum Beispiel nach 24 Stunden.
  3. Markieren Sie die Adresse erst als bestätigt, wenn der Link geöffnet wurde.
  4. Schicken Sie bis dahin nichts anderes an diese Adresse.

Normalisieren Sie sparsam: Leerraum entfernen und die Domain in Kleinbuchstaben umwandeln. RFC 5321 behandelt den Teil vor dem @ als abhängig von Groß- und Kleinschreibung, auch wenn die meisten Anbieter sie ignorieren. Speichern Sie ihn deshalb so, wie er eingegeben wurde.

Testen Sie die Muster mit Ihrer eigenen Liste

Fügen Sie eines der Muster ohne die umgebenden Schrägstriche in den Regex-Tester ein, setzen Sie die Flags auf gm und tragen Sie Ihre Beispieladressen zeilenweise ein. Mit dem Flag m gelten ^ und $ für jede einzelne Zeile, so wird jede akzeptierte Adresse für sich hervorgehoben. Wir haben geprüft, dass diese zeilenweise Ansicht für alle drei Muster oben dieselben Ergebnisse liefert wie der Einzeltest jeder Adresse. Im Anwendungscode testen Sie dagegen eine Adresse nach der anderen ohne m, sonst könnte ein mehrzeiliger Wert durchgehen, nur weil eine seiner Zeilen passt.

Häufige Fragen

Welches Regex eignet sich am besten zur E-Mail-Validierung?

Für die meisten Formulare ^[^\s@]+@[^\s@.]+(?:\.[^\s@.]+)+$ zusammen mit einer Längenprüfung auf 254 Zeichen. Es lehnt Leerzeichen, fehlende oder doppelte @-Zeichen und leere Domain-Labels ab, ohne internationale Adressen abzuweisen. Bestätigen Sie die Adresse danach per E-Mail.

Warum kein vollständiges RFC-5322-Regex?

Weil es Strings in Anführungszeichen, Kommentare und IP-Adressen als Domain akzeptiert, die die meisten Systeme ablehnen, sehr schwer zu pflegen ist und trotzdem weder Tippfehler wie gmial.com erkennt noch feststellen kann, ob das Postfach existiert.

Reicht input type=email aus?

Als erste Prüfung im Browser ist es gut, aber es lehnt Nicht-ASCII-Adressen ab, akzeptiert Domains ohne Punkt und lässt sich umgehen. Validieren Sie immer zusätzlich auf dem Server.

Wie prüfe ich, ob eine E-Mail-Adresse wirklich existiert?

Schicken Sie eine Bestätigungsmail mit einem Einmal-Link und behandeln Sie die Adresse erst als bestätigt, wenn der Link geöffnet wurde. Syntaxprüfungen und MX-Abfragen können nicht beweisen, dass ein Postfach existiert oder dem Nutzer gehört.
Direkt ausprobieren: Regex-Tester