E-Mail-Adressen in Python verifizieren
Eine E-Mail-Adresse in Python zu verifizieren ist bei den einfachen Teilen unkompliziert und bei dem Teil, der am meisten zählt, überraschend schwer. Dieser Guide zeigt Syntaxprüfungen und DNS-Lookups, die du lokal ausführen kannst, erklärt genau, warum rohe SMTP-Abfragen in der Praxis scheitern, und zeigt, wie du über eine REST-API ein Ergebnis auf Postfach-Ebene bekommst.
Nutze Python, um fehlerhafte Eingaben abzulehnen und optional DNS-/MX-Prüfungen zu cachen. Für das Ergebnis auf Postfach-Ebene nutzt du eine Verifizierungs-API, weil direkte Abfragen per smtplib leicht gedrosselt werden und oft mehrdeutige Antworten liefern.
Was „Verifizieren“ einer E-Mail eigentlich bedeutet
E-Mail-Verifizierung ist der Prozess, mit dem du bestätigst, dass eine Adresse echt ist und Mails empfangen kann, bevor du irgendetwas an sie sendest. Er besteht aus einer Reihe von Prüfungen, jede schwieriger als die vorherige: Ist die Adresse korrekt formatiert, nimmt ihre Domain überhaupt Mails an, und existiert das konkrete Postfach? In Python lassen sich die ersten beiden gut umsetzen. Beim dritten scheitern die meisten Eigenbau-Lösungen still und leise, und zu verstehen, warum, ist das Nützlichste an diesem Artikel.
Der Plan unten ist mehrstufig. Führe die günstigen, schnellen Prüfungen lokal aus, um offensichtlich kaputte Eingaben auszusortieren, und ruf dann eine Verifizierungs-API für die Antwort auf Postfach-Ebene auf, ob die Adresse nutzbar ist. So lehnst du Müll sofort ohne API-Aufruf ab und bekommst für alles, was übrig bleibt, ein klareres Ergebnis.
Schritt 1: Syntaxvalidierung
Die erste Prüfung bestätigt, dass die Adresse korrekt aufgebaut ist. Es ist verlockend, dafür einen regulären Ausdruck zu schreiben, aber die E-Mail-Syntax ist viel komplizierter, als sie aussieht, und selbstgebaute Regexes sind fast immer entweder zu streng oder zu lasch. Die Referenz-Bibliothek dafür ist email-validator. Sie setzt die relevanten Standards sauber um und ist in Produktion weit verbreitet.
Installiere sie mit pip:
pip install email-validator
Dann validierst du eine Adresse. Die Bibliothek wirft EmailNotValidError bei allem, was fehlerhaft ist, und gibt bei gültigen Eingaben ein normalisiertes Objekt zurück:
from email_validator import validate_email, EmailNotValidError
def check_syntax(address):
try:
result = validate_email(address, check_deliverability=False)
return True, result.normalized
except EmailNotValidError as error:
return False, str(error)
ok, value = check_syntax("jane.doe@example.com")
print(ok, value) # True jane.doe@example.com
ok, value = check_syntax("jane.doe@@example")
print(ok, value) # False, with a description of the problem
Mit check_deliverability=False bleibt dieser Schritt eine reine Syntaxprüfung ohne Netzwerkaufrufe und ist damit schnell genug für jeden Tastendruck oder jedes abgeschickte Formular. Speichere immer den Wert normalized , den die Bibliothek zurückgibt, statt der rohen Nutzereingabe, denn sie bringt die Adresse für eine konsistente Speicherung in eine kanonische Form.
Schritt 2: Domain- und MX-Prüfungen
Eine korrekt formatierte Adresse ist trotzdem nutzlos, wenn ihre Domain keine E-Mails empfangen kann. Die nächste Prüfung fragt die DNS-Records der Domain ab und sucht nach MX-Records, die die zuständigen Mailserver der Domain benennen. Eine Domain ohne MX-Records kann keine Mails annehmen, also lässt sich jede Adresse darauf sofort ablehnen.
Die email-validator kann das für dich erledigen, wenn du check_deliverability=Trueübergibst. Dann läuft der MX-Lookup direkt als Teil der Validierung mit:
from email_validator import validate_email, EmailNotValidError
def check_domain(address):
try:
result = validate_email(address, check_deliverability=True)
return True, result.domain
except EmailNotValidError as error:
return False, str(error)
Wenn du die DNS-Abfrage selbst ausführen willst, etwa um Ergebnisse für viele Adressen auf derselben Domain zu cachen, nutze die Bibliothek dnspython direkt:
pip install dnspython
import dns.exception
import dns.resolver
def has_mx_record(domain):
try:
records = dns.resolver.resolve(domain, "MX")
return len(records) > 0
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
return False
except dns.exception.DNSException:
return False # Treat resolver errors as inconclusive.
print(has_mx_record("gmail.com")) # True
print(has_mx_record("no-such-domain-xyz.invalid")) # False
Das ist wirklich nützlich. Es sortiert Adressen auf Domains aus, die abgelaufen sind, nie existiert haben oder schlicht keine Mails verarbeiten. Aber beachte, was es dir immer noch nicht verrät: ob someone@gmail.com ein echtes Postfach ist. Gmail hat MX-Records, also besteht jede Gmail-Adresse diese Prüfung, ob gültig oder nicht.
Schritt 3: Die Postfach-Prüfung und warum rohes SMTP nicht reicht
Um das Postfach selbst zu bestätigen, musst du mit dem empfangenden Mailserver sprechen. Im Prinzip verbindest du dich per SMTP, stellst dich vor, sendest den Befehl RCPT TO mit der Zieladresse und liest den Antwortcode: Ein positiver Code deutet darauf hin, dass das Postfach existiert, eine Ablehnung darauf, dass es nicht existiert. Pythons eingebautes smtplib kann das, und der Code sieht trügerisch einfach aus:
import smtplib
import dns.resolver
def naive_smtp_check(address):
domain = address.split("@")[1]
mx_host = str(dns.resolver.resolve(domain, "MX")[0].exchange)
server = smtplib.SMTP(timeout=10)
server.connect(mx_host)
server.helo("example.com")
server.mail("probe@example.com")
code, message = server.rcpt(address)
server.quit()
# 250 and 251 generally mean the mailbox was accepted.
return code in (250, 251)
Im Tutorial funktioniert das, in Produktion scheitert es. Die Gründe lohnen sich im Detail, denn sie erklären, warum sich kein ernsthafter Verifizierer auf ein Skript wie dieses verlässt.
IP-Reputation und Drosselung
Mailbox-Anbieter erkennen Verifizierungsabfragen aktiv. Führe von einem Server aus eine Handvoll Prüfungen per RCPT TO durch, und Anbieter wie Gmail und Outlook drosseln oder blockieren diese IP nach wenigen Versuchen. Ist die IP erst gedrosselt, liefert der Server mehrdeutige Antworten, egal ob das Postfach existiert, und deine Ergebnisse werden bedeutungslos. Echte Verifizierung läuft genau deshalb über große Pools sauber aufgewärmter, gut verwalteter IP-Adressen.
Greylisting
Viele Server nutzen Greylisting und geben absichtlich einen vorübergehenden Fehler 4xx zurück, wenn ein unbekannter Absender zum ersten Mal Kontakt aufnimmt. Legitime Mailserver versuchen es später erneut, Spammer meist nicht. Ein naives Skript ohne Wiederholung liest diesen vorübergehenden Fehler als Ablehnung und markiert ein völlig intaktes Postfach als ungültig. Das ist ein falsch negatives Ergebnis, verursacht allein durch Ungeduld.
Catch-all-Domains
Eine Catch-all-Domain akzeptiert Mails an jede mögliche Adresse, daher liefert RCPT TO einen positiven Code für realperson@domain.com und im random-string-9f3a@domain.com gleichermaßen. Eine rohe SMTP-Prüfung kann auf diesen Domains ein echtes Postfach nicht von einem nicht existierenden unterscheiden. Um ein Catch-all zu erkennen, musst du eine zweite Abfrage an eine Adresse schicken, die ganz sicher nicht existiert, und schauen, ob auch sie akzeptiert wird. Das ist Catch-all-Erkennung, kein einfaches Ja oder Nein.
Mehrdeutige Antworten großer Anbieter
Einige große Anbieter haben ihr Verhalten bei RCPT TO bewusst mehrdeutig gemacht. Manche akzeptieren im Handshake jede Adresse und bouncen erst später, sodass die SMTP-Antwort die gesuchte Information schlicht nicht enthält.
Deshalb lassen die Maintainer von email-validator SMTP-Prüfungen bewusst aus der Bibliothek heraus. Ihre Dokumentation sagt klar, dass es nichts bringt, selbst einen SMTP-Server zu kontaktieren, weil Server gut darin sind, nicht preiszugeben, ob eine Adresse zustellbar ist, und weil eine Adresse, die Mails anzunehmen scheint, danach trotzdem bouncen kann. Die ehrliche Erkenntnis: Syntax- und MX-Prüfungen kannst du in deinem eigenen Code gut umsetzen, eine zuverlässige Postfach-Prüfung nicht.
Schritt 4: Verifizieren mit der VeriMails-API
Die praktische Lösung: Überlass die Postfach-Prüfung einem Verifizierungsdienst mit dafür gebauter Infrastruktur und ruf diesen Dienst aus Python mit einem einzigen HTTP-Request auf. VeriMails bietet eine REST-API , die die komplette Pipeline ausführt: Syntax, MX, DNS, einen Live-SMTP-Handshake, Catch-all-Erkennung, Wegwerf-Erkennung und Rollen-Erkennung, und ein strukturiertes Ergebnis zurückgibt.
Mit der Standard-Bibliothek requests sieht ein Verifizierungsaufruf so aus. Details zum Endpunkt findest du in der VeriMails API-Dokumentation:
import requests
def verify_email(address, api_key):
response = requests.get(
"https://api.verimails.com/v1/verify",
params={"email": address},
headers={"Authorization": f"Bearer {api_key}"},
timeout=10,
)
response.raise_for_status()
return response.json()
result = verify_email("jane.doe@example.com", api_key="YOUR_API_KEY")
print(result["status"]) # e.g. "deliverable", "undeliverable", "catch_all"
print(result["disposable"]) # True if a throwaway address
print(result["role_based"]) # True for addresses such as info@ or support@
Danach kannst du auf das Ergebnis reagieren. Ein Anmeldeformular könnte Adressen mit deliverable akzeptieren, solche mit undeliverable und im disposable ablehnen und für catch_all:
def is_acceptable_for_signup(address, api_key):
result = verify_email(address, api_key)
if result["disposable"]:
return False, "Disposable addresses are not allowed."
if result["status"] == "undeliverable":
return False, "That address does not appear to exist."
return True, "Address verified."
eine eigene Regel festlegen. Da jeder Aufruf ein klares Ergebnis liefert, ist er schnell genug für den Einsatz beim Absenden eines Formulars, ohne dass die Person warten muss. Für eine bestehende Liste von Adressen in deiner Datenbank ist die Massen-CSV-Verifizierung die bessere Wahl, denn eine einzige Datei hochzuladen ist weit effizienter, als den Endpunkt für einzelne Adressen tausende Male in einer Schleife aufzurufen.
Das empfohlene Muster für eine Python-Anwendung kombiniert beide Ebenen: Behalte die lokale Syntaxprüfung mit email-validator bei, um Müll-Eingaben sofort abzulehnen, bevor du einen Credit ausgibst, und ruf dann für alles, was durchkommt, die API für das maßgebliche Zustellbarkeitsergebnis auf. So bekommst du schnelles Feedback bei offensichtlichen Fehlern und ein verlässliches Urteil für echte Adressen.
Tabelle: Regeln für die Anwendung
| Ergebnis | Regel bei der Registrierung | Regel bei Import oder CRM |
|---|---|---|
deliverable | Normalisierte Adresse akzeptieren und speichern | Im aktiven Segment behalten |
undeliverable | Mit klarem Korrekturhinweis ablehnen | Vor jeder Kampagne unterdrücken |
catch_all | Je nach Kontorisiko akzeptieren oder prüfen | Separat segmentieren und vorsichtig senden |
disposable | Für die meisten Produkte ablehnen | Aus Outreach-Listen unterdrücken |
role_based | Nur zulassen, wenn geteilte Postfächer akzeptabel sind | Vor Cold Outreach prüfen |
API-Aufrufe vs. Listen-Jobs
Nutze die API dort, wo eine sofortige Entscheidung zählt: bei Registrierung, Checkout, Lead-Formularen, Einladungen und Kontoänderungen. Nutze die Massenverifizierung für einen CSV-Export, eine CRM-Bereinigung oder eine Kampagnen-Zielgruppe, bei der tausende Adressen dieselbe Prüfung brauchen. Beide Workflows sollten dieselben Unterdrückungsregeln speisen, damit eine Adresse, die auf einem Weg abgelehnt wurde, später nicht über ein anderes Tool angeschrieben wird.
Alles zusammengesetzt
Eine saubere Implementierung hat drei Ebenen. Erstens eine Syntaxprüfung mit email-validator und check_deliverability=False, lokal und sofort ausgeführt, um fehlerhafte Eingaben abzulehnen. Zweitens eine optionale MX-Prüfung mit dnspython , wenn du tote Domains vor dem API-Aufruf herausfiltern willst, auch wenn die API das ebenfalls abdeckt. Drittens ein Aufruf der VeriMails-API für das Ergebnis auf Postfach-Ebene, inklusive Catch-all-, Wegwerf- und Rollen-Erkennung, die du allein nicht zuverlässig nachbauen kannst.
Wichtig ist die Arbeitsteilung. Syntax und DNS kannst du wirklich selbst in Python erledigen. Die Live-Postfach-Prüfung hängt von IP-Reputation, Greylisting-Verhalten und Catch-all-Erkennung ab, die ein einzelnes Skript nicht stemmen kann. Genau deshalb lässt die Standard-Validierungsbibliothek SMTP-Abfragen bewusst weg. Nutze lokale Prüfungen für Tempo, eine API für die Verifizierung auf Postfach-Ebene und die Preisseite , um den Plan zu wählen, der zu deinem erwarteten Volumen passt.
Häufig gestellte Fragen
Verwandte Artikel
Starte mit sauberen Daten
100 Gratis-Credits bei der Anmeldung. Keine Kreditkarte nötig. Setz den Rat noch heute in die Praxis um.
Kostenlos starten