Files
mail-intake/mail_intake/parsers/headers.py

103 lines
2.9 KiB
Python

"""
# Summary
Message header parsing utilities for Mail Intake.
This module provides helper functions for normalizing and extracting
useful information from provider-native message headers.
The functions here are intentionally simple and tolerant of malformed
or incomplete header data.
"""
from typing import Dict, List, Tuple, Optional
def parse_headers(raw_headers: List[Dict[str, str]]) -> Dict[str, str]:
"""
Convert a list of Gmail-style headers into a normalized dict.
Args:
raw_headers (List[Dict[str, str]]):
List of header dictionaries, each containing `name` and `value` keys.
Returns:
Dict[str, str]:
Dictionary mapping lowercase header names to stripped values.
Notes:
**Guarantees:**
- Provider payloads (such as Gmail) typically represent headers as a
list of name/value mappings.
- This function normalizes them into a case-insensitive dictionary
keyed by lowercase header names.
Example:
Typical usage:
```python
Input:
[
{"name": "From", "value": "John Doe <john@example.com>"},
{"name": "Subject", "value": "Re: Interview Update"},
]
Output:
{
"from": "John Doe <john@example.com>",
"subject": "Re: Interview Update",
}
```
"""
headers: Dict[str, str] = {}
for header in raw_headers or []:
name = header.get("name")
value = header.get("value")
if not name or value is None:
continue
headers[name.lower()] = value.strip()
return headers
def extract_sender(headers: Dict[str, str]) -> Tuple[str, Optional[str]]:
"""
Extract sender email and optional display name from headers.
Args:
headers (Dict[str, str]):
Normalized header dictionary as returned by `parse_headers()`.
Returns:
Tuple[str, Optional[str]]:
A tuple `(email, name)` where `email` is the sender email address
and `name` is the display name, or `None` if unavailable.
Notes:
**Responsibilities:**
- This function parses the `From` header and attempts to extract
sender email address and optional human-readable display name.
Example:
Typical values:
- `"John Doe <john@example.com>"` -> `("john@example.com", "John Doe")`
- `"john@example.com"` -> `("john@example.com", None)`
"""
from_header = headers.get("from")
if not from_header:
return "", None
if "<" in from_header and ">" in from_header:
name_part, email_part = from_header.split("<", 1)
email = email_part.rstrip(">").strip()
name = name_part.strip().strip('"') or None
return email, name
return from_header.strip(), None