python
40 lines · 8 steps
Normalizing signup emails in Python
A single function cleans, validates, and canonicalizes email addresses while rejecting blanks and disposable domains.
Explained by
highlit
1import re
2from email_validator import validate_email, EmailNotValidError
3
4_DISPOSABLE_DOMAINS = {
5 "mailinator.com",
6 "guerrillamail.com",
7 "10minutemail.com",
8 "tempmail.com",
9}
10
11_WHITESPACE = re.compile(r"\s+")
12
13
14class EmailValidationError(Exception):
15 pass
16
17
18def normalize_signup_email(raw: str, *, allow_disposable: bool = False) -> str:
19 if not raw or not raw.strip():
20 raise EmailValidationError("Email is required.")
21
22 candidate = _WHITESPACE.sub("", raw).strip("<>").lower()
23
24 try:
25 result = validate_email(candidate, check_deliverability=True)
26 except EmailNotValidError as exc:
27 raise EmailValidationError(str(exc)) from exc
28
29 normalized = result.normalized
30 domain = result.domain.lower()
31
32 if not allow_disposable and domain in _DISPOSABLE_DOMAINS:
33 raise EmailValidationError("Disposable email addresses are not allowed.")
34
35 local, _, host = normalized.partition("@")
36 if host in {"gmail.com", "googlemail.com"}:
37 local = local.split("+", 1)[0].replace(".", "")
38 normalized = f"{local}@gmail.com"
39
40 return normalized
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Wrapping a library's exception in your own domain error keeps callers decoupled from third-party details.
- 2Canonicalizing provider-specific quirks like Gmail dots and plus-tags prevents duplicate accounts for the same person.
- 3Normalizing input before validating catches sloppy but salvageable data instead of rejecting it outright.
Related explainers
php
<?php class NameParser {
Parsing a full name into components in PHP
string-parsing
arrays
normalization
Intermediate
8 steps
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/normalizing-signup-emails-in-python-explained-python-72c9/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.