- 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
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
- Implement the public contract — never subclass built-in adapters.
- Keep transport in the adapter, parsing in parsers, auth in the provider.
- Return the provider-native payload and let parsers normalize it.
- Inject dependencies explicitly — no global state or env reads.
📚 Read Next
- How to Use — the built-in Gmail flow.
- Development — running tests and docs.