> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oximail.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# Mailboxes & storage

> What lives where on disk: the SQLite database, the content-addressed blob directory, the search index; quotas, trash and undelete, retention windows, and the storage maintenance commands.

An OxiMail instance stores everything in three places, all under your control:

| Location (defaults)        | Contents                                                                                                                                     | Config key              |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `/var/lib/oximail/data.db` | The SQLite database: folders, message metadata, flags, contacts, events, tasks, the change log — everything structured. SQLCipher-encrypted. | `[storage] sqlite_path` |
| `/var/lib/oximail/blobs/`  | The content-addressed blob store: raw messages, attachments, file-storage content. Encrypted per the [at-rest model](./encryption-at-rest).  | `[storage] blob_path`   |
| the search index directory | The Tantivy full-text index. Rebuildable at any time from the other two.                                                                     | `[storage] search_path` |

Plus `/etc/oximail/` — config, DKIM keys, and the **key material** without which the two data stores are ciphertext. The three data locations plus `/etc/oximail` are the complete backup surface ([operations](./operations)).

## How mail is laid out

A message is stored **once, in two forms** (ADR-009): the raw RFC 5322 bytes as a blob, and the parsed metadata (headers, structure, `hasAttachment`, preview, thread) as rows. Nothing re-parses on read. Blobs are addressed by the SHA-256 of their cleartext, so an attachment sent to ten colleagues is stored once per organization — deduplication happens below the mailbox level, and two copies of an email in two mailboxes are always two metadata rows pointing at one blob (never deduplicated at the message level; that class of bug is designed out).

The blob directory is namespaced per organization and per account (`{tenant}/{account}/…`, with a reserved `_tenant/` area for organization-wide content), which is what makes per-account crypto-erasure and per-organization isolation physical rather than logical.

## Folders

Folders are JMAP Mailboxes with RFC 8621 roles (`inbox`, `sent`, `drafts`, `trash`, `junk`, `archive`), provisioned per account in the account's language. Hierarchy, per-folder counts, and sharing (`shareWith`) are all data. The IMAP bridge shows the same tree. Duplicate folders left over from old imports are repaired with `oximail account dedupe-folders` ([migration](./migration)).

## Trash, undelete, and retention

Destruction is **two-stage with a visible trash** (ADR-035): a destroyed object lands in `deleted_items` and can be restored — this backs the trash surfaces in every client and the recovery of destroyed DAV resources. Independent of user-facing trash, two retention windows matter operationally:

* **`change_log`: 90 days.** The delta-sync history (`/changes`, `sync-collection`) is pruned past 90 days; a client absent longer than that does a full resync instead of an incremental one. This is by design — the change log is a sync mechanism, not an audit trail.
* **`audit_log`: years.** The administrative audit trail has its own long horizon with an enforcing retention worker ([compliance](./compliance)).

Blob garbage collection removes blobs no longer referenced by any row — with reference tracking that includes non-obvious holders like edit history, so GC never orphans content that something can still display.

## Quotas

* **Per account**: `oximail account quota --account <email> --mb <n>` (0 = no per-account limit). Exposed to clients via `Quota/get`.
* **Per collection**: volume caps (ADR-072) bound what any single collection can grow to.
* **Chat capacity caps** are separate ([multi-tenancy](./multi-tenancy)).

## The search index is disposable

The Tantivy index carries no primary data. If it is lost, corrupted, or you change its storage, rebuild it:

```bash theme={null}
oximail reindex --config /etc/oximail/oximail.toml ...
```

Reindexing streams every message through the same extraction used at ingestion; a background queue converges the work. Note the index is the one store whose content is **not** encrypted per account (it must be tokenized server-side to be searchable) — which is why account erasure sweeps it explicitly.

## Database maintenance

None scheduled — this is deliberate. WAL checkpointing is automatic (bounded at \~64 MiB, checkpointed at shutdown), query-planner statistics are refreshed after migrations, and the connection pool needs no tuning below a few hundred concurrent users (`[storage] pool_size`, default 32, raise on read-heavy machines). The operational database story is: keep disk space, keep [backups](./operations), and let the server run.

`oximail sql` exists as a guarded escape hatch for support scenarios; day-to-day inspection goes through the CLI verbs (`oximail mailbox`, `oximail email`) and the admin API's per-account data views.
