Claude Code for email.headerregistry: Python Typed Email Headers — Claude Skills 360 Blog
Blog / AI / Claude Code for email.headerregistry: Python Typed Email Headers
AI

Claude Code for email.headerregistry: Python Typed Email Headers

Published: February 1, 2029
Read time: 5 min read
By: Claude Skills 360

Python’s email.headerregistry module provides typed header objects that the modern email.policy (Python 3.6+) uses when parsing messages. from email.headerregistry import Address, Group, HeaderRegistry. Key classes: Address(display_name="", username="", domain="", addr_spec=None) — represents a single RFC 5322 email address; properties: .display_name, .username, .domain, .addr_spec (user@domain); str(addr) gives the fully-formatted address. Group(display_name="", addresses=()) — RFC 5322 group syntax. HeaderRegistry — the callable mapping used by email.policy.default to create the right header class from a name-value pair; can be extended. Typed header attributes (when parsed with policy.default): msg["From"].addresses → tuple of Address; msg["To"].addresses; msg["Date"].datetimedatetime; msg["Content-Type"].content_type"text/plain"; msg["Content-Type"].params{"charset": "utf-8"}. Build an Address directly: Address("Alice Smith", addr_spec="[email protected]"). Build a header string: email.utils.formataddr(("Alice", "[email protected]")). Claude Code generates RFC-compliant address parsers, typed header inspectors, display-name extractors, domain-based address filters, and structured message header validators.

CLAUDE.md for email.headerregistry

## email.headerregistry Stack
- Stdlib: from email.headerregistry import Address, Group, HeaderRegistry
-         from email import policy
-         from email.parser import BytesParser
- Address:  a = Address("Alice", addr_spec="[email protected]")
-           str(a)            # "Alice <[email protected]>"
-           a.display_name    # "Alice"
-           a.addr_spec       # "[email protected]"
-           a.username        # "alice"
-           a.domain          # "example.com"
- Group:    g = Group("Team", [a1, a2])
-           str(g)            # "Team:Alice <[email protected]>,Bob <[email protected]>;"
- Parsed:   msg = BytesParser(policy=policy.default).parsebytes(raw)
-           msg["From"].addresses    # tuple[Address, ...]
-           msg["Date"].datetime     # datetime
-           msg["Content-Type"].content_type  # "text/plain"

email.headerregistry Typed Header Pipeline

# app/emailheaderregistryutil.py — parse, inspect, filter, build, validate
from __future__ import annotations

import re
from dataclasses import dataclass, field
from datetime import datetime
from email import policy as _policy
from email.headerregistry import Address, Group, HeaderRegistry
from email.message import EmailMessage
from email.parser import BytesParser, Parser
from typing import Any


# ─────────────────────────────────────────────────────────────────────────────
# 1. Address construction and formatting
# ─────────────────────────────────────────────────────────────────────────────

def make_address(display_name: str = "",
                 addr_spec: str = "") -> Address:
    """
    Create an Address from display name and addr_spec.

    Example:
        a = make_address("Alice Smith", "[email protected]")
        print(str(a))   # "Alice Smith <[email protected]>"
    """
    return Address(display_name=display_name, addr_spec=addr_spec)


def parse_address(text: str) -> Address | None:
    """
    Parse a single RFC 5322 address string into an Address object.
    Returns None on failure.

    Example:
        a = parse_address("Bob Jones <[email protected]>")
        print(a.domain)   # "example.com"
    """
    raw = f"From: {text}\r\n\r\n"
    try:
        msg = BytesParser(policy=_policy.default).parsebytes(raw.encode())
        addrs = msg["From"].addresses
        return addrs[0] if addrs else None
    except Exception:
        return None


def format_address_list(addresses: "list[Address]") -> str:
    """
    Format a list of Address objects as a comma-separated header value.

    Example:
        addrs = [make_address("Alice", "[email protected]"), make_address("Bob", "[email protected]")]
        print(format_address_list(addrs))   # "Alice <[email protected]>, Bob <[email protected]>"
    """
    return ", ".join(str(a) for a in addresses)


# ─────────────────────────────────────────────────────────────────────────────
# 2. Typed header extraction from parsed messages
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class MessageHeaders:
    subject:       str
    from_addr:     list[Address]
    to_addrs:      list[Address]
    cc_addrs:      list[Address]
    bcc_addrs:     list[Address]
    date:          datetime | None
    message_id:    str
    content_type:  str
    charset:       str
    reply_to:      list[Address]
    in_reply_to:   str


def extract_headers(raw: "bytes | str",
                    pol: Any = _policy.default) -> MessageHeaders:
    """
    Parse raw message and extract all standard headers into typed fields.

    Example:
        with open("msg.eml", "rb") as f:
            hdrs = extract_headers(f.read())
        print(hdrs.from_addr, hdrs.date)
    """
    if isinstance(raw, bytes):
        msg: EmailMessage = BytesParser(policy=pol).parsebytes(raw)  # type: ignore
    else:
        msg = Parser(policy=pol).parsestr(raw)  # type: ignore

    def get_addrs(key: str) -> list[Address]:
        hdr = msg.get(key)
        if hdr is None:
            return []
        try:
            return list(hdr.addresses)
        except AttributeError:
            return []

    def get_date() -> datetime | None:
        hdr = msg.get("date")
        if hdr is None:
            return None
        try:
            return hdr.datetime
        except AttributeError:
            return None

    ct_hdr = msg.get("content-type")
    content_type = ""
    charset = "utf-8"
    if ct_hdr is not None:
        try:
            content_type = ct_hdr.content_type
            charset = ct_hdr.params.get("charset", "utf-8")
        except AttributeError:
            content_type = str(ct_hdr)

    return MessageHeaders(
        subject=msg.get("subject", ""),
        from_addr=get_addrs("from"),
        to_addrs=get_addrs("to"),
        cc_addrs=get_addrs("cc"),
        bcc_addrs=get_addrs("bcc"),
        date=get_date(),
        message_id=msg.get("message-id", ""),
        content_type=content_type,
        charset=charset,
        reply_to=get_addrs("reply-to"),
        in_reply_to=msg.get("in-reply-to", ""),
    )


# ─────────────────────────────────────────────────────────────────────────────
# 3. Address-based filters
# ─────────────────────────────────────────────────────────────────────────────

def filter_by_domain(addresses: "list[Address]",
                     domain: str) -> list[Address]:
    """
    Return addresses whose domain matches (case-insensitive).

    Example:
        addrs = parse_addresses_from_raw(raw)
        internal = filter_by_domain(addrs, "mycompany.com")
    """
    d = domain.lower()
    return [a for a in addresses if a.domain.lower() == d]


def extract_all_addresses(raw: "bytes | str") -> list[Address]:
    """
    Extract all unique addresses from From/To/Cc/Bcc headers.

    Example:
        addrs = extract_all_addresses(raw_bytes)
        for a in addrs:
            print(a.addr_spec)
    """
    hdrs = extract_headers(raw)
    seen: dict[str, Address] = {}
    for bucket in (hdrs.from_addr, hdrs.to_addrs,
                   hdrs.cc_addrs, hdrs.bcc_addrs):
        for a in bucket:
            key = a.addr_spec.lower()
            if key not in seen:
                seen[key] = a
    return list(seen.values())


# ─────────────────────────────────────────────────────────────────────────────
# 4. Custom HeaderRegistry extension
# ─────────────────────────────────────────────────────────────────────────────

def custom_registry_policy(extra_headers: "dict[str, Any] | None" = None) -> Any:
    """
    Build an email.policy.EmailPolicy with a custom HeaderRegistry that
    adds user-defined header handlers.  extra_headers maps lower-case
    header names to header class factories.

    Example:
        pol = custom_registry_policy({"x-priority": None})
        msg = BytesParser(policy=pol).parsebytes(raw)
    """
    reg = HeaderRegistry()
    if extra_headers:
        for name, factory in extra_headers.items():
            if factory is not None:
                reg.map_to_type(name, factory)
    return _policy.default.clone(header_factory=reg)


# ─────────────────────────────────────────────────────────────────────────────
# 5. Header validation
# ─────────────────────────────────────────────────────────────────────────────

@dataclass
class ValidationResult:
    valid:    bool
    issues:   list[str] = field(default_factory=list)


def validate_message_headers(raw: "bytes | str") -> ValidationResult:
    """
    Check that a raw message has well-formed required headers and valid addresses.

    Example:
        result = validate_message_headers(raw_email_bytes)
        if not result.valid:
            for issue in result.issues:
                print(issue)
    """
    issues: list[str] = []

    try:
        hdrs = extract_headers(raw)
    except Exception as e:
        return ValidationResult(valid=False, issues=[f"parse error: {e}"])

    if not hdrs.from_addr:
        issues.append("Missing or empty From header")
    if not hdrs.to_addrs and not hdrs.cc_addrs:
        issues.append("No recipients in To or Cc")
    if not hdrs.subject:
        issues.append("Missing Subject header")
    if not hdrs.message_id:
        issues.append("Missing Message-ID header")

    for addr in hdrs.from_addr + hdrs.to_addrs + hdrs.cc_addrs:
        if not addr.domain or "." not in addr.domain:
            issues.append(f"Suspicious address (no valid domain): {addr.addr_spec!r}")
        if not addr.username:
            issues.append(f"Suspicious address (no local part): {addr.addr_spec!r}")

    return ValidationResult(valid=len(issues) == 0, issues=issues)


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== email.headerregistry demo ===")

    sample = (
        b"From: Alice Smith <[email protected]>\r\n"
        b"To: Bob Jones <[email protected]>, [email protected]\r\n"
        b"Cc: [email protected]\r\n"
        b"Subject: Typed header demo\r\n"
        b"Date: Mon, 01 Feb 2029 12:00:00 +0000\r\n"
        b"Message-ID: <[email protected]>\r\n"
        b"Content-Type: text/plain; charset=utf-8\r\n"
        b"\r\n"
        b"Hello!\r\n"
    )

    # ── Address construction ────────────────────────────────────────────────
    print("\n--- Address ---")
    a = make_address("Dave", "[email protected]")
    print(f"  str       : {str(a)!r}")
    print(f"  display   : {a.display_name!r}")
    print(f"  addr_spec : {a.addr_spec!r}")
    print(f"  username  : {a.username!r}")
    print(f"  domain    : {a.domain!r}")

    # ── Group ───────────────────────────────────────────────────────────────
    print("\n--- Group ---")
    a1 = make_address("Alice", "[email protected]")
    a2 = make_address("Bob", "[email protected]")
    g = Group("Engineering", [a1, a2])
    print(f"  str: {str(g)!r}")

    # ── extract_headers ────────────────────────────────────────────────────
    print("\n--- extract_headers ---")
    hdrs = extract_headers(sample)
    print(f"  subject    : {hdrs.subject!r}")
    print(f"  from       : {[str(a) for a in hdrs.from_addr]}")
    print(f"  to         : {[str(a) for a in hdrs.to_addrs]}")
    print(f"  date       : {hdrs.date}")
    print(f"  content_type: {hdrs.content_type!r}")
    print(f"  charset    : {hdrs.charset!r}")

    # ── filter_by_domain ───────────────────────────────────────────────────
    print("\n--- filter_by_domain ---")
    all_addrs = extract_all_addresses(sample)
    example_addrs = filter_by_domain(all_addrs, "example.com")
    print(f"  all: {[a.addr_spec for a in all_addrs]}")
    print(f"  @example.com: {[a.addr_spec for a in example_addrs]}")

    # ── validate_message_headers ───────────────────────────────────────────
    print("\n--- validate_message_headers ---")
    good = validate_message_headers(sample)
    bad_raw = b"From: badaddr\r\nTo:\r\n\r\nbody"
    bad = validate_message_headers(bad_raw)
    print(f"  good.valid: {good.valid}  issues: {good.issues}")
    print(f"  bad.valid : {bad.valid}  issues: {bad.issues}")

    # ── parse_address ──────────────────────────────────────────────────────
    print("\n--- parse_address ---")
    for text in ["Eve <[email protected]>", "[email protected]", "bogus"]:
        parsed = parse_address(text)
        if parsed:
            print(f"  {text!r:35s}{parsed.addr_spec!r}")
        else:
            print(f"  {text!r:35s} → None")

    print("\n=== done ===")

For the email.utils stdlib companion — email.utils.parseaddr("Alice <[email protected]>")("Alice", "[email protected]") and email.utils.getaddresses(["Alice <[email protected]>, Bob <[email protected]>"])[("Alice", "[email protected]"), ("Bob", "[email protected]")] provide quick stdlib address tuple parsing without the full email.headerregistry.Address object — use email.utils for simple display-name/addr-spec extraction in scripts; use email.headerregistry.Address with policy.default when you need structured objects, Group support, or full RFC 5322 structural validation. For the flanker (PyPI) alternative — flanker.addresslib.address.parse("Alice <[email protected]>") provides production-grade RFC 5321/5322 address parsing with deliverability checks, role-address detection, and mailbox normalization — use flanker in ESPs and inbox-validation services that process untrusted user input at scale; use email.headerregistry in standard Python tools that trust the input envelope. The Claude Skills 360 bundle includes email.headerregistry skill sets covering make_address()/parse_address()/format_address_list() address builders, MessageHeaders/extract_headers() typed header extractor, filter_by_domain()/extract_all_addresses() address filters, custom_registry_policy() registry extension, and ValidationResult/validate_message_headers() header validator. Start with the free tier to try typed header patterns and email.headerregistry pipeline code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free