philiprehberger-email-validate
Email validation with syntax checking and normalization.
Installation
pip install philiprehberger-email-validate
Usage
from philiprehberger_email_validate import validate_email
result = validate_email("user@example.com")
print(result.valid) # True
print(result.normalized) # "user@example.com"
print(result.domain) # "example.com"
Quick Syntax Check
from philiprehberger_email_validate import is_valid
is_valid("user@example.com") # True
is_valid("not-an-email") # False
Normalization
from philiprehberger_email_validate import normalize
normalize(" User@Example.COM ") # "user@example.com"
normalize("first.last+tag@gmail.com") # "firstlast@gmail.com"
normalize("user+promo@example.com") # "user@example.com"
MX Lookup
from philiprehberger_email_validate import validate_email
result = validate_email("user@example.com", check_mx=True)
if not result.valid:
print(result.error) # "MX lookup failed for domain: example.com"
Disposable Email Detection
from philiprehberger_email_validate import validate_email
result = validate_email("user@mailinator.com")
print(result.is_disposable) # True
Custom Disposable Domains
from philiprehberger_email_validate import validate_email, set_disposable_domains
# Per-call extra domains
result = validate_email("user@tempmail.xyz", extra_disposable=["tempmail.xyz"])
print(result.is_disposable) # True
# Global merge with built-in list
set_disposable_domains({"tempmail.xyz", "fakeemail.org"})
Role-Based Email Detection
from philiprehberger_email_validate import validate_email, is_role_based
result = validate_email("info@example.com")
print(result.is_role_based) # True
is_role_based("admin@example.com") # True
is_role_based("john@example.com") # False
Free Provider Detection
Flag consumer/free mailboxes (useful for filtering B2B signups that should use a company address):
from philiprehberger_email_validate import validate_email, is_free_email
result = validate_email("user@gmail.com")
print(result.is_free) # True
is_free_email("user@gmail.com") # True
is_free_email("user@acme-corp.com") # False
Email Domain Suggestions
from philiprehberger_email_validate import validate_email, suggest_domain, suggest_email
result = validate_email("user@gmial.com")
print(result.suggested_domain) # "gmail.com"
suggest_domain("hotmial.com") # "hotmail.com"
suggest_domain("gmail.com") # "" (no suggestion needed)
# Correct the whole address (local part and any +tag are preserved)
suggest_email("first.last+promo@hotmial.com") # "first.last+promo@hotmail.com"
suggest_email("user@gmail.com") # "" (no suggestion needed)
RFC 5321 Strict Mode
from philiprehberger_email_validate import validate_email
result = validate_email("user@example.com", strict=True)
print(result.valid) # True
result = validate_email(".user@example.com", strict=True)
print(result.valid) # False
print(result.error) # "Local part starts or ends with a dot (RFC 5321)"
Bulk Validation
from philiprehberger_email_validate import validate_many
results = validate_many(["user@example.com", "bad@@email", "test@gmail.com"])
for r in results:
print(r.normalized, r.valid)
# With concurrent MX lookups and strict mode
results = validate_many(emails, check_mx=True, concurrent=True, strict=True)
Extract Emails from Text
from philiprehberger_email_validate import extract_emails
emails = extract_emails("Contact hello@example.com or support@test.org")
# ["hello@example.com", "support@test.org"]
Email Parts
from philiprehberger_email_validate import email_parts
parts = email_parts("user@example.com")
print(parts.local) # "user"
print(parts.domain) # "example.com"
print(parts.tld) # "com"
Mask Email
from philiprehberger_email_validate import mask_email
mask_email("john@example.com") # "j***n@example.com"
mask_email("alice@example.com") # "a***e@example.com"
Disposable check
from philiprehberger_email_validate import is_disposable
is_disposable("user@mailinator.com") # True
is_disposable("user@gmail.com") # False
is_disposable("not-an-email") # False
Comparing emails
from philiprehberger_email_validate import compare_emails
compare_emails("Foo@Gmail.com", "foo@gmail.com") # True
compare_emails("foo.bar+tag@gmail.com", "foobar@gmail.com") # True
compare_emails("foo@a.com", "bar@a.com") # False
API
| Function / Class | Description |
|---|---|
EmailResult |
Dataclass with valid, normalized, domain, error, is_disposable, is_role_based, is_free, and suggested_domain fields |
normalize(email) |
Normalize an email: lowercase, strip whitespace, Gmail dot-insensitivity, plus-addressing cleanup |
is_valid(email) |
Quick boolean syntax check |
validate_email(email, check_mx, extra_disposable, strict) |
Full validation returning an EmailResult |
validate_many(emails, check_mx, concurrent, extra_disposable, strict) |
Validate multiple emails with optional parallel MX lookups |
is_role_based(email) |
Check if an email uses a role-based local part (info@, admin@, etc.) |
is_disposable(email) |
Check if an email's domain is in the disposable-domains set |
is_free_email(email) |
Check if an email's domain is a known free/public provider (gmail, yahoo, etc.) |
compare_emails(a, b) |
Check if two emails are equivalent after normalization |
suggest_domain(domain) |
Suggest a corrected domain for common typos |
suggest_email(email) |
Suggest a corrected full email address for a domain typo |
set_disposable_domains(domains) |
Merge additional domains into the global disposable domains set |
DISPOSABLE_DOMAINS |
Mutable set of known disposable email domains |
ROLE_PREFIXES |
Frozen set of known role-based email prefixes |
COMMON_DOMAINS |
Frozen set of common email provider domains used for suggestions |
FREE_EMAIL_DOMAINS |
Frozen set of known free/public email provider domains |
extract_emails(text) |
Extract all valid email addresses from text, deduplicated |
email_parts(email) |
Split email into structured parts (local, domain, tld, normalized) |
EmailParts |
Dataclass with local, domain, tld, normalized fields |
mask_email(email, mask_char, visible) |
Mask the local part for privacy display |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Release files for philiprehberger-email-validate 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| philiprehberger_email_validate-0.7.0.tar.gz | 188.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| philiprehberger_email_validate-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 198.9 kB
Release files / philiprehberger_email_validate-0.7.0.tar.gz
| Download URL | philiprehberger_email_validate-0.7.0.tar.gz |
|---|---|
| Size | 188.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b848f6e926102ea6b3b7dc3578c2d189b8bcefdd4a679ffc911ab77ee71bef4e
|
|
BLAKE2b-256 checksum How to use checksums |
53fba6d8a497a2d7547d3d6a47203ce503fedecc4f859184c3a393f9d05562ec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / philiprehberger_email_validate-0.7.0-py3-none-any.whl
| Download URL | philiprehberger_email_validate-0.7.0-py3-none-any.whl |
|---|---|
| Size | 10.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
24620c64fb7f974dbc23d90cb9b778837e782ee7fe445a74dc3b96ffc92683a5
|
|
BLAKE2b-256 checksum How to use checksums |
e53fb07d88fc26e6e3188973345e3418b339820119c01efb75c12f0af2638594
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|