- 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
91 lines
4.3 KiB
Markdown
91 lines
4.3 KiB
Markdown
# 🧱 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. |