The strict parameter in email.utils.getaddresses helps applications parse address lists with tighter rules. It is especially useful when software reads To, Cc, or Reply-To values from external messages, forms, APIs, or imported data. Instead of accepting malformed structures and trying to repair them silently, strict parsing makes failures easier to detect and handle.
What getaddresses does
getaddresses receives a sequence of strings and returns pairs containing a display name and an address. It understands commas, quoted names, angle brackets, and common mailbox syntax.
from email.utils import getaddresses
headers = [
'Alice <alice@example.com>, Bob <bob@example.com>'
]
for name, address in getaddresses(headers, strict=True):
print(name, address)
With strict=True, malformed input is less likely to be converted into a result that only appears valid. This gives the calling application a clearer boundary between accepted and rejected data.
Why strict parsing matters
Permissive parsing can hide problems. A malformed address list may be interpreted differently from what the user intended, which can cause delivery mistakes, inconsistent records, or filter bypasses. Strict mode reduces ambiguity by following the message syntax more carefully.
However, strict parsing is only one layer. It does not prove that a domain exists, that a mailbox accepts mail, or that the address belongs to a specific person. Real systems should combine parsing with domain rules, confirmation workflows, rate limits, and application-specific authorization.
Validate the returned values
Do not assume that every returned pair is usable. Check for empty strings and enforce your own rules:
from email.utils import getaddresses
def extract_recipients(values: list[str]) -> list[str]:
recipients = []
for name, address in getaddresses(values, strict=True):
address = address.strip()
if not address or '@' not in address:
raise ValueError('Invalid email address')
recipients.append(address)
if not recipients:
raise ValueError('No valid recipients')
return recipients
This example is intentionally simple. Production validation may also limit the number of recipients, reject control characters, and apply a domain allowlist.
Avoid destructive normalization
Many applications lowercase the whole address. That can be practical for internal comparison, but the local part is technically case-sensitive on some systems. Preserve the original value and create a separate normalized key when necessary.
Do not remove characters such as plus signs, dots, hyphens, or underscores without a provider-specific reason. An aggressive cleanup step can turn one valid address into another address. For broader Python guidance, browse the Python section and the Advanced Python articles.
Separate parsing from authorization
Parsing answers: “Is this structured like an address list?” Authorization answers: “May this address be used here?” Keep those responsibilities separate.
ALLOWED_DOMAINS = {'example.com', 'company.com'}
def is_allowed(address: str) -> bool:
_, domain = address.rsplit('@', 1)
return domain.lower() in ALLOWED_DOMAINS
This design makes testing easier and prevents business rules from being mixed into low-level syntax handling.
Handling web input
When addresses come from a browser or public API, enforce input limits before parsing. Restrict the total length of the field and the maximum number of recipients. Large inputs can waste CPU, memory, and logging capacity.
Reject carriage returns and line feeds supplied by users. Uncontrolled \r or \n characters can create header-injection problems. Prefer the structured classes in Python’s email package instead of manually concatenating header strings.
Using a data model
from dataclasses import dataclass
from email.utils import getaddresses
@dataclass(frozen=True)
class Recipient:
name: str
address: str
def parse_recipients(values: list[str]) -> list[Recipient]:
items = []
for name, address in getaddresses(values, strict=True):
if not address or '@' not in address:
raise ValueError(f'Invalid input: {name!r}')
items.append(Recipient(name.strip(), address.strip()))
return items
An immutable model prevents accidental changes after validation and works well across APIs, queues, and mail-delivery services.
Important tests
Test plain addresses, quoted display names, multiple recipients, empty values, extra commas, malformed brackets, duplicate addresses, Unicode names, and maximum lengths.
def test_valid_recipient():
items = parse_recipients(['Alice <alice@example.com>'])
assert items[0].address == 'alice@example.com'
def test_invalid_recipient():
try:
parse_recipients(['not an address'])
except ValueError:
pass
else:
raise AssertionError('ValueError was expected')
See the site’s testing content and automation guides for related practices.
Version compatibility
Confirm the minimum Python version supported by your project before passing strict. If your library must run on older interpreters, isolate compatibility logic in one documented function and test it in continuous integration.
Avoid catching every TypeError and retrying without strict mode. That pattern can hide programming errors unrelated to compatibility. Prefer explicit version checks or a clearly tested adapter.
Security boundaries
Strict parsing does not make an address trustworthy. Never use the parsed text as a shell command, file path, database fragment, or authorization token. Apply validation appropriate to every destination.
Logs also deserve care. Recording complete address lists can expose personal information. Log a request identifier, count, domain summary, or redacted value when full addresses are unnecessary.
Duplicate handling
Applications often need to remove duplicates while preserving order:
def unique_recipients(addresses: list[str]) -> list[str]:
seen = set()
result = []
for address in addresses:
key = address.casefold()
if key not in seen:
seen.add(key)
result.append(address)
return result
Decide whether deduplication applies across To, Cc, and Bcc. Keep the original recipient categories when privacy or audit requirements depend on them.
Error reporting
Public error messages should be useful without exposing parser internals. “One or more recipient addresses are invalid” is often safer than echoing the full malformed input. Internal logs can include structured diagnostic details with sensitive parts removed.
Official references
The Python email.utils documentation describes helper functions and version behavior. The complete Internet Message Format is specified by RFC 5322.
Conclusion
email.utils.getaddresses(..., strict=True) gives Python applications a stronger starting point for recipient parsing. Use it with explicit checks, size limits, immutable models, security rules, and thorough tests. Strict parsing reduces ambiguity, while the surrounding architecture determines whether the final system is reliable and safe.







