- Add hand-written wiki (index, overview, how-to, extending, dev) following the platform anatomy - Remove stale nested docs/lib/mail_intake and regenerate the flat lib reference to match docforge.nav.yml - Regenerate MCP bundle with standardized docstrings
4.3 KiB
4.3 KiB
🧱 Overview
Mail Intake is a contract-first ingestion pipeline. Adapters handle transport to a provider, parsers normalize provider payloads, and the reader orchestrates the whole flow into canonical domain models.
🏗️ Architecture
┌─────────────────────────────────────────┐
│ External Provider (e.g. Gmail API) │
└─────────────────────┬───────────────────┘
│
┌─────────────────▼──────────────────┐
│ MailIntakeAdapter (transport) │ provider API calls
└─────────────────┬──────────────────┘
│ provider-native payloads
┌─────────────────▼──────────────────┐
│ Parsers (normalization) │ headers, body, subject
└─────────────────┬──────────────────┘
│ composed
┌─────────────────▼──────────────────┐
│ MailIntakeReader (orchestration) │ iter_messages / iter_threads
└─────────────────┬──────────────────┘
│
┌─────────────────▼──────────────────┐
│ MailIntakeMessage / Thread │ canonical domain models
└────────────────────────────────────┘
Layers:
- Adapters (
mail_intake.adapters) — provider-specific, read-only transport. Return provider-native payloads; never interpret them. - Auth (
mail_intake.auth) — credential acquisition and lifecycle management, decoupled from adapters. - Credentials (
mail_intake.credentials) — persistence of auth tokens;PickleCredentialStorelocally,RedisCredentialStorefor production. - Parsers (
mail_intake.parsers) — extract headers, body text, sender, and normalized subjects from provider payloads. - Ingestion (
mail_intake.ingestion) —MailIntakeReaderwires an adapter + parsers into iterators over canonical models. - Models (
mail_intake.models) — provider-agnosticMailIntakeMessageandMailIntakeThread.
📦 Domain models
MailIntakeMessage:
| Field | Type | Meaning |
|---|---|---|
message_id |
str |
Provider message id |
thread_id |
str |
Conversation thread id |
timestamp |
datetime |
Message timestamp |
from_email |
str |
Sender email |
from_name |
str | None |
Sender display name |
subject |
str |
Message subject |
body_text |
str |
Extracted plain-text body |
snippet |
str |
Provider snippet |
raw_headers |
dict[str, str] |
Unmodified headers |
MailIntakeThread:
| Field | Type | Meaning |
|---|---|---|
thread_id |
str |
Conversation id |
normalized_subject |
str |
Normalized subject (threads share one) |
participants |
set[str] |
Distinct senders |
messages |
list[MailIntakeMessage] |
Ordered messages |
last_activity_at |
datetime | None |
Latest message time |
🔒 Design guarantees
- Read-only access — no mutation of provider state.
- Provider-agnostic domain models.
- Explicit configuration and dependency injection (no implicit env reads).
- Extensible via public contracts; built-in adapters are reference implementations and may change internally.
📚 Read Next
- How to Use — the Gmail ingestion flow.
- Extending Mail Intake — custom adapters and stores.