PHP.de Wissenssammlung

Standard E-Mail-Validierung

filter_var()
als Standard-Weg
Internationale Domainnamen / Punycode
Domains mit Sonderzeichen
Ohne Punycode
Lose Rahmenprüfung durch reguläre Ausdrücke
DNS Domain-Prüfung
zusätzliche Existenz-Prüfung
Weiterführende Quellen
Links und RFCs

Dieses Tutorial zeigt grundsätzliche (übliche) Möglichkeiten, eine E-Mail-Adresse (wie sie für den Transport per SMTP im Internet verwendet wird, bestehend aus zwei Teilen, die durch ein @-Zeichen voneinander getrennt sind) zu validieren.

Vorweg sei an dieser Stelle erwähnt, dass eine Prüfung auf tatsächliche Existenz einer E-Mail-Adresse auf diesem Weg nicht möglich ist. Die nachfolgenden Ansätze dienen lediglich zur Feststellung ob die grundlegenden formellen Rahmenbedingungen erfüllt werden bzw. einer positiven DNS-Antwort im Falle einer Domain-DNS-Prüfung.

Des Weiteren erhebt dieses Tutorial nicht den Anspruch, sämtlichen RFC zu diesem Thema zu genügen (wenn sich schon die meisten großen Provider und Mail-Anbieter nicht daran halten …).

filter_var()

PHP stellt ab Version 5.2 die Funktion filter_var() zur Verfügung. Mit dem optionalen Parameter FILTER_VALIDATE_EMAIL kann diese grundsätzlich zur E-Mail-Validierung verwendet werden. Jedoch ist es damit nicht möglich internationalisierte E-Mail-Adressen zu prüfen - solche werden immer als falsch ausgewertet. Lösungsansätze folgen weiter unten.

function isValidEmail($mail) {
    return (bool) filter_var($mail, FILTER_VALIDATE_EMAIL);
}

var_dump(isValidEmail("test@example.com"));  // true
var_dump(isValidEmail("pelé@example.com"));  // false
var_dump(isValidEmail("mail@übung.de"));     // false

Hinweis

Sollte filter_var() nicht verfügbar sein, dann den Provider kontaktieren (oder wechseln ;)). Im ungünstigsten Fall gibt es auf dieser Seite unten (vorletzter Absatz) ein zu RFC 2822 empfohlenen regulären Ausdruck (Regex).

We get a more practical implementation of RFC 2822 if we omit the syntax using double quotes and square brackets. It will still match 99.99% of all email addresses in actual use today.

function isValidEmail($mail) {
    $pattern = '#[a-z0-9!\\#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!\#$%&\'*+/=?^_`{|}~-]+)*'
             . '@'
             . '(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?#i';
    return (bool) preg_match($pattern, $mail);
}

var_dump(isValidEmail("test@example.com"));  // true
var_dump(isValidEmail("pelé@example.com"));  // false
var_dump(isValidEmail("mail@übung.de"));     // false

Dies kann alternativ zu filter_var() verwendet werden. Ebenso wie oben bei filter_var() schlägt die Prüfung von internationalisierten Domains fehl (was hier bereits am Pattern erkennbar ist).

Internationalisierte Domainnamen (IDN)

Um auch internationalisierte Domains / E-Mail-Adressen auf grundsätzliche formelle Korrektheit zu prüfen ist die Konvertierung in Punycode vor der eigentlichen Prüfung nötig. Weitere Informationen und Möglichkeiten zur Konvertierung gibt es hier.

Ohne Punycode - Lose Rahmenprüfung mittels regulären Ausdrücken (Regex)

Diese Variante kommt ohne Punycode-Konvertierung aus. Hierbei spielen die verwendeten Zeichen kaum eine Rolle, denn es wird nur der grobe Rahmen geprüft und ob keine Whitespaces (Leerzeichen, Tabstopps, etc.) vorhanden sind.

function isValidEmail($mail) {
    // Gesamtlänge check
    // http://de.wikipedia.org/wiki/E-Mail-Adresse#L.C3.A4nge_der_E-Mail-Adresse
    if (strlen($mail) > 256) {
        return false;
    }
    $pattern = '#^'
             . '\S+'
             . '@'
             . '(?:[^\s.](?:[^\s.]*[^\s.])?\\.)+[^\s.](?:[^\s.]*[^\s.])?'
             . '$#i';
    return (bool) preg_match($pattern, $mail);
}

var_dump(isValidEmail("test@.....com"));                              // false
var_dump(isValidEmail("test@sub.mail.dot.anything.example.com"));     // true
var_dump(isValidEmail("test@übärdrübär.com"));                        // true
var_dump(isValidEmail("test@sub.mail.dot.anything.übärdrübär.com"));  // true

Zusatz-Option: DNS-Domain-Prüfung

Generell kann in jeder oben angeführten Varianten, wenn gewüscht, die Antwort des DNS zur Domain (auf vorhandenen “MX” oder “A”-Record) berücksichtigt werden.

Hinweis: Die an das DNS übergebene Domain der E-Mail-Adresse muss für die Verwendung von internationalisierten Domains (wie bei filter_var()) ebenfalls in Punycode konvertiert sein.

function checkEMailDomainDNS($mail) {
    $parts = explode('@', $mail);
    return (checkdnsrr($parts[1], "MX") or checkdnsrr($parts[1], "A"));
}

var_dump(checkEMailDomainDNS('mail@example.com'));  // true

Weiterführende Quellen

Wer sich genauer für die Regex-Prüfung interessiert, dem sei dieser Link empfohlen. Danke an Trainmaster für den Link.

Wer sich dafür interessiert wie eigentlich filter_var() validiert, dem sei ein Blick in den Quelltext von PHP empfohlen oder etwas einfacher hier in diesem Forumsbeitrag. Danke an Asterixus für die Recherche.

RFC zum Thema E-Mail

  • RFC 2142 - Mailbox Names for Common Services, Roles and Functions
  • RFC 2368 - The mailto URL scheme
  • RFC 2822 - Internet Message Format
  • RFC 3696 - Application Techniques for Checking and Transformation of Names
  • RFC 4021 - Registration of Mail and MIME Header Fields
  • RFC 5321 - Simple Mail Transfer Protocol
  • RFC 5322 - Internet Message Format
  • RFC 5335 - Internationalized Email Headers

Dieser Beitrag wird zur Zeit diskutiert und wurde zuletzt von tr0y verändert.

Beiträge die zur Diskussion gestellt werden, enthalten mitunter Informationen bei denen wir uns noch bezüglich der finalen Darstellung absprechen müssen. Gedulde dich etwas, wir stellen diesen Beitrag fertig, sobald die Diskussion beendet ist.

An diesem Beitrag waren bisher beteiligt: hausl, tr0y