How to Validate an Email Address and Raise ValueError in Python

This code defines a validate_email function that checks an email address against a regex pattern and several rules, raising ValueError with a specific reason when invalid.

Easy Python 3.9+ Aug 9, 2026 Errors & debugging 14 views 0 copies

Python code

32 lines
Python 3.9+
import re

def validate_email(email: str) -> str:
    """Validate an email address and return it if valid, otherwise raise ValueError."""
    if not isinstance(email, str):
        raise ValueError("Email must be a string")
    if len(email) > 254:
        raise ValueError("Email length exceeds 254 characters")

    # Basic RFC 5322-inspired pattern
    pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    if not re.match(pattern, email):
        raise ValueError(f"Invalid email format: '{email}'")

    local_part, domain = email.rsplit("@", 1)

    if not local_part or len(local_part) > 64:
        raise ValueError(f"Local part invalid: '{local_part}'")
    if not domain or "." not in domain:
        raise ValueError(f"Domain invalid: '{domain}'")
    if domain.startswith(".") or domain.endswith(".") or ".." in domain:
        raise ValueError(f"Domain has invalid dots: '{domain}'")

    return email

if __name__ == "__main__":
    for addr in ["user@example.com", "invalid", "foo@.com", "a@b.co", "test@sub.domain.org"]:
        try:
            result = validate_email(addr)
            print(f"Valid: {result}")
        except ValueError as e:
            print(f"Error: {e}")

Output

stdout
Valid: user@example.com
Error: invalid
Error: foo@.com
Error: a@b.co
Valid: test@sub.domain.org

How it works

The function first checks the type and length, then uses a regex to match the basic structure. It splits the email into local and domain parts, validating each further. Raising ValueError with a descriptive message allows callers to catch and handle the error, making the code robust for user input validation. The main block demonstrates usage in a loop, catching errors per address.

Common mistakes

  • Using re.match without anchoring the pattern, which can allow partial matches.
  • Forgetting to check for consecutive dots in the domain, allowing invalid domains like 'foo..bar.com'.
  • Not handling the case where the email is not a string, leading to TypeError instead of ValueError.

Variations

  1. Use a more complex regex from the `email-validator` library for fuller RFC compliance.
  2. Return a tuple of (valid, reason) instead of raising exceptions for non-exceptional control flow.

Real-world use cases

  • Validating user input in a signup form before storing in a database.
  • Checking email addresses in bulk during a data import to log invalid entries.
  • Ensuring emails from an API payload meet the expected format before processing.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Errors & debugging

Related tutorials and quizzes for this topic.