62 lines
1.8 KiB
Python
62 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Quick email validation utility. Validates email format without external dependencies."""
|
|
|
|
import re
|
|
from typing import NamedTuple
|
|
|
|
class EmailValidationResult(NamedTuple):
|
|
"""Result of email validation."""
|
|
is_valid: bool
|
|
normalized: str | None
|
|
error: str | None = None
|
|
|
|
def validate_email(email: str) -> EmailValidationResult:
|
|
"""Validate email address format.
|
|
|
|
Args:
|
|
email: Email address to validate
|
|
|
|
Returns:
|
|
EmailValidationResult with validation status
|
|
"""
|
|
if not email:
|
|
return EmailValidationResult(False, None, "Email is empty")
|
|
|
|
email = email.strip().lower()
|
|
|
|
# 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):
|
|
return EmailValidationResult(False, None, "Invalid email format")
|
|
|
|
local, _, domain = email.rpartition('@')
|
|
|
|
if len(local) > 64:
|
|
return EmailValidationResult(False, None, "Local part too long (>64 chars)")
|
|
|
|
if len(domain) > 253:
|
|
return EmailValidationResult(False, None, "Domain part too long (>253 chars)")
|
|
|
|
# Check for consecutive dots
|
|
if '..' in email:
|
|
return EmailValidationResult(False, None, "Consecutive dots not allowed")
|
|
|
|
return EmailValidationResult(True, email)
|
|
|
|
if __name__ == "__main__":
|
|
test_emails = [
|
|
"test@example.com",
|
|
" USER@Example.COM ",
|
|
"invalid-email",
|
|
"bad..email@example.com",
|
|
"",
|
|
"valid.email+tag@subdomain.example.org"
|
|
]
|
|
|
|
print("Email Validation Results:")
|
|
print("-" * 60)
|
|
for email in test_emails:
|
|
result = validate_email(email)
|
|
status = "✓ VALID" if result.is_valid else f"✗ INVALID: {result.error}"
|
|
print(f"{email!r:45} -> {status}") |