docs(mail_intake): add comprehensive docstrings across ingestion, adapters, auth, and parsing layers

- docs(mail_intake/__init__.py): document module-based public API and usage patterns
- docs(mail_intake/ingestion/reader.py): document high-level ingestion orchestration
- docs(mail_intake/adapters/base.py): document adapter contract for mail providers
- docs(mail_intake/adapters/gmail.py): document Gmail adapter implementation and constraints
- docs(mail_intake/auth/base.py): document authentication provider contract
- docs(mail_intake/auth/google.py): document Google OAuth authentication provider
- docs(mail_intake/models/message.py): document canonical email message model
- docs(mail_intake/models/thread.py): document canonical email thread model
- docs(mail_intake/parsers/body.py): document message body extraction logic
- docs(mail_intake/parsers/headers.py): document message header normalization utilities
- docs(mail_intake/parsers/subject.py): document subject normalization utilities
- docs(mail_intake/config.py): document global configuration model
- docs(mail_intake/exceptions.py): document library exception hierarchy
This commit is contained in:
2026-01-09 17:40:25 +05:30
parent dbfef295b8
commit f22af90e98
18 changed files with 751 additions and 71 deletions

View File

@@ -0,0 +1,28 @@
"""
Mail provider adapter implementations for Mail Intake.
This package contains **adapter-layer implementations** responsible for
interfacing with external mail providers and exposing a normalized,
provider-agnostic contract to the rest of the system.
Adapters in this package:
- Implement the `MailIntakeAdapter` interface
- Encapsulate all provider-specific APIs and semantics
- Perform read-only access to mail data
- Return provider-native payloads without interpretation
Provider-specific logic **must not leak** outside of adapter implementations.
All parsings, normalizations, and transformations must be handled by downstream
components.
Public adapters exported from this package are considered the supported
integration surface for mail providers.
"""
from .base import MailIntakeAdapter
from .gmail import MailIntakeGmailAdapter
__all__ = [
"MailIntakeAdapter",
"MailIntakeGmailAdapter",
]

View File

@@ -1,3 +1,14 @@
"""
Mail provider adapter contracts for Mail Intake.
This module defines the **provider-agnostic adapter interface** used for
read-only mail ingestion.
Adapters encapsulate all provider-specific access logic and expose a
minimal, normalized contract to the rest of the system. No provider-specific
types or semantics should leak beyond implementations of this interface.
"""
from abc import ABC, abstractmethod
from typing import Iterator, Dict, Any
@@ -6,43 +17,60 @@ class MailIntakeAdapter(ABC):
"""
Base adapter interface for mail providers.
This interface defines the minimal contract required for
read-only mail ingestion. No provider-specific concepts
should leak beyond implementations of this class.
This interface defines the minimal contract required to:
- Discover messages matching a query
- Retrieve full message payloads
- Retrieve full thread payloads
Adapters are intentionally read-only and must not mutate provider state.
"""
@abstractmethod
def iter_message_refs(self, query: str) -> Iterator[Dict[str, str]]:
"""
Iterate over lightweight message references.
Iterate over lightweight message references matching a query.
Must yield dictionaries containing at least:
- message_id
- thread_id
Implementations must yield dictionaries containing at least:
- ``message_id``: Provider-specific message identifier
- ``thread_id``: Provider-specific thread identifier
Args:
query: Provider-specific query string used to filter messages.
Yields:
Dictionaries containing message and thread identifiers.
Example yield:
{
"message_id": "...",
"thread_id": "..."
}
{
"message_id": "...",
"thread_id": "..."
}
"""
raise NotImplementedError
@abstractmethod
def fetch_message(self, message_id: str) -> Dict[str, Any]:
"""
Fetch a full raw message by message_id.
Fetch a full raw message by message identifier.
Returns the provider-native message payload
(e.g., Gmail message JSON).
Args:
message_id: Provider-specific message identifier.
Returns:
Provider-native message payload
(e.g., Gmail message JSON structure).
"""
raise NotImplementedError
@abstractmethod
def fetch_thread(self, thread_id: str) -> Dict[str, Any]:
"""
Fetch a full raw thread by thread_id.
Fetch a full raw thread by thread identifier.
Returns the provider-native thread payload.
Args:
thread_id: Provider-specific thread identifier.
Returns:
Provider-native thread payload.
"""
raise NotImplementedError

View File

@@ -1,3 +1,17 @@
"""
Gmail adapter implementation for Mail Intake.
This module provides a **Gmail-specific implementation** of the
`MailIntakeAdapter` contract.
It is the only place in the codebase where:
- `googleapiclient` is imported
- Gmail REST API semantics are known
- Low-level `.execute()` calls are made
All Gmail-specific behavior must be strictly contained within this module.
"""
from typing import Iterator, Dict, Any
from googleapiclient.discovery import build
@@ -12,12 +26,19 @@ class MailIntakeGmailAdapter(MailIntakeAdapter):
"""
Gmail read-only adapter.
This adapter implements the `MailIntakeAdapter` interface using the
Gmail REST API. It translates the generic mail intake contract into
Gmail-specific API calls.
This class is the ONLY place where:
- googleapiclient is imported
- Gmail REST semantics are known
- .execute() is called
It must remain thin and dumb by design.
Design constraints:
- Must remain thin and imperative
- Must not perform parsing or interpretation
- Must not expose Gmail-specific types beyond this class
"""
def __init__(
@@ -25,12 +46,29 @@ class MailIntakeGmailAdapter(MailIntakeAdapter):
auth_provider: MailIntakeAuthProvider,
user_id: str = "me",
):
"""
Initialize the Gmail adapter.
Args:
auth_provider: Authentication provider capable of supplying
valid Gmail API credentials.
user_id: Gmail user identifier. Defaults to `"me"`.
"""
self._auth_provider = auth_provider
self._user_id = user_id
self._service = None
@property
def service(self):
"""
Lazily initialize and return the Gmail API service client.
Returns:
Initialized Gmail API service instance.
Raises:
MailIntakeAdapterError: If the Gmail service cannot be initialized.
"""
if self._service is None:
try:
creds = self._auth_provider.get_credentials()
@@ -45,11 +83,16 @@ class MailIntakeGmailAdapter(MailIntakeAdapter):
"""
Iterate over message references matching the query.
Args:
query: Gmail search query string.
Yields:
{
"message_id": "...",
"thread_id": "..."
}
Dictionaries containing:
- ``message_id``: Gmail message ID
- ``thread_id``: Gmail thread ID
Raises:
MailIntakeAdapterError: If the Gmail API returns an error.
"""
try:
request = (
@@ -79,6 +122,18 @@ class MailIntakeGmailAdapter(MailIntakeAdapter):
) from exc
def fetch_message(self, message_id: str) -> Dict[str, Any]:
"""
Fetch a full Gmail message by message ID.
Args:
message_id: Gmail message identifier.
Returns:
Provider-native Gmail message payload.
Raises:
MailIntakeAdapterError: If the Gmail API returns an error.
"""
try:
return (
self.service.users()
@@ -92,6 +147,18 @@ class MailIntakeGmailAdapter(MailIntakeAdapter):
) from exc
def fetch_thread(self, thread_id: str) -> Dict[str, Any]:
"""
Fetch a full Gmail thread by thread ID.
Args:
thread_id: Gmail thread identifier.
Returns:
Provider-native Gmail thread payload.
Raises:
MailIntakeAdapterError: If the Gmail API returns an error.
"""
try:
return (
self.service.users()