Skip to content
Starten Sie mit 100 kostenlosen Verifizierungs-Credits
Qualisend
Alle Artikel
Engineering / 22. Juli 2026

E-Mail-Adresse in PHP validieren – so geht es richtig

7 minutes read

Qualisend team
Ein geschichtetes Diagramm einer PHP-E-Mail-Adresse, die eine filter_var-Syntaxvalidierung, eine checkdnsrr-MX-Abfrage und eine SMTP-Postfachprüfung durchläuft und sich zu einem einzigen Zustellbarkeitsurteil verengt

Die Validierung einer E-Mail-Adresse in PHP beginnt und endet üblicherweise mit einer Zeile: filter_var($email, FILTER_VALIDATE_EMAIL). Sie ist integriert, sie ist schnell und sie ist wirklich nützlich – doch sie beantwortet nur die erste der drei Fragen, die echte Validierung stellt. Ist die Adresse korrekt geformt? Kann ihre Domain Mail empfangen? Existiert das Postfach tatsächlich? Die Standardbibliothek von PHP beantwortet die ersten beiden von Haus aus; die dritte ist ein Netzwerkproblem, das man besser auslagert. Dieser Leitfaden baut die PHP-E-Mail-Validierung in Ebenen auf, mit funktionierendem Code für jede, und zeigt genau, wo filter_var aufhört.

Die kurze Antwort#

Verwenden Sie filter_var() mit FILTER_VALIDATE_EMAIL für die Syntax, checkdnsrr() oder getmxrr() für die MX-Abfrage und eine Verifizierungs-API für die SMTP-Postfachprüfung – die günstigste zuerst, mit Abbruch, sobald eine davon entscheidend ist. Versuchen Sie nicht, aus PHP heraus eine SMTP-Sitzung zu öffnen, um Postfächer selbst zu prüfen: Der ausgehende Port 25 ist auf den meisten Hosts gesperrt, und die Antwort hängt von der Reputation der sendenden IP und vom Greylisting ab, das Sie nicht selbst nachbauen wollen. Jede Ebene sortiert Adressen günstiger aus als die vorherige; nur die letzte kann eine Adresse einschließen.

Ebene 1: Syntax mit filter_var#

Für PHP ist filter_var das richtige Werkzeug für Ebene eins – es erspart Ihnen das Basteln einer eigenen Regex und ist besser getestet als alles, was Sie von Stack Overflow einfügen würden. FILTER_VALIDATE_EMAIL gibt bei Erfolg die Adresse zurück und bei Misserfolg false, vergleichen Sie also strikt:

function is_valid_syntax(string $email): bool
{
    return strlen($email) <= 320
        && filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
is_valid_syntax('jane@example.com'); // true
is_valid_syntax('not-an-email');     // false
is_valid_syntax('a@@b.com');         // false

Das strikte !== false ist entscheidend. filter_var gibt bei Erfolg die gefilterte Zeichenkette zurück, nicht true, ein lockeres if (filter_var(...)) funktioniert also nur, weil eine nicht leere Zeichenkette truthy ist – der Vergleich gegen false sagt, was Sie meinen, und übersteht Refactorings. Der Längen-Guard ist doppelt abgesichert: Eine Adresse mit mehr als 320 Zeichen kann keine echte sein, und es ist günstiger, sie früh abzulehnen, als eine riesige Zeichenkette an irgendetwas nachgelagertes weiterzureichen.

Wissen Sie, was dieser Filter tut und was nicht. Standardmäßig validiert er gegen eine RFC-abgeleitete Grammatik und lehnt internationalisierte (Unicode-)Local-Parts ab – 用户@example.com scheitert also, sofern Sie nicht ab PHP 7.1 das Flag FILTER_FLAG_EMAIL_UNICODE hinzufügen. Es ist ein Syntax-Filter, Punkt: Er berührt niemals DNS, öffnet niemals einen Socket und hat keine Ahnung, ob example.com existiert. Beachten Sie außerdem, dass FILTER_SANITIZE_EMAIL ein anderes Kaliber ist – es entfernt unzulässige Zeichen und gibt eine verstümmelte Zeichenkette zurück statt einer Ja/Nein- Antwort, greifen Sie also nicht dazu, wenn Sie validieren wollen.

Warum ein bestandener filter_var-Test kein grünes Licht ist#

Ein bestandener filter_var-Test bedeutet, dass die Zeichenkette wie eine E-Mail-Adresse geformt ist. Er sagt nichts darüber aus, ob Mail ankommen wird. definitely-fake@gmail.com besteht. info@company-that-folded.com besteht. typo@gmial.com besteht. Alle drei sind unzustellbar, und kein noch so ausgefeilter Mustervergleich – weder filter_var noch die aufwendigste Regex, die Sie finden – wird Ihnen das je verraten, denn Syntax und Zustellbarkeit sind verschiedene Fragen. Die eine ist eine Tatsache über die Zeichenkette; die andere eine Tatsache über das Internet. Das ist dieselbe Falle, die Regex-E-Mail-Validierung scheitern lässt, und filter_var steht auf genau derselben Seite der Linie.

Wenn Sie die Lücke selbst sehen möchten, fügen Sie eine syntaktisch perfekte Adresse in den kostenlosen E-Mail-Checker ein und beobachten Sie, wie eine von filter_var gebilligte Zeichenkette als undeliverable zurückkommt.

Ebene 2: Kann die Domain Mail empfangen?#

Hier verdient sich PHP seinen Lohn ganz ohne Abhängigkeiten. Eine Domain ohne Mailroute kann für niemanden Mail annehmen, diese eine Abfrage eliminiert also tote Domains, falsch geschriebene Firmennamen und erfundene TLDs. Die schnellste Prüfung ist checkdnsrr(), das einen Boolean dafür zurückgibt, ob ein bestimmter Eintragstyp existiert:

function has_mail_route(string $domain): bool
{
    // checkdnsrr() returns true if the domain publishes at least one MX record.
    // Fall back to A for domains that accept mail on an implicit MX.
    return checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A');
}
has_mail_route('gmail.com');               // true
has_mail_route('company-that-folded.com'); // false

Trennen Sie die Domain mit strrpos von der Adresse ab, damit Sie immer am letzten @ schneiden:

$domain = substr($email, strrpos($email, '@') + 1);

Wenn Sie die tatsächlichen Mail-Hosts statt eines Ja/Nein benötigen – etwa um sie zu protokollieren oder die Prioritäten zu prüfen –, greifen Sie zu getmxrr(). Es füllt per Referenz ein Hosts-Array und ein passendes Gewichtungs-Array und gibt false zurück, wenn überhaupt kein MX-Eintrag vorhanden ist:

function mail_hosts(string $domain): array
{
    $hosts = [];
    $weights = [];
    if (!getmxrr($domain, $hosts, $weights)) {
        return [];
    }
    array_multisort($weights, $hosts); // lowest weight = highest priority
    return $hosts; // e.g. ['gmail-smtp-in.l.google.com', 'alt1.gmail-smtp-in.l.google.com', ...]
}

Ebene 3: Existiert das Postfach tatsächlich?#

Ebene eins und zwei können eine Adresse nur aussortieren. Eine Domain kann perfekte MX-Einträge veröffentlichen und trotzdem kein Postfach unter der Adresse haben, die Sie in Händen halten – noreply-9f2x@gmail.com ist syntaktisch gültig auf einer Domain mit aktiver Mailroute und ist dennoch ein Postfach, das nie angelegt wurde. Zu bestätigen, dass ein bestimmtes Postfach existiert, bedeutet die SMTP-Zustellkonversation: eine Verbindung zum Mail-Host aufbauen, RCPT TO absetzen, die Antwort lesen und die Verbindung trennen, bevor irgendetwas gesendet wird. Es steckt mehr dahinter – wie E-Mail-Verifizierung funktioniert durchläuft die gesamte Pipeline, einschließlich Catch-All-Domains, die jede Adresse annehmen und eine naive Prüfung aushebeln.

Im Prinzip können Sie das in PHP mit fsockopen() und rohen SMTP-Befehlen skripten. In der Praxis sollten Sie es nicht von Ihrem Anwendungsserver aus ausführen: Die meisten Cloud-Anbieter sperren den ausgehenden Port 25, die Antwort hängt von der Reputation der IP ab, von der aus Sie verbinden, und empfangende Server betreiben Greylisting und Rate-Limiting bei unbekannten Absendern – eine Prüfung, die im lokalen Test funktioniert, scheitert also in der Produktion still oder bringt Sie auf eine Blockliste. Das ist die Ebene, die sich zu delegieren lohnt.

Die vollständige Prüfung mit einer API#

Qualisends POST /verify durchläuft die gesamte Pipeline – Syntax, DNS und die SMTP-Postfachprüfung – von einer reputationsverwalteten, dafür gebauten Infrastruktur aus und gibt ein Urteil zurück. Ganz ohne Framework deckt ein kleiner cURL-Helfer jeden Aufruf ab, den Sie machen werden:

const QUALISEND_BASE = 'https://app.qualisend.com/api/v1';

function qualisend(string $method, string $path, ?array $body = null): array
{
    $ch = curl_init(QUALISEND_BASE . $path);
    curl_setopt_array($ch, [
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => [
            'Authorization: Bearer ' . getenv('QUALISEND_API_KEY'),
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => $body !== null ? json_encode($body) : null,
        CURLOPT_TIMEOUT    => 10,
    ]);

    $raw    = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($raw === false || $status >= 400) {
        throw new RuntimeException("Qualisend responded {$status}");
    }
    return json_decode($raw, true);
}

function verify(string $email): array
{
    return qualisend('POST', '/verify', ['email' => $email]);
}

Wenn Sie bereits Guzzle verwenden, ist dieselbe Anfrage ein paar Zeilen kürzer und übernimmt JSON und Fehlerstatuscodes für Sie:

use GuzzleHttp\Client;

$http = new Client(['base_uri' => 'https://app.qualisend.com/api/v1/']);

$response = $http->post('verify', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('QUALISEND_API_KEY')],
    'json'    => ['email' => 'jane@example.com'],
    'timeout' => 10,
]);
$result = json_decode((string) $response->getBody(), true);

Die lokalen Prüfungen kommen sofort zurück, während die SMTP-Prüfung in die Warteschlange gestellt wird:

{
  "job_id": "6f1c2e0a-9b3d-4a1e-8c77-1a2b3c4d5e6f",
  "probe_queued": true,
  "result": {
    "email": "jane@example.com",
    "status": "deliverable",
    "score": 95,
    "sub_flags": { "role": false, "disposable": false, "free": false, "catch_all": false },
    "did_you_mean": null,
    "smtp": "pending",
    "reason": null
  }
}

Für die Live-Validierung bei der Registrierung reicht das unmittelbare result in der Regel als Handlungsgrundlage aus – undeliverable ablehnen, die did_you_mean-Korrektur anbieten, disposable markieren. Wenn Sie das per SMTP bestätigte Urteil benötigen, fragen Sie den Job ab, bis die Prüfung abgeschlossen ist:

function verify_and_wait(string $email, int $tries = 10, float $delay = 1.5): ?array
{
    $jobId = verify($email)['job_id'];

    for ($i = 0; $i < $tries; $i++) {
        $job = qualisend('GET', "/jobs/{$jobId}?include=results");
        if ($job['status'] === 'completed') {
            return $job['results'][0]; // ['status' => ..., 'score' => ..., 'reason' => ...]
        }
        usleep((int) ($delay * 1_000_000));
    }
    return null; // still processing — treat as unknown, retry later
}

Die Ebenen zusammenfügen#

Die günstigste zuerst, Stopp, sobald Sie eine Antwort haben:

function validate_email(string $email): array
{
    if (!is_valid_syntax($email)) {
        return ['status' => 'undeliverable', 'reason' => 'invalid_email'];
    }

    $domain = substr($email, strrpos($email, '@') + 1);
    if (!has_mail_route($domain)) {
        return ['status' => 'undeliverable', 'reason' => 'invalid_domain'];
    }

    return verify($email)['result']; // deliverable | risky | undeliverable | unknown
}

Die beiden lokalen Ebenen kosten nichts und fangen den meisten Müll sofort ab; die API-Ebene läuft nur bei Adressen, die den Netzwerk-Roundtrip wert sind. Diese Reihenfolge ist der ganze Trick – dieselbe Form finden Sie auch in der Node.js- und der Python-Version dieses Leitfadens, denn die Schichtung, nicht die Sprache, ist es, die Validierung funktionieren lässt.

Häufig gestellte Fragen#

Reicht filter_var aus, um eine E-Mail-Adresse in PHP zu validieren?#

Für die Syntax: ja – filter_var($email, FILTER_VALIDATE_EMAIL) ist die richtige Prüfung auf Ebene eins und die bessere Wahl als eine selbst geschriebene Regex. Doch es validiert die Form, nicht die Zustellbarkeit: Es löst niemals DNS auf und kontaktiert keinen Mailserver, ein bestandener Test bedeutet also „sieht aus wie eine E-Mail“, nicht „wird zugestellt“. Kombinieren Sie es mit einer MX-Abfrage und einer SMTP-Postfachprüfung, bevor Sie der Adresse vertrauen.

Was ist der Unterschied zwischen checkdnsrr() und getmxrr()?#

checkdnsrr() beantwortet eine Ja/Nein-Frage – veröffentlicht die Domain einen Eintrag eines bestimmten Typs? – und gibt einen Boolean zurück, was alles ist, was Sie brauchen, um zu bestätigen, dass eine Mailroute existiert. getmxrr() geht weiter: Es füllt Arrays per Referenz mit den tatsächlichen MX-Hostnamen und deren Gewichtungen, verwenden Sie es also, wenn Sie die Mailserver untersuchen oder sortieren möchten, statt nur zu bestätigen, dass sie vorhanden sind. Beide geben false zurück, wenn kein passender Eintrag existiert.

Kann ich ein Postfach in PHP ohne externen Dienst verifizieren?#

Teilweise. checkdnsrr() und getmxrr() bestätigen, dass die Domain Mail annimmt, was tote Domains kostenlos aussortiert und nichts über die Standardbibliothek hinaus benötigt. Das Postfach zu bestätigen bedeutet eine SMTP-Konversation, die Sie mit fsockopen() versuchen können, aber nicht von Ihrem App-Server aus ausführen sollten – Port 25 ist weithin gesperrt und das Ergebnis hängt von der Reputation Ihrer IP ab. Das ist die Ebene, für deren Bewältigung ein Verifizierungsdienst existiert.

Sollte ich diese Prüfungen bei der Registrierung oder beim Bereinigen einer Liste durchführen?#

Beides, in unterschiedlicher Tiefe. Führen Sie die Syntax- und die MX-Abfrage synchron bei der Registrierung aus – sie sind schnell genug, um die Anfrage zu blockieren und sofortiges Feedback zu geben – und handeln Sie auch dort auf Basis des unmittelbaren API-Urteils. Reservieren Sie das vollständige, per SMTP bestätigte Ergebnis für die Listenbereinigung und langsamere Back-Office-Arbeit; der Serverless-Registrierungsleitfaden zeigt das Muster von Anfang bis Ende.


Bereit, die SMTP-Ebene hinzuzufügen? Der kostenlose Tarif umfasst 100 Credits, die die vollständige Pipeline durchlaufen, und die API-Referenz enthält die vollständigen /verify- und /jobs-Endpunkte mit Copy-and-paste-Beispielen in sieben Sprachen.

Your reputation, protected.

Clean your first list in minutes. 100 free credits, no card required.

Get started