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.
Python code
32 linesimport 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
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
- Use a more complex regex from the `email-validator` library for fuller RFC compliance.
- 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
More from Errors & debugging
- Catch RecursionError and Fail Gracefully in Python easy
- Catch ValueError and print friendly message in Python easy
- Collect Multiple Validation Errors in Python Before Raising medium
- Handle ValueError and ZeroDivisionError in Python with try except easy
- How to Add a Correlation ID to Logging Records in Python medium
- How to Assert Preconditions with Descriptive Messages in Python easy
Keep learning
Related tutorials and quizzes for this topic.