# 🧱 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 ```text ┌─────────────────────────────────────────┐ │ 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: 1. **Adapters** (`mail_intake.adapters`) — provider-specific, read-only transport. Return provider-native payloads; never interpret them. 2. **Auth** (`mail_intake.auth`) — credential acquisition and lifecycle management, decoupled from adapters. 3. **Credentials** (`mail_intake.credentials`) — persistence of auth tokens; `PickleCredentialStore` locally, `RedisCredentialStore` for production. 4. **Parsers** (`mail_intake.parsers`) — extract headers, body text, sender, and normalized subjects from provider payloads. 5. **Ingestion** (`mail_intake.ingestion`) — `MailIntakeReader` wires an adapter + parsers into iterators over canonical models. 6. **Models** (`mail_intake.models`) — provider-agnostic `MailIntakeMessage` and `MailIntakeThread`. --- ## 📦 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](02_how_to_use.md) — the Gmail ingestion flow. - [Extending Mail Intake](03_extending.md) — custom adapters and stores.