Architecture
MailDesk is built on a clean, layered ("onion") design: a provider-agnostic core owns the data, and provider-specific logic (Gmail/Graph/IMAP) and Odoo-app integrations live at the edges. This page is the map; deeper write-ups live in each module's in-repo docs/ and in the developer-only internal/architecture/ set (ADRs, contracts, dataflows).
MailDesk is built on a clean, layered ("onion") design: a provider-agnostic core owns the data, and
provider-specific logic (Gmail/Graph/IMAP) and Odoo-app integrations live at the edges. This page is the
map; deeper write-ups live in each module's in-repo docs/ and in the developer-only
internal/architecture/ set (ADRs, contracts, dataflows).
Module dependency graph
graph TD
web & contacts & mail & google_gmail & microsoft_outlook --> B[Basic<br/>maildesk_mail_client]
B --> P[Pro<br/>maildesk_mail_client_pro<br/>AI · 2-way sync · mobile · realtime]
P --> AUTO[Automation]
P --> CAL[Calendar]
P --> CHAT[Chatter]
P --> CRM[CRM]
P --> DOC[Documents]
P --> HD[Helpdesk]
P --> P360[Partner 360]
P --> SALE[Sales]
P --> COCK[Cockpit]
AUTO --> COCK
resource[resource] --> COCK
The single source of truth (SSOT)
Everything hangs off one principle: maildesk.message_index is the authoritative record of every
message, keyed by a delivery_key of (account, provider, folder, uid). Bodies and attachment lists
are kept in a separate time-limited cache (maildesk.ui_cache); importing into Odoo's native
mail.thread happens through a durable queue. Derived/read-side views (Cockpit, Partner 360) never
become a second owner of that truth. (See internal/architecture/adr/ADR-001-ssot-ownership.md.)
graph LR
subgraph Providers
G[Gmail API] ; O[Graph API] ; I[IMAP]
end
G & O & I -->|scheduled sync| MI[(maildesk.message_index<br/>SSOT)]
MI --> UC[(maildesk.ui_cache<br/>bodies/attachments TTL)]
MI --> IQ[[maildesk.ingest_queue]]
IQ --> MT[(Odoo mail.thread / mail.message)]
ES[(maildesk.email_state<br/>read/star/archive)] --- MI
MI --> EL[(maildesk.email.link → Odoo records)]:::pro
ES -->|Pro: 2-way| UQ[[maildesk.update_queue]]:::pro
UQ -->|mutation executors| G & O & I
classDef pro fill:#efe6ff,stroke:#714697;
- Inbound (Basic): provider → SSOT → cache; the ingest queue materialises selected messages into
mail.thread. One-way. - Outbound (Pro, two-way): a user action (mark read, move, delete, flag) updates
maildesk.email_stateand enqueues a coalesced mutation onmaildesk.update_queue; per-provider executors apply it back to Gmail/Graph/IMAP with lease-locking and backoff.
Layers
| Layer | Responsibility | Examples |
|---|---|---|
| Domain / use-cases | Provider-agnostic business logic | open_thread_messages, warm_message_cache, detect_imap_profile |
| Adapters | Bridge use-cases to Odoo ORM / RPC | *_adapter.py |
| Infrastructure | Provider SDKs, persistence, transport | gmail/, outlook/, imap/, repositories |
| Presentation | OWL components, services, hooks (frontend) | static/src/... |
Provider-specific code is confined to the infrastructure layer
(internal/architecture/adr/ADR-010-provider-boundaries.md); integration bridges must not become second
platforms (ADR-007-bridge-addon-rules.md).
Synchronization (overview)
Stable builds deliver mail through scheduled jobs and refresh the open UI over Odoo's websocket bus; 4.2.0 adds true push for Gmail/Outlook and body prefetch. Full detail, including the exact mechanism per provider and the stable-vs-4.2.0 split, is in Synchronization and Realtime architecture.
AI (overview)
AI lives in Pro (and Cockpit for manager briefings) behind a single authorization chokepoint, with a deliberately narrow data boundary — the AI is handed only the email/thread in front of the user, never the whole inbox or arbitrary Odoo records. Provider abstraction supports OpenAI/Gemini/Claude/Grok/DeepSeek and self-hosted servers. See AI architecture and the user-facing AI permissions & data access.
Mobile (overview)
The adaptive phone/tablet UI is Pro-only and auto-detected (no configuration). Pro patches Basic's widgets and adds mobile OWL services/hooks/components plus a mobile dark theme. See Mobile and Frontend assets.
Further reading
- In-module developer docs (current): Basic
docs/architecture_overview.md,docs/clean_onion_architecture.md,docs/dataflow/*,docs/ui_cache_and_ssot.md,docs/invariants_and_guarantees.md. - Developer-only architecture/refactor set:
internal/architecture/(findings, contracts, ADRs 001–012, module inventory, roadmap).
Maps reflect the Basic + Pro source trees (v18) and the 4.2.0 branches; see linked pages for citations.