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. ob eine positive DNS-Antwort im Falle einer Domain-DNS-Prüfung vorliegt.

Des Weiteren erhebt dieses Tutorial nicht den Anspruch, sämtlichen RFCs zu diesem Thema zu genügen. Auch viele der großen Provider und E-Mail-Anbieter befolgen nicht alle RFCs.

filter_var

PHP stellt ab Version 5.2 die Funktion filter_var zur Verfügung. Mit dem 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

Sollte filter_var nicht eingesetzt werden können, gibt es auf dieser Seite unten (vorletzter Absatz) einen zu RFC 2822 empfohlenen regulären Ausdruck.

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

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

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 der 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

RFCs 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 mermshaus 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, mermshaus