Anleitung · PHP & Laravel

E-Mail-Validierung in PHP: von filter_var bis zur Postfachprüfung

PHP bringt eine E-Mail-Validierung mit, die aber beim Format aufhört. Diese Anleitung geht bis zum Postfach: filter_var und eine strengere Regex, eine DNS-Prüfung, die Null-MX erkennt, ein API-Aufruf mit cURL und dieselben Prüfungen als Laravel-Validierungsregel.

Aktualisiert am 29. Oktober 2026 · 11 Min. Lesezeit

E-Mail-Adresse in PHP mit filter_var und FILTER_VALIDATE_EMAIL validieren

Die E-Mail-Validierung in PHP beginnt mit einer eingebauten Funktion, filter_var($email, FILTER_VALIDATE_EMAIL), und in vielen Projekten endet sie dort auch. Diese Funktion prüft das Format und sonst nichts: Eine Adresse auf einer Domain, die nicht existiert, oder für ein Postfach, das nie angelegt wurde, besteht. Diese Anleitung ergänzt die fehlenden Prüfungen in der Reihenfolge, in der sie laufen, mit Code, den wir unter PHP 8.5 ausgeführt haben: eine strengere Formatprüfung, eine DNS-Prüfung, eine Postfachprüfung über eine API und dieselben Schritte als Laravel-Validierungsregel.

1. Formatprüfung mit filter_var

<?php
$email = is_string($_POST['email'] ?? null) ? trim($_POST['email']) : '';

if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
    http_response_code(422);
    exit('Bitte geben Sie eine gültige E-Mail-Adresse ein.');
}

Entfernen Sie Leerzeichen vor der Prüfung: In unserem Test lehnte filter_var eine Adresse mit einem Leerzeichen davor ab, und Nutzer fügen Adressen oft mit Leerzeichen ein. Die Prüfung mit is_string() verhindert, dass eine Anfrage mit email[]=… ein Array liefert, bei dem trim() einen TypeError wirft.

Laut PHP-Handbuch prüft FILTER_VALIDATE_EMAIL die Adresssyntax aus RFC 822, ohne Kommentare, Whitespace-Folding und Domainnamen ohne Punkt. In der Praxis bleiben ein paar Lücken (alle Ergebnisse in der Tabelle in Schritt 2):

2. Eine strengere Prüfung mit preg_match

Für eine Regel, die Sie selbst in der Hand haben, nutzen Sie das getestete Muster aus unserem englischen Leitfaden zur E-Mail-Regex. normalizeEmail entfernt Leerzeichen am Rand und wandelt eine internationale Domain mit idn_to_ascii() aus der intl-Erweiterung in Punycode um:

<?php // validate.php
const EMAIL_REGEX = '/\A(?=.{1,254}\z)(?=.{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})\z/';

function isValidEmail(string $email): bool
{
    return preg_match(EMAIL_REGEX, $email) === 1;
}

// Entfernt Leerzeichen am Rand und wandelt eine internationale Domain in Punycode um (braucht ext-intl).
function normalizeEmail(string $input): string
{
    $email = trim($input);
    $at = strrpos($email, '@');
    if ($at === false || $at === 0) {
        return $email; // lehnt isValidEmail ab
    }
    $domain = idn_to_ascii(substr($email, $at + 1), IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
    return $domain === false ? $email : substr($email, 0, $at + 1) . $domain;
}

Das Muster ist mit \A und \z verankert. Mit ^ und $ akzeptiert preg_match eine Adresse mit nachfolgendem Zeilenumbruch, weil $ auch vor einem abschließenden Newline passt.

Jede Adresse unten lief unter PHP 8.5.12 durch jede Prüfung, die beiden Laravel-Spalten mit illuminate/validation 13.39. ✓ heißt, die Prüfung nimmt die Adresse an, ✗, dass sie sie ablehnt.

AdresseSoll bestehen?filter_varRegexnormalizeEmail + RegexLaravel emailLaravel email:strict,filter
jane@example.comJa✓✓✓✓✓
jane.doe+news@example.comJa✓✓✓✓✓
o'brien@example.ieJa✓✓✓✓✓
jane@xn--bcher-kva.exampleJa✓✓✓✓✓
jane@bücher.exampleNach IDN-Umwandlung✗✗✓✓✗
jane.@example.comNein✗✗✗✗✗
jane..doe@example.comNein✗✗✗✗✗
jane@exampleNein✗✗✗✓✗
jane@example.cNein✓✗✗✓✓
jane@-example.comNein✗✗✗✗✗
jane@exa_mple.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)✗✗✗✓✗
aaa…a@example.com (65 a)Nein✗✗✗✓✗
jane@example.com mit Leerzeichen am RandNach dem Trimmen✗✗✓✗✗
jane@example.com + ZeilenumbruchNein✗✗✓ (getrimmt)✗✗

normalizeEmail entfernt Leerzeichen und Zeilenumbruch, was Sie bei eingefügten Adressen wollen. Die einfache Laravel-Regel email ist die großzügigste Prüfung in der Tabelle; Schritt 6 zeigt, welche Optionen sie strenger machen.

3. Nimmt die Domain E-Mails an?

Die übliche PHP-Antwort ist checkdnsrr($domain, 'MX'), und sie hat eine Lücke: Sie fragt nur, ob ein MX-Eintrag existiert. Eine Domain, die keine E-Mails empfängt, kann das mit einem Null-MX sagen, einem einzelnen MX-Eintrag mit dem Ziel . (RFC 7505). checkdnsrr('example.com', 'MX') lieferte in unserem Test true, obwohl example.com genau diesen Eintrag veröffentlicht, und getmxrr() gab ihn als einen Host mit leerem Namen zurück. Lesen Sie die Einträge deshalb mit dns_get_record():

<?php // mx.php
// true: die Domain nimmt E-Mails an; false: nicht; null: DNS gab keine klare Antwort.
function acceptsMail(string $domain): ?bool
{
    $mx = @dns_get_record($domain, DNS_MX);
    if ($mx === false) {
        return null; // die Abfrage schlug fehl: unbekannt, nicht ablehnen
    }
    if ($mx !== []) {
        // Ein einzelner MX-Eintrag mit leerem Ziel ist ein Null-MX (RFC 7505): keine E-Mails.
        return !(count($mx) === 1 && $mx[0]['target'] === '');
    }
    // Kein MX-Eintrag: Absender stellen an den A- oder AAAA-Eintrag der Domain zu (impliziter MX).
    $addresses = @dns_get_record($domain, DNS_A | DNS_AAAA);
    return $addresses === false ? null : $addresses !== [];
}

Gegen das öffentliche DNS:

DomainDNScheckdnsrr($d, 'MX')acceptsMail
gmail.comFünf MX-Einträgetruetrue
example.comNull-MXtruefalse
neverssl.comA-Eintrag, kein MXfalsetrue
Eine Domain, die nicht existiertNXDOMAINfalsefalse
dnssec-failed.orgSERVFAILfalsefalse

Die letzte Zeile zeigt eine Grenze der DNS-Funktionen von PHP: Sie nutzen den Resolver des Systems, haben keine Einstellung für Zeitlimits, und dns_get_record() lieferte in unserem Test für ein SERVFAIL dasselbe leere Array wie für eine nicht existierende Domain. false kann also gelegentlich „DNS ist ausgefallen“ bedeuten. Nutzen Sie das Ergebnis, um offensichtliche Tippfehler in der Domain abzufangen, und überlassen Sie die Entscheidung der Postfachprüfung, die eine tote Domain als invalid mit dem Grund invalid_mx meldet. Mit dem MX-Lookup prüfen Sie eine Domain von Hand.

4. Das Postfach per API prüfen

Nur der Mailserver des Empfängers weiß, ob anna@example.org existiert. Ihn selbst zu fragen, braucht 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. Mit der cURL-Erweiterung von PHP:

<?php // check-mailbox.php
// Liefert das Ergebnis der API oder null, wenn die Prüfung nicht möglich war
// (API nicht erreichbar oder langsam, falscher Schlüssel, Kontingent aufgebraucht). Braucht ext-curl.
function checkMailbox(string $email): ?array
{
    $key = getenv('EMAILVALIDATION_KEY');
    if ($key === false || $key === '') {
        throw new RuntimeException('EMAILVALIDATION_KEY is not set');
    }

    $url = 'https://api.emailvalidation.io/v1/info?' . http_build_query(['email' => $email, 'timeout' => 8]);
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_TIMEOUT => 10, // die API antwortet innerhalb von 8 Sekunden
        CURLOPT_HTTPHEADER => ['apikey: ' . $key],
    ]);
    $body = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

    if ($body === false || $status !== 200) {
        error_log(sprintf('email check skipped: HTTP %d %s', $status, $body === false ? curl_error($ch) : $body));
        return null;
    }
    return json_decode($body, true, flags: JSON_THROW_ON_ERROR);
}

Was der Code erledigt:

Die Antwort hat 21 Felder. Entscheiden Sie anhand von status:

statusBeispiele für sub_statusrecommended_actionWas tun
validnull, role_based, possible_typosend, send_with_cautionAnnehmen; did_you_mean anzeigen, wenn es nicht leer ist.
invalidmailbox_not_found, no_dns_entriessuppressAblehnen 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 ist 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; die Seite Result Statuses (Englisch) ordnet sie einander zu, und Catch-all-E-Mail-Adressen erklärt, warum sich manche Domains nicht Postfach für Postfach prüfen lassen.

Das offizielle SDK (composer require everapi/emailvalidation-php, auf Basis von Guzzle) sendet dieselbe Anfrage: (new \Emailvalidation\EmailvalidationClient($key, ['timeout' => 10]))->validate($email). In Version 1.0 wirft es bei Netzwerkfehlern und Zeitüberschreitungen eine EmailvalidationException, gibt den Fehlertext einer 401- oder 429-Antwort aber als normales Array zurück. Prüfen Sie also, ob das Ergebnis ein Feld status hat, bevor Sie es verwenden.

5. Alles zusammen in einem Anmeldeskript

<?php // signup.php
require __DIR__ . '/validate.php';
require __DIR__ . '/check-mailbox.php';

$email = normalizeEmail(is_string($_POST['email'] ?? null) ? $_POST['email'] : '');
if (!isValidEmail($email)) {
    http_response_code(422);
    exit('Bitte geben Sie eine gültige E-Mail-Adresse ein.');
}

$result = checkMailbox($email); // null: Die API konnte nicht antworten, also Adresse annehmen
if (($result['status'] ?? null) === 'invalid') {
    http_response_code(422);
    exit('Diese E-Mail-Adresse existiert nicht. Bitte prüfen Sie sie.');
}
if (($result['status'] ?? null) === 'do_not_mail') {
    http_response_code(422);
    exit('Bitte verwenden Sie eine dauerhafte E-Mail-Adresse.');
}

// Konto anlegen ...
http_response_code(201);
echo 'Danke für Ihre Anmeldung.';

Wir haben das Skript mit dem eingebauten Webserver von PHP ausgeliefert, checkMailbox auf eine lokale Nachbildung der API mit dem dokumentierten Antwortformat gerichtet und Formulardaten gesendet:

Gesendetes emailAntwort
anna@example.org201
anna@example.org mit Leerzeichen am Rand201
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
Kein Feld email oder email[]=…422
Beliebige Adresse, während die API 429 antwortet201, protokolliert

Die API-Prüfung lässt im Zweifel absichtlich durch: Ist die API langsam, nicht erreichbar oder das Kontingent aufgebraucht, geht die Anmeldung durch. Ein Ausfall der Validierung soll Sie nie einen Kunden kosten.

6. E-Mail-Validierung in Laravel

Die Laravel-Regel email nimmt eine Liste von Validatoren, die alle bestehen müssen. Die wichtigen:

RegelWas sie ergänzt
email oder email:rfcRFC-Prüfung (egulias/email-validator). Der Standard.
email:strictRFC-Prüfung ohne die Warnungen, die sie sonst toleriert: In unserem Test lehnte sie jane@example, lokale Teile in Anführungszeichen, IP-Adressen in eckigen Klammern und lokale Teile mit 65 Zeichen ab.
email:filterPHPs filter_var wie in Schritt 1.
email:dnsPrüft die MX-Einträge der Domain; sie lehnte example.com (Null-MX) ab und nahm neverssl.com (nur A-Eintrag) an.
email:spoofLehnt Adressen mit irreführenden Unicode-Zeichen ab, die andere Buchstaben nachahmen (braucht die intl-Erweiterung).

email:strict,filter,dns kombiniert die strenge Formatprüfung mit einer DNS-Prüfung. Um auch das Postfach zu prüfen, ergänzen Sie eine eigene Regel:

<?php // app/Rules/Deliverable.php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class Deliverable implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        try {
            $result = Http::withHeaders(['apikey' => config('services.emailvalidation.key')])
                ->connectTimeout(5)
                ->timeout(10)
                ->get('https://api.emailvalidation.io/v1/info', ['email' => $value, 'timeout' => 8])
                ->throw()
                ->json();
        } catch (ConnectionException|RequestException $e) {
            Log::warning('email check skipped: ' . $e->getMessage());
            return; // API ausgefallen, langsam oder Kontingent aufgebraucht: Adresse durchlassen
        }

        match ($result['status'] ?? null) {
            'invalid' => $fail('Diese E-Mail-Adresse existiert nicht. Bitte prüfen Sie sie.'),
            'do_not_mail' => $fail('Bitte verwenden Sie eine dauerhafte E-Mail-Adresse.'),
            default => null,
        };
    }
}

Legen Sie den Schlüssel als EMAILVALIDATION_KEY in .env ab und lesen Sie ihn in config/services.php aus, damit config:cache weiter funktioniert:

'emailvalidation' => [
    'key' => env('EMAILVALIDATION_KEY'),
],

Dann nutzen Sie die Regel in einem Controller oder Form Request. bail stoppt bei der ersten fehlgeschlagenen Regel, eine Adresse mit falschem Format erreicht die API also nie:

$request->validate([
    'email' => ['bail', 'required', 'email:strict,filter', new Deliverable],
]);

Wir haben die Regel mit illuminate/validation und illuminate/http 13.39 gegen die Nachbildung ausgeführt: Eine existierende Adresse bestand, Adressen mit invalid und do_not_mail scheiterten mit den beiden Meldungen, eine Catch-all-Adresse bestand, jane@example scheiterte an der Formatprüfung ohne API-Anfrage, und eine API, die 429 antwortete oder länger als 10 Sekunden brauchte, ließ die Adresse mit einer Warnung im Log durch. Die Regel braucht Laravel 10 oder neuer, wo ValidationRule eingeführt wurde.

WordPress: WooCommerce und Gravity Forms

Derselbe API-Aufruf funktioniert in WordPress-Plugins. Für Shops ergänzt die WooCommerce-E-Mail-Prüfung beim Checkout (Englisch) ihn im klassischen Checkout und im Checkout-Block; für Kontakt- und Lead-Formulare zeigt der Gravity-Forms-Filter (Englisch) einen Fehler am E-Mail-Feld, bevor der Eintrag gespeichert wird.

Empfohlener Aufbau

  1. Bei der Eingabe: normalizeEmail, dann isValidEmail, oder in Laravel email:strict,filter.
  2. Optional eine DNS-Prüfung mit acceptsMail oder email:dns, um tote Domains ohne API-Aufruf abzufangen.
  3. Beim Absenden: die Postfachprüfung. Blockieren Sie invalid und do_not_mail, nehmen Sie alles andere an, und nehmen Sie die Adresse an, wenn die API nicht erreichbar ist.
  4. 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 erlaubt 10 Anfragen pro Minute und 5 gleichzeitige Prüfungen, bezahlte Tarife 25 gleichzeitig ohne Minutenlimit.

Der kostenlose Tarif enthält 100 Prüfungen im Monat; mehr unter Preise der E-Mail-Validierungs-API. Dieselben Prüfungen in anderen Sprachen: E-Mail-Validierung in JavaScript und E-Mail-Validierung in Python.

Quellen

Geprüft am 29. Oktober 2026: PHP-Handbuch: Filter-Konstanten, checkdnsrr, dns_get_record, idn_to_ascii, curl_close; Laravel-Dokumentation: Validierung, Regel email, eigene Regeln, HTTP-Client; RFC 7505 (Null-MX); API-Dokumentation von emailvalidation.io: Validierungs-Endpunkt, Rate Limits. Code ausgeführt mit PHP 8.5.12 (Erweiterungen cURL und intl), illuminate/validation und illuminate/http 13.39, gegen das öffentliche DNS und eine lokale Nachbildung der API.

E-Mail-Validierung in anderen Sprachen

Häufig gestellte Fragen

Reicht filter_var mit FILTER_VALIDATE_EMAIL?

Es ist eine solide Formatprüfung, akzeptierte in unserem Test aber jane@example.c und jane@[192.0.2.10] und kann nicht erkennen, ob die Domain existiert oder das Postfach je angelegt wurde. Entfernen Sie zuerst Leerzeichen am Rand, und prüfen Sie bei Anmeldungen und Importen zusätzlich das Postfach, etwa mit einer E-Mail-Validierungs-API.

Warum liefert checkdnsrr true für eine Domain, die keine E-Mails annimmt?

Eine Domain, die keine E-Mails empfängt, kann einen Null-MX veröffentlichen: einen MX-Eintrag mit dem Ziel . (RFC 7505). checkdnsrr($domain, 'MX') fragt nur, ob es einen MX-Eintrag gibt, und liefert für solche Domains deshalb true, auch für example.com. Lesen Sie die Einträge mit dns_get_record() und behandeln Sie einen einzelnen Eintrag mit leerem Ziel als „keine E-Mails“.

Wie prüfe ich in Laravel die DNS-Einträge einer E-Mail-Domain?

Nutzen Sie die Regel email:rfc,dns oder ergänzen Sie dns in der Liste der Validatoren, etwa email:strict,filter,dns. Die DNS-Prüfung lehnte in unserem Test eine Domain mit Null-MX ab. Ob das Postfach existiert, prüft sie nicht; das leistet eine eigene Regel, die eine API aufruft.

Welche Laravel-Regel für E-Mail-Adressen soll ich verwenden?

email allein führt die RFC-Prüfung aus, die in unserem Test jane@example, lokale Teile in Anführungszeichen und IP-Adressen in eckigen Klammern annahm. email:strict,filter lehnte alle drei ab und stimmte bei jeder Testadresse außer jane@example.c mit unserer Regex überein.

Brauche ich noch curl_close()?

Nein. Ein cURL-Handle ist seit PHP 8.0 ein Objekt, das PHP selbst freigibt, und PHP 8.5 markiert curl_close() als veraltet. Ein Aufruf unter PHP 8.5 erzeugt einen Deprecation-Hinweis.

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