Files
mail-intake/docs/wiki/03_extending.md
Vishesh 'ironeagle' Bangotra 370d1272bf docs: add wiki and refresh flat lib with mcp artifacts
- 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
2026-09-16 20:02:50 +05:30

2.5 KiB

🧩 Extending Mail Intake

Mail Intake is designed to be extended through its public contracts. Implement your own adapter, auth provider, or credential store to support a new provider or storage backend.


📬 Custom adapters

Subclass MailIntakeAdapter to integrate a new provider. Adapters perform read-only transport and return provider-native payloads:

from mail_intake.adapters import MailIntakeAdapter

class ExchangeAdapter(MailIntakeAdapter):
    def __init__(self, auth_provider):
        self._auth = auth_provider

    def fetch_messages(self, query):
        # call the provider API, return native payloads
        ...

    def fetch_threads(self, query):
        ...

Do not subclass built-in adapters like MailIntakeGmailAdapter — they are reference implementations and may change internally without notice.


🔐 Custom auth providers

Subclass MailIntakeAuthProvider[T] to own a different credential flow:

from mail_intake.auth import MailIntakeAuthProvider

class ExchangeAuth(MailIntakeAuthProvider[exchange_credentials]):
    def get_credentials(self):
        return self._store.load()

    def refresh(self):
        ...

Auth providers remain decoupled from adapter logic — they only manage credentials.


🗄️ Custom credential stores

Implement the CredentialStore[T] contract for a new persistence backend:

from mail_intake.credentials import CredentialStore

class S3CredentialStore(CredentialStore):
    def save(self, credentials):
        ...

    def load(self):
        ...

    def delete(self):
        ...

The store abstraction keeps tokens out of config and rotates safely.


🧪 Wiring a custom backend

from mail_intake.ingestion import MailIntakeReader

auth = ExchangeAuth(store=S3CredentialStore(...))
adapter = ExchangeAdapter(auth_provider=auth)
reader = MailIntakeReader(adapter)

for message in reader.iter_messages("query"):
    print(message.subject)

The reader only depends on the adapter contract, so the rest of the pipeline keeps working unchanged.


Extension checklist

  1. Implement the public contract — never subclass built-in adapters.
  2. Keep transport in the adapter, parsing in parsers, auth in the provider.
  3. Return the provider-native payload and let parsers normalize it.
  4. Inject dependencies explicitly — no global state or env reads.