> ## 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.

# Core concepts

> A short glossary of the ideas the rest of the manual builds on: organizations, accounts, IDs, blobs, capabilities, and fail-loud.

This page defines the handful of terms you need before reading the rest of the manual. Each concept has a short definition and a pointer to the Architecture Decision Record (ADR) that decided it, in the OxiMail server repository, where the reasoning lives. This is a glossary, not a how-to.

## Organization

An **organization** is an isolated customer of an OxiMail instance: a company, a public body, a hospital, a university, anything that gets its own walled-off slice of a shared server. In the storage model an organization is a *tenant*, identified by a `tenant_id`. Every object in the system, every mailbox, email, calendar, contact, and blob, belongs to exactly one organization. Isolation is enforced in the storage layer, not just in access-control checks: `tenant_id` is a mandatory parameter on every store method, and every SQL query carries a `WHERE tenant_id = ?` clause. A bug in a request handler cannot physically reach another organization's rows. This is defense in depth, separate from and underneath role-based access control.

Decided in **ADR-015** (tenant isolation at the storage layer). The ADR also documents two narrow, deliberate exceptions where a query runs without the `tenant_id` filter: the cross-tenant spam-feedback aggregation, which contains no personal data, and the WebAuthn discoverable-credential lookup, which has no tenant context yet because resolving it is the whole point of that query.

## Account and Principal

OxiMail keeps three concepts that other servers tend to blur cleanly apart, following RFC 9670:

* **User** is a human who authenticates. A user has credentials and belongs to an organization.
* **Account** is a data space: a set of mailboxes, calendars, and contacts. Each user has a primary account and can be granted access to other accounts through sharing.
* **Principal** is a shareable identity. A user is a principal; so is a group, and so is a resource such as a meeting room. You share an account, or objects within it, with a principal.

Keeping these separate makes both sharing and multi-tenancy unambiguous: an organization contains users and accounts, and an account is shared with a principal.

Decided in **ADR-012** (explicit Account/Principal model).

## UUIDv7 IDs

Every object ID in OxiMail is a **UUIDv7**, written as lowercase hex with dashes (for example `550e8400-e29b-71d4-a716-446655440000`). There is no custom encoding. UUIDv7 is time-ordered, so newer IDs sort after older ones, which gives chronological ordering and pagination for free. Validation is standard: a string is either a valid UUID or it is not. A malformed ID is never silently dropped; it immediately returns `notFound`.

Decided in **ADR-008** (UUIDv7 for all IDs).

## Blob

A **blob** is a piece of opaque content, most often the raw bytes of an email or an attachment. Blobs are content-addressed: a blob's identifier is the SHA-256 hash of its content. Two identical attachments therefore resolve to the same blob and are stored once. Deduplication happens only at this storage layer and only by content hash, never by `Message-Id`: two emails that share a `Message-Id` are always two distinct Email objects, even if they point at the same underlying blob. This is what makes sending mail to yourself work correctly.

When an email is ingested it is parsed exactly once. The raw RFC 5322 bytes are stored as a blob, and a compact structured snapshot (parsed headers, flags, thread references, derived fields such as `hasAttachment`) is stored in the database. Reads never re-parse the raw message: queries use the structured snapshot, and the raw blob is kept for faithful export, MIME download, and signature re-verification.

Decided in **ADR-014** (blob dedup by content hash) and **ADR-009** (store raw plus structured).

## Capabilities

A **capability** is a feature set the server advertises in the JMAP session, identified by a URI such as `urn:ietf:params:jmap:mail`. A client opts in to the capabilities it intends to use by listing them in the `using` array of a request; calling a method whose capability was not requested is an error, not a silent success.

OxiMail advertises two generations of capabilities side by side. The v1 capabilities are the standard RFC 8620 / RFC 8621 set. Alongside them it advertises a modernized v2 set under the `urn:oximail:params:jmap:v2:*` namespace. Both are visible in the session, and a request may use either one or both at the same time. Each handler registers its v2 URN as an additional capability, so a request that lists both a v1 capability and its v2 counterpart receives the union of their properties. The dispatcher keeps a mutual-exclusion mechanism, but its pair list is currently empty, so no combination is rejected today (the mechanism is retained for a possible future generation). Which capabilities a given account actually sees is filtered down by its organization plan and its account role; these levels can only restrict the server set, never enlarge it.

See **ADR-028** (dynamic accountCapabilities) for the per-account filtering model. For the wire detail of the session and the `using` array, see [JMAP Core](/developer/jmap-core).

## Fail-loud

**Fail-loud** is the project's first rule: OxiMail never silently drops data and never swallows an error. An invalid ID is reported in `notFound`, not discarded. A serialization failure returns `serverFail`, not an empty object. An email that was accepted with `250 OK` is always delivered somewhere, even if later processing fails. Defaults are never used to mask an error, and a Rust `Result` is never quietly ignored. This principle is enforced in the code by `clippy::unwrap_used` and `clippy::expect_used` deny rules, so a stray `unwrap()` in production code fails the build.

Decided in **ADR-027** (fail-silent audit), which records the original sweep that fixed every fail-silent pattern then known and put the lint gate in place.

## Where to go next

* [Architecture at a glance](/architecture) for how these concepts sit inside the single binary.
* [JMAP Core](/developer/jmap-core) for the session, capabilities, and request format on the wire.
