Lib/email/headerregistry.py
cpython 3.14 @ ab2d84fe1023/Lib/email/headerregistry.py
Lib/email/headerregistry.py is the header-object layer that EmailPolicy calls into when
reading or writing headers. Instead of returning raw strings, HeaderRegistry dispatches to
a type-specific class depending on the header name. The result is that msg['From'] gives
back an Address object rather than a plain string, and msg['Date'] gives back a
datetime.
Map
| Lines | Symbol | Role |
|---|---|---|
| 1-80 | BaseHeader | Mixin that all header classes inherit; stores name and value, provides fold() |
| 81-145 | UniqueUnstructuredHeader, UniqueMessageIDHeader | Unstructured and message-ID header types |
| 146-220 | DateHeader, AddressHeader | Typed headers that parse into datetime and Address objects |
| 221-310 | MIMEVersionHeader, ParameterizedMIMEHeader | MIME-specific header types with parameter parsing |
| 311-440 | Address, Group | Structured address and group types |
| 441-500 | HeaderRegistry | Dispatch table; maps lowercase header names to classes |
Reading
HeaderRegistry dispatch
HeaderRegistry.__call__ is the entry point. Given a header name and a raw value string it
looks up the registered class for that name (falling back to UnstructuredHeader for unknown
headers) and builds a new type dynamically via type(), merging BaseHeader with the
registered class.
# CPython: Lib/email/headerregistry.py:441 HeaderRegistry.__call__
def __call__(self, name, value):
cls = self.registry.get(name.lower(), self.base_class)
return cls(name, value)
The dynamic type() merge allows any header class to pick up BaseHeader behaviour
(folding, source tracking) without needing to inherit from it explicitly in the class body.
Address and structured parse
AddressHeader.parse calls email._parseaddr to turn a raw string like
"Alice <alice@example.com>" into (display_name, addr_spec) tuples, then wraps each
result in an Address object.
# CPython: Lib/email/headerregistry.py:195 AddressHeader.parse
@staticmethod
def parse(value, kwds):
kwds['parse_tree'] = parse_tree = parser.get_address_list(value)[0]
kwds['decoded'] = str(parse_tree)
kwds['groups'] = [Group(dn, [Address(dn, addr_spec=addr)])
for dn, addr in parse_tree.as_address_list()]
kwds['addresses'] = [address
for group in kwds['groups']
for address in group.addresses]
DateHeader.parse
DateHeader.parse calls utils.parsedate_to_datetime, which returns a timezone-aware
datetime.datetime if the date string includes a timezone, or a naive datetime otherwise.
gopy notes
Not yet ported. The planned package path is module/email/headerregistry. The Go mirror
will need a HeaderRegistry map from string to a factory function, and concrete types for
Address, Group, and the date/MIME families.
CPython 3.14 changes
Python 3.14 added Address.display_name as a property alias. The HeaderRegistry default
set is unchanged; extensions continue to register custom classes via map_to_type.