Data model
Supermail is an event log of change notifications — not a mail store. It never keeps your emails.
The single most important thing to understand about Supermail:
Supermail does not store your emails. It keeps a durable, append-only event log of what changed in each mailbox. The message bodies and attachments themselves are never stored here; they stay at the provider.
An event log, not a mailbox
For every connected account, Supermail maintains an ordered event log: one immutable event per observed change — a message received, a flag flipped, a message deleted, a folder renamed, a sync completing. Message events are thin notifications: they identify the message and its mailbox occurrences, and carry no addresses, flags, attachment descriptors, or body.
This is what Supermail is: a normalization and change-capture layer over messy providers, exposed as one ordered log. It is deliberately not a system of record for mail.
Notifications, not content
Events never carry message content or content handles. Mail metadata and raw bytes reach authorized consumers only through client-owned mail replication and its content lane, which re-fetches the bytes from the provider on demand and streams them as bounded binary frames, never as a JSON-RPC message.
Folding the log into state is your concern
The log tells you what changed. If you want current state — a mailbox mirror, an unread count, a search index — you fold the event log into that state yourself. Supermail intentionally does not maintain it for you.
Folding is straightforward because of two guarantees:
- Order by
(account_id, seq). Each event has a per-account monotonically increasingseq. Apply events inseqorder and treat the highestseqyou have seen as current. - Placements are complete. An
email.updatedevent carries the message's complete current mailbox occurrences, not a diff — so a consumer that missed or reordered an earlier event still converges to the right placement state (the fold is self-healing).
Combined with at-least-once delivery, this means your materializer must be
idempotent: deduplicate on event.id
and last-writer-by-seq wins.
provider changes ──▶ Supermail ──▶ append to event log (change notifications)
│
list events / webhook push │ your app
▼
fold into your own state ◀── you own thisRetention & replay
The log is durable and replayable within a retention window: you can list retained history and receive new events through a webhook consumer. Past the retention window an event is garbage-collected and can only be recovered by re-fetching from the source where the source still has it. This is why consumers that need long-term state keep their own folded copy rather than treating Supermail as permanent storage. The retention window is consumption-derived with a TTL floor and cap — see Events → Retention & recovery for how the buffer drops events, when it redelivers, and how to refetch gaps or the whole window.