Guides
Last updated
July 20, 2025

5 Ways to Implement Email Validation in Python

Nicolas Rios
Nicolas Rios
Table of Contents:
ON THIS PAGE
Get your free
email validation
 API key now
stars rating
4.8 from 1,863 votes
See why the best developers build on Abstract
START FOR FREE
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
No credit card required

Validating email addresses in Python is a common requirement for clean data and reliable communication. We will explore five ways to implement an email validator, providing working code for each. We'll also examine the pitfalls of these approaches and show how Abstract API overcomes them for more dependable validation.

How to Implement an Email Validator in Python

Here are four distinct methods to validate email addresses with Python. Each approach offers a different balance of simplicity, accuracy, and depth of validation for your specific project needs.

Standard-Library Parse

Python's core "email" package contains tools that implement the official RFC 5322 standard. The "email.headerregistry.Address" class, available in Python 3.6 and later, performs a full grammar parse. This process also normalizes the local part and domain.

This method provides syntactic validation without any third-party dependencies. The code defines a function named "validate_addr_stdlib". It attempts to create an "Address" object from the input string. If the parse is successful, it returns the normalized address. An error causes a "ValueError". The official documentation provides more details.

from email.headerregistry import Address
from email.errors import HeaderParseError

def validate_addr_stdlib(addr: str) -> str:
    try:
        # Reject display-name; insist on pure addr-spec
        parsed = Address(addr_spec=addr)
        return parsed.addr_spec            # normalized, puny-code handled
    except (HeaderParseError, ValueError):
        raise ValueError("invalid RFC 5322 address")

A Hand-Rolled RFC 5322 Regular Expression

A regular expression offers a lightweight, dependency-free check. While many simple patterns exist, a regex that properly follows the RFC 5322 specification is complex. The community-accepted version is quite extensive.

The code first compiles this large regular expression pattern. The function "validate_addr_regex" then uses the "fullmatch" method. This check ensures the entire email string conforms to the pattern. If it matches, the function returns the address, otherwise it raises a "ValueError". Other resources explore this validation technique and why developers avoid simple regex.

EMAIL_RX = re.compile(r'(?:[a-zA-Z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\.[…snip…]'
                      r'(?:(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}'
                      r'[A-Za-z0-9])?\.)+[A-Za-z]{2,63}|'
                      r'\[(?:(?:\d{1,3}\.){3}\d{1,3}|IPv6:[0-9a-fA-F:]+)\]))$')
def validate_addr_regex(addr: str) -> str:
    if EMAIL_RX.fullmatch(addr):
        return addr
    raise ValueError("invalid address")

The Email-Validator Package

For a more robust solution, the email-validator package is a popular choice. It performs syntax checks, punycode translation, and Unicode safety checks. It can also optionally perform a DNS check to see if the domain is configured to receive email.

The function "validate_email" returns a rich dataclass with normalized forms of the email. The code shows how to call this function. It passes the address and a boolean to "check_deliverability". If valid, it returns the "normalized" version of the email. The project's repository contains further information.

from email_validator import validate_email, EmailNotValidError

def validate_addr_emailvalidator(addr: str, *, dns=True) -> str:
    v = validate_email(addr, check_deliverability=dns)
    return v.normalized      # canonical string for storage

MX Lookup with an Optional SMTP Handshake

When validation must confirm that an address can likely receive mail, a direct check is necessary. This method involves a network operation to find the domain's mail exchange (MX) records. After it finds the mail servers, it can optionally initiate an SMTP handshake.

This handshake simulates the first steps of an email delivery. The code uses "dnspython" to resolve MX records and "smtplib" to talk to the mail server. It attempts the "RCPT TO" command. A successful response code indicates the server accepts mail for that address. This approach gives high confidence, as shown by validation articles.

import dns.resolver, smtplib, socket

def validate_addr_mx(addr: str, timeout=3.0) -> str:
    local, domain = addr.rsplit('@', 1)
    try:
        mx_hosts = [r.exchange.to_text() for r in
                    dns.resolver.resolve(domain, 'MX')]
    except dns.exception.DNSException:
        raise ValueError("no MX")

    for host in sorted(mx_hosts, key=lambda h: h.preference):
        try:
            with smtplib.SMTP(host=str(host), timeout=timeout) as s:
                s.helo()
                code, _ = s.mail('validator@example.com')
                if code != 250:
                    continue
                code, _ = s.rcpt(addr)
                if code in (250, 251):
                    return addr       # accepted
        except (socket.error, smtplib.SMTPException):
            continue
    raise ValueError("undeliverable")

Challenges of Python Email Validation

While these methods offer functional solutions, they come with inherent trade-offs. Each approach presents specific difficulties that can affect the accuracy, performance, and maintenance of your email validation logic.

  • Regular expressions cannot fully parse RFC 5322's complex grammar. A hand-rolled regex implementation often creates maintenance debt and guarantees edge-case leaks or false positives, which makes it an unreliable method for strict validation.
  • Many libraries improperly handle Unicode addresses. They often skip or mis-order crucial normalization steps like case-folding and punycode conversion. This leads to subtle mismatches between the addresses you accept, store, and use.
  • Deliverability checks, used in the MX lookup method and the email-validator package, introduce network latency. DNS lookups can block on slow resolvers or exceed timeouts, which makes validation dependent on network connectivity and prone to intermittent failure.
  • Some tools, like the email-validator package, use opinionated heuristics that reject obscure but technically valid syntaxes. While this simplifies validation, it deviates from the official specification and produces false negatives for a small number of addresses.

Validate Emails with Abstract API.
Validate email addresses using Python to protect your sender reputation and improve deliverability rates.
Get started for free

How Abstract API Handles Email Validation in Python

Abstract API addresses the core weaknesses of traditional methods through a comprehensive API check that replaces local logic.

  • It performs RFC-compliant syntax analysis to confirm email format.
  • It conducts real-time MX-record and SMTP handshake tests.
  • It detects disposable, free, catch-all, role-based, and grey-listed domains.
  • It provides a machine learning-driven quality score and risk grade for each address.
  • It delivers these checks in a single call, which eliminates the need for local DNS logic or constant provider list updates.

How to Bring Abstract API to Your Dev Environment

Once you are familiar with Abstract’s capabilities, to add its email validator API to your project is simple. You can prepare your development environment with a few quick steps.

  • Install the Python SDK with pip: `pip install abstract-python-email-validation`
  • Create an Abstract account to get your Email Validation API key.
  • Export the key as an environment variable: `export ABSTRACT_EMAIL_KEY=your_key`
  • Import and configure the SDK in your application.
from python_email_validation import AbstractEmailValidation
import os

# Configure the SDK with your API key
AbstractEmailValidation.configure(os.getenv("ABSTRACT_EMAIL_KEY"))

# Verify an email address
result = AbstractEmailValidation.verify("user@example.com")
print(result)

Sample Email Validator Implementation with Abstract API

The Python SDK returns a structured object that contains detailed validation data. The code below shows how to verify an address and print its deliverability status and quality score. This approach gives you immediate, actionable data without complex local logic.

from python_email_validation import AbstractEmailValidation

API_KEY = "YOUR_ABSTRACT_KEY"
AbstractEmailValidation.configure(API_KEY)

validation = AbstractEmailValidation.verify("jane.doe@gmail.com")
print(validation.deliverability, validation.quality_score)

A typical API response provides a full breakdown of the email address. For example, a check on a disposable email address returns the following data.

{
  "email":"mike.smith@yopmail.com",
  "auto_correct":"",
  "deliverability":"DELIVERABLE",
  "quality_score":0.33,
  "is_valid_format":true,
  "is_free_email":false,
  "is_disposable_email":true,
  "is_role_email":false,
  "is_catchall_email":false,
  "is_mx_found":true,
  "is_smtp_valid":true
}

In this response, the address has a valid format and the domain accepts mail, as "is_mx_found" and "is_smtp_valid" are both "true". However, because "is_disposable_email" is also "true", the API assigns a low "quality_score" of 0.33. The "DELIVERABLE" status lets your system decide whether to accept, throttle, or deny the user.

Final Thoughts

Traditional regex checks only confirm syntax and fail to detect deliverability issues or disposable domains. Abstract API overcomes these limits with a single call that provides comprehensive validation, from SMTP handshakes to quality scores. To reliably validate user emails, create an account on Abstract API and get your free API key.

Validate Emails with Abstract API
Build a Python email validator to improve your data quality and reduce bounced emails.
Get started for free

Related Articles

Phone Validation
key now
Get your free
stars rating
4.8 from 1,863 votes
See why the best developers build on Abstract
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
No credit card required