Tutorial · Python

Validate email addresses in Python

From a syntax check to a full mailbox verification of a CSV file, with working Python code.

Updated October 9, 2026 · 1 min read

Validating an email address in Python with the email-validator package

1. Syntax check with email-validator

pip install email-validator
from email_validator import validate_email, EmailNotValidError

try:
    info = validate_email("Anna@Example.com", check_deliverability=False)
    email = info.normalized  # "Anna@example.com"
except EmailNotValidError as e:
    print(str(e))

check_deliverability=True additionally checks that the domain has DNS records for email.

2. MX lookup with dnspython

import dns.resolver  # pip install dnspython

def has_mx(domain: str) -> bool:
    try:
        return len(dns.resolver.resolve(domain, "MX")) > 0
    except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer, dns.resolver.NoNameservers):
        return False

3. Check that the mailbox exists

import os
import requests

def validate(email: str) -> dict:
    res = requests.get(
        "https://api.emailvalidation.io/v1/info",
        params={"email": email},
        headers={"apikey": os.environ["EMAILVALIDATION_KEY"]},
        timeout=30,
    )
    res.raise_for_status()
    return res.json()

result = validate("anna@example.com")
print(result["state"], result["reason"], result["score"])

4. Validate a CSV file

import csv

with open("contacts.csv") as src, open("contacts.validated.csv", "w", newline="") as dst:
    reader = csv.DictReader(src)
    writer = csv.DictWriter(dst, fieldnames=reader.fieldnames + ["state", "reason", "disposable"])
    writer.writeheader()
    for row in reader:
        r = validate(row["email"])
        writer.writerow({**row, "state": r["state"], "reason": r["reason"], "disposable": r["disposable"]})

For large files, run requests in parallel with a thread pool and respect your plan’s limits: the free plan allows 10 requests a minute and 5 checks at a time, paid plans 25 at a time. Or send the whole file to the bulk endpoint of the email validation API. To check a few addresses without writing code, use the bulk email validator; without an account it checks a few addresses an hour.

Validate email in other languages

Frequently asked questions

Which Python library validates email addresses?

The email-validator package (pip install email-validator) checks syntax and, optionally, that the domain resolves. It does not check whether the mailbox exists.

Can I verify an email with smtplib?

In theory you can send RCPT TO with smtplib, but most residential and cloud IPs are blocked on port 25, many servers greylist or accept everything (catch-all), and repeated probes can get your IP on a blocklist. An API handles this for you.

Email validation API

Validate emails in your app

emailvalidation.io checks syntax, MX records and the mailbox over SMTP, flags disposable, role and free addresses and returns a quality score, in one request.

/v1/info Email validation API Read the documentation

100 free validations every month. No credit card required.

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"
}

Keep reading

Start using our email validation software today!

Get 100 validations per month for free