Articles

3 methods for email validation using Python (tutorial and code)

Kerry Campion Kerry Campion
· 21 min read · September 30th, 2024
Nobody likes spam (the junk mail kind, we won’t make assumptions about your taste for canned luncheon meat). And you definitely don’t want to be marked as spam thanks to a flood of fake email addresses on your list.

Enter email validation using Python 💪.

We’ll share 3 step-by-step tutorials (with sample code) for validating your email list using regex, the email-validator library, and an API for Python. Heads up, we think our API is really, really good but we’re professionals and we’ll give you an honest overview of each method discussed. 

But before we do, let’s get clear on why email validation is so important. 

✅ This article was reviewed and fact-checked by Igor Hrček, Senior Site Reliability Engineer at MailerLite. 

Why email validation is (very) important

Email validation ensures your company’s emails land in your customers’ inboxes. In broad terms, it does this by checking that the email addresses you’re sending to actually exist. 

Without proper email validation, your list can quickly become full of fake, catch-all, or invalid email addresses. When this happens your bounce rate starts to increase, meaning your sender reputation decreases. And the more your sender reputation decreases the more your emails are marked as spam. The more your emails are marked as spam the more your sender reputation decreases and the more…

You get the picture. 

Now that we understand the risks, here’s how you can avoid the vicious spam cycle and safeguard your deliverability. 

Method 1: Validate email addresses with Python using regular expressions (Regex)

We’ll start with the most basic email verification checks using regex. Think of it as a search pattern for finding and matching text, kind of like CTRL + F on steroids. It checks email addresses for things like:

  1. An "@" symbol in the right place

  2. A valid domain name (like gmail.com)

  3. Forbidden characters (like spaces or extra symbols)

And setting it up is pretty straightforward. 

Step 1: Define a regular expression pattern for email validation 

A simple email validation pattern might look something like this:

def email-validator(email):    
pattern = (r"^(?!\.)(?!.*\.\.)[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+"

               r"@[a-zA-Z0-9-]+\.[a-zA-Z]{2,}$")

    return re.match(pattern, email) is not None

This pattern:

  • Prevents consecutive periods

  • Enforces at least two characters in the top-level domain (TLD)

re.match vs re.fullmatch 

When validating email addresses using Python’s re module, it’s important to understand the difference between re.match() and re.fullmatch(). Both have different behaviors when it comes to pattern matching which can have a big impact on your output. 

The re.match() method checks if the beginning of a string matches a given regular expression pattern, returning a match object even if the rest of the string doesn't match. On the other hand, re.fullmatch() ensures that the entire string conforms to the pattern, only returning a match if the string matches from start to finish.

We recommend going with re.fullmatch() because it’ll only return a match if the entire email address follows the correct pattern. This avoids partial matches that could lead to invalid inputs being accepted.

Igor’s take: Relying on regex for Python has its limitations

While regex can check if an email address has a valid domain format (e.g., example.com), it can’t confirm whether the domain is actually reachable or configured to receive emails.

Regex also doesn’t tell you anything about the deliverability or functionality of an email address. Even if an email address passes regex and domain validation, it might still be invalid if the mailbox doesn’t exist or if the email server is misconfigured.

With that said, if you want to take your email verification up a notch you could leverage an external library for Python like email-validator. 

Method 2: Validate email addresses with Python’s email-validator library

This method helps you validate email addresses according to the RFC 5321/5322 standards, making it more robust than regex alone. 

Step 1: Install the email-validator library

Before using the library, you need to install it via pip.

pip install email-validator

(You might need to use pip3 depending on your local environment.)

Troubleshooting tip: pip Not Recognized

If you get a ‘pip’ not recognized error these are the usual culprits: 

  • Python or pip is not properly installed

  • Python's directory is not added to the system's PATH environment variable

  • You're using a Python installation that doesn't include pip (although this is rare in modern installations)

💡 Here’s how to troubleshoot these issues: 

  • Make sure Python is installed correctly. You can check this by running python –version in the command line

  • Pip usually comes pre-installed with Python versions 2.7.9+ and 3.4+. But for older versions, you might need to install pip separately

Step 2: Import the required modules

Once the library is installed, import the necessary modules in your Python script.

Step 3: Use ‘email-validator()’ function 

You can now use the email-validator() function to validate an email address, huzzah!

Here’s a sample code snippet:

from email-validator import email-validator, EmailNotValidError
def email-validator_address(email):
try:
valid = email-validator(email)
return True, valid.email
except EmailNotValidError as e:
return False, str(e)

This function performs several checks:

  • Syntax validation: ensures the email matches the correct format

  • Domain validation: verifies that the domain exists by checking DNS records

  • Normalization: returns the email in its normalized form (e.g., converts domain names to lowercase)

Step 4: Test it out with sample emails

Take the function for a test ride by sampling some email addresses.

if __name__ == "__main__":
    emails = [
        "[email protected]",
        "invalid-email",
        "[email protected]",
        "[email protected]"
    ]
    is_valid, result = email-validator_address(email)
if is_valid:
print(f"Valid email: {result}")
else:
print(f"Invalid email: {result}")


Output:
Valid email: [email protected]
Invalid email: The email address is not valid. It must have exactly one @-sign.
Valid email: [email protected]
Invalid email: The domain name gnail.com does not exist.

Step 5 (Optional): Add custom validation rules

You can extend the functionality of email-validator by adding custom validation rules, like checking for disposable emails. You’d need a separate mechanism for this, like a list of known disposable domains.

Here’s an example using a simple disposable domain check:

DISPOSABLE_DOMAINS = {'mailinator.com', '10minutemail.com'}

def email-validator_with_custom_rules(email):
try:
# Validate the email
valid = email-validator(email)
domain = valid.domain

# Custom check: disposable email domains
if domain in DISPOSABLE_DOMAINS:
return False, "Disposable email addresses are not allowed"

return True, valid.email

except EmailNotValidError as e:
return False, str(e)

# Usage:
is_valid, result = email-validator_with_custom_rules("[email protected]")
if is_valid:
print(f"Valid email: {result}")
else:
print(f"Invalid email: {result}")

Igor’s take: Python’s email-validator library is a step up from regex, but not without its limitations 

Using a library like email-validator can overcome some of the limitations of regex mentioned above. It goes beyond checking if an email “looks” right: It verifies that the domain exists and is properly formatted. Additionally, it supports Unicode, so email addresses with non-Latin characters, like 名前@例え.テス, aren’t an issue.

However, it does have its limitations. It doesn’t validate if a mailbox is real or active and may slow down large-scale systems due to its extra domain checks. Relying on external libraries also means you’ll need to manage updates and compatibility. Finally, it might not be flexible enough for highly specific validation needs.

Method 2 continued: Validate emails from a text file using Python

Another common approach is to handle email validation in bulk by reading addresses from a text file, this allows you to process long lists of emails with just a few lines of code. 

Here’s how you’d go about that. 

Step 1: Install the email-validator library

Before using the library, you need to install it via pip.

pip install email-validator

Step 2: Create a text file with email addresses

  1. Create a new text file: Use a text editor (e.g., Notepad, Sublime Text, VSCode) to create a new file named emails.txt. Make sure the file is saved in the same directory where you plan to run your Python script or note its path

  2. Add email addresses: Enter one email address per line. Include a mix of valid and invalid emails to test the validation process

Step 3: Write a Python script to read and validate emails

Create a Python script that reads the email addresses from the text file and validates each one.

  1. Import Required Modules:

from email-validator import email-validator, EmailNotValidError
import sys
  1. Define the Validation Function:

from email-validator import email-validator, EmailNotValidError
import sys
from typing import List, Tuple

def email-validators_from_file(file_path: str) -> Tuple[List[str], List[Tuple[int, str, str]]]:
valid_emails = []
invalid_emails = []

try:
with open(file_path, 'r', encoding='utf-8') as file:
for line_number, line in enumerate(file, start=1):
email = line.strip()
if not email:
print(f"Line {line_number}: Skipped empty line.")
continue

try:
valid = email-validator(email)
email_normalized = valid.email
valid_emails.append(email_normalized)
print(f"Line {line_number}: Valid email - {email_normalized}")
except EmailNotValidError as e:
invalid_emails.append((line_number, email, str(e)))
print(f"Line {line_number}: Invalid email '{email}' - {str(e)}")

except FileNotFoundError:
print(f"Error: The file '{file_path}' was not found.")
sys.exit(1)
except IOError as e:
print(f"Error: Could not read the file '{file_path}'. {str(e)}")
sys.exit(1)

return valid_emails, invalid_emails
  1. Handle Execution from the Command Line:

if _name_ == "__main__":
if len(sys.argv) != 2:
print("Usage: python email-validators.py ")
sys.exit(1)

file_path = sys.argv[1]
valid, invalid = email-validators_from_file(file_path)

print(f"\nTotal valid emails: {len(valid)}")
print(f"Total invalid emails: {len(invalid)}")

# Optionally, you can write the results to files
with open('valid_emails.txt', 'w') as f:
f.write('\n'.join(valid))

with open('invalid_emails.txt', 'w') as f:
for line_num, email, error in invalid:
f.write(f"Line {line_num}: {email} - {error}\n")

Explanation 

  • Stripping Whitespace: Each email is stripped of leading and trailing whitespace to prevent false negatives

  • Empty Lines: The script skips empty lines and notifies you

  • Validation: Uses email-validator() to check each email. If valid, it's normalized and added to the list of valid emails

  • Error Handling:

    • File Errors: Catches FileNotFoundError and IOError when accessing the file

    • Validation Errors: Catches EmailNotValidError for invalid emails and records the error message

  • Command-Line Arguments: The script expects the path to the email file as a command-line argument

  • Output Files: Writes valid and invalid emails to separate text files for review

Troubleshooting

  • Issue: FileNotFoundError if the file path is incorrect

    • Solution: Ensure the file path is correct. If the file is in the same directory, use emails.txt. Otherwise, provide the full path

  • Issue: UnicodeDecodeError when reading the file

    • Solution: Specify the correct encoding when opening the file (e.g., encoding='utf-8')

  • Issue: Script doesn't execute due to incorrect command-line usage

    • Solution: Provide the file path as an argument when running the script

Step 4: Run the Python script

Execute the script to validate your email addresses.

  1. Save the Script: Save your Python script as email-validators.py in the same directory as emails.txt or adjust the file paths accordingly

  2. Open Terminal: Navigate to the directory containing your script and the text file

  3. Run the Script:

python email-validators.py emails.txt

Remember to replace emails.txt with the path to your email file if it's located elsewhere.

Step 5: Review results 

After running the script, review the output and the results stored in the output files.

Example Output:

Line 1: Valid email - [email protected]

Line 2: Invalid email 'invalid-email' - The email address is not valid. It must have exactly one @-sign.

Line 3: Valid email - [email protected]

Line 4: Invalid email 'user@invalid-domain' - The domain name invalid-domain does not exist.

Line 5: Invalid email 'emptyline@' - The email address is not valid. It must have a domain part after the @-sign.

Line 6: Valid email - [email protected]

Output Files:

valid_emails.txt: Contains all the valid, normalized email addresses.

[email protected]

[email protected]

[email protected]

invalid_emails.txt: Contains all the invalid email addresses as entered in the original file

invalid-email

user@invalid-domain

emptyline@

Igor’s take: Advantages and disadvantages of validating using a text file 

You might want to take this approach if you’re dealing with a small/mid-sized list that doesn’t require high performance. This method may struggle with larger email lists, but it's a good option if you’re on a tight budget and want complete control over the process. 

However, you’ll need to consider a different approach if you want to run more sophisticated checks as email-validator won’t detect other important risks like full mailboxes or disposable emails. It also won’t help you if you need real-time validation. We recommend implementing real-time validation because it stops invalid emails from making it to your list in the first place. When it comes to your deliverability, you want to be as proactive as possible.

Method 3: Using an email verification API for Python - MailerCheck

Before you fire up your keyboard, we want to talk to you about one last way to validate email addresses using Python—with a dedicated API (ours, to be exact—we warned you it was coming!).

Not only does an API give you greater insight into an email’s deliverability, but it also scales and automates the process for you. 

So let’s talk about email verification with the MailerCheck API. 

Step 1: Setup your account

Sign up for a MailerCheck account. It’s completely free to sign up and you’ll get 200 free credits to try it out. 

Step 2: Install the requests library 

Step 3: Create an API token 

Head to the API tokens in the left navigation menu and click Generate Token.

Step 4: Write Python code 

import requests

from typing import Dict, Any

import os

from dotenv import load_dotenv


# Load environment variables


load_dotenv()


API_TOKEN = os.getenv('MAILERCHECK_API_TOKEN')


API_URL = "https://app.mailercheck.com/api/check/single"


class MailerCheckAPIError(Exception):


   """Custom exception for MailerCheck API errors"""


   pass


def email-validator(email: str) -> Dict[str, Any]:


   """


   Validate an email address using the MailerCheck API.



   Args:


       email (str): The email address to validate.



   Returns:


       Dict[str, Any]: The API response data.


   Raises:


       MailerCheckAPIError: If there's an error with the API request.


       ValueError: If the API token is not set.


   """


   if not API_TOKEN:


       raise ValueError("MailerCheck API token is not set. Please set the MAILERCHECK_API_TOKEN environment variable.")


   headers = {'Authorization': f'Bearer {API_TOKEN}', 'Content-Type': 'application/json'}


   payload = {'email': email}


   try:


       response = requests.post(API_URL, json=payload, headers=headers, timeout=10)


       response.raise_for_status()  # Raises an HTTPError for bad responses


       return response.json()


   except requests.exceptions.RequestException as e:


       raise MailerCheckAPIError(f"Error validating email: {str(e)}")


def process_validation_result(email: str, result: Dict[str, Any]) -> None:


   """


   Process and print the email validation result.


   Args:


       email (str): The email address that was validated.


       result (Dict[str, Any]): The validation result from the API.


   """


   status = result.get('status', 'unknown')


   if status == 'valid':


       print(f"{email} is valid.")


   else:


       reason = result.get('reason', 'Unknown reason')


       print(f"{email} is invalid or risky. Status: {status}, Reason: {reason}")


   # Print additional details if available


   if 'details' in result:


       print("Additional details:")


       for key, value in result['details'].items():


           print(f"  {key}: {value}")


def main():


   email = input("Enter an email address to validate: ")


   try:


       result = email-validator(email)


       process_validation_result(email, result)


   except (MailerCheckAPIError, ValueError) as e:


       print(f"Error: {str(e)}")



if __name__ == "__main__":


   main()

Usage: python script-name.py after which it will ask you for an email address and provide you with output. Here’s an example: https://gist.github.com/igorhrcek/315fa901845db126d160ccf428d315d9

Step 5: Run the Python script 

Run the script to validate a sample of email addresses. And voilá, you’re done! Wasn’t that easy? 

Why use an API for Python? (Lots of reasons, actually) 

In a nutshell, using an API for email validation overcomes a lot of the limitations when using manual methods like regex or external Python libraries. It makes your whole email validation process stronger, more scalable, and efficient. 

More comprehensive validation 

An API strengthens your validation process by going way beyond basic syntax validation and domain checks. It gives you maximum insight into the deliverability of an email address by running a host of checks and returning status codes like; catch-all, mailbox-full, role-based, disposable, typos, and many more. The validation checks you can run with regex or Python libraries don’t come close to this level of visibility and accuracy. 

Real-time validation 

Your deliverability and sender reputation will also go Gandalf-vs-Balrog mode with real-time validation as invalid email addresses are screened out before they’re even added to your email list. Remember, proactive > reactive. 

Scalable and more efficient 

An API is also a great option if you’re looking for a more scalable and efficient solution. It slashes time spent on validation by distributing validation tasks across multiple servers, caching, reusing common queries, and using bulk submission endpoints (among other nifty features).

Lightens your workload 

Finally, an API reduces the mental load and responsibility you have to take on as a developer. Manually maintaining things like disposable domain lists and managing updates/compatibility of Python libraries is a drain on your most precious resource: time. With an API you no longer have to worry about this. 

In short, trusting an API with your validation process leads to less strain on your resources, a higher sender reputation, and ironclad security—all things your CTO will love you for.

What now?

We wouldn’t expect you to blindly trust just any email verification tool—ours included. That’s why we offer 200 free credits when you sign up for an account. Take those 200 free credits to run a test using a portion of your email list. Then see its impact on bounce rates, inbox placement, and overall email deliverability. 

See you in the inbox 🤩. 

Take our email validation API for a test run

MailerCheck’s detailed reports identify safe, risky, and harmful email addresses with 98% accuracy. With 13+ years of industry experience, we know what it takes to maintain great deliverability and reach inboxes.

FAQs

What is email-validator in Python?

email-validator is a Python library used to verify the format of an email address and optionally check if the email's domain has a valid MX (Mail Exchange) record. It's useful for basic syntax validation and for ensuring the email can, theoretically, receive messages.

What is py3 validate email?

py3-validate-email is a fork of the original email-validator library, designed to be compatible with Python 3. It provides similar functionality, including format validation and MX record checking.

Can I use a different regex pattern for email validation in Python?

Yes, you can. While Python’s re module allows for custom regex patterns, be cautious!  Email validation via regex alone can be tricky since the official email specification (RFC 5321/5322) is complex. Use established libraries, APIs, or patterns to avoid common pitfalls.

What is the best way to validate an email address in Python?

For reliable email validation, using a dedicated email verification tool is the best approach. While libraries like email-validator can check syntax and MX records, APIs (e.g., MailerCheck) provide additional benefits like identifying disposable emails, detecting role-based addresses, and checking if an email actually exists. These services offer deeper validation beyond basic syntax and DNS checks, ensuring higher deliverability and accuracy.

Kerry Campion
I'm Kerry, a word-scribbler here at MailerCheck. When I'm not muttering to myself at my keyboard I'm wandering the woods with my German Shepherd, Kira, or wrangling my two kids. My dream is to someday own a pig called Juan Carlos.