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

# oximail-core

> The JMAP Core foundation crate: session, method dispatch, capabilities, push, blob plumbing, errors, and the cross-domain EventBus.

`oximail-core` is the foundation crate every other domain crate builds on. It implements **JMAP Core** ([RFC 8620](https://www.rfc-editor.org/rfc/rfc8620)): the session resource a client discovers the server with, the dispatcher that routes a batch of method calls, the capability model that gates them, the push delivery types, the blob and ID primitives, the typed error vocabulary, and the `EventBus` that lets domain crates talk to each other without importing one another.

## Overview

Every authenticated JMAP request passes through this crate. The HTTP layer in `oximail-server` parses the request, builds a `RequestContext`, and hands it to the `MethodRegistry` defined here. The registry resolves back-references, checks capabilities and access, and dispatches each call to the handler registered for that method name. Domain crates (`oximail-mail`, `oximail-calendar`, `oximail-contact`, and the rest) implement the `JmapMethod` trait and register their handlers; `oximail-core` itself owns only the cross-cutting machinery and a small set of core-level methods.

It sits at the bottom of the request path. It depends on `oximail-store` for the ID, blob, and state primitives, and on nothing above it. The mail crate never imports the calendar crate; both depend on `oximail-core` and communicate through its `EventBus`.

## Features

* **Session resource** (RFC 8620 §2): the single discovery document served at `/.well-known/jmap`, listing capabilities, accounts, primary accounts, and the API / upload / download / EventSource URLs.
* **Method dispatch** (RFC 8620 §3.5): a registry of `JmapMethod` handlers keyed by method name, executing each call in a batched request in order.
* **Back-reference resolution** (RFC 8620 §3.7): creation references (`#clientId`) and result references (`{ "resultOf", "name", "path" }`, including `#`-prefixed keys and the `*` wildcard JSON Pointer).
* **Capability model** (RFC 8620 §2, ADR-028): server-level capabilities, dynamic per-account capabilities, and the v1 / v2 URN surfaces advertised side by side.
* **Typed error vocabulary** (RFC 8620 §3.6): request-level, method-level, and set-level error enums that serialize to the exact JMAP wire `type`.
* **Generic filter machinery**: a recursive AND / OR / NOT combinator shared by every `Foo/query` method.
* **Push delivery types** (RFC 8620 §7): push subscriptions, the `StateChange` notification payload, and the Web Push (RFC 8291) and VAPID primitives behind EventSource and WebSocket delivery.
* **EventBus** (ADR-011): a typed publish / subscribe channel for cross-domain events.
* **Core-level methods**: `Core/echo`, `PushSubscription/*`, plus the saved-message (bookmark) and message-task-link types and the v2 streaming surfaces.

## How it works

### The session resource

A client begins by fetching the session resource. `Session::build` assembles the server-level `capabilities` map, the `accounts` map (the user's personal account plus any shared accounts), the `primaryAccounts` map, the API / upload / download / EventSource URL templates, and an opaque `state` string. The limits announced in the Core capability (`maxSizeUpload`, `maxCallsInRequest`, `maxObjectsInGet`, and the rest) are defined as constants in this crate so that the values advertised in the session and the values enforced at dispatch come from one source of truth.

`Session::build_for_account` layers the ADR-028 pipeline on top: it computes the per-account capabilities from the organization's plan and the account's role, and trims `primaryAccounts` to only the capabilities the account actually has. Shared accounts are added separately by `add_shared_accounts`, each keyed `shared:{ownerId}` and carrying only the capabilities for the object types that were shared.

### Dispatch and back-references

`MethodRegistry::process` walks the method calls of a request in order. For each call it:

1. **Resolves back-references** in the arguments. A string `"#name"` is replaced by the server id created earlier in the batch; an object with `resultOf` / `name` / `path` (or a `#`-prefixed key) is replaced by the value at that JSON Pointer in a prior call's result. A reference to an unknown call id, or a path that does not resolve, returns `invalidResultReference` rather than a silent `null`.
2. **Validates `accountId`**: the requested account must match the authenticated account, a `shared:`-prefixed form of it, or the authenticating account. A mismatch returns `accountNotFound`.
3. **Checks the capability**: the handler's required capability (or one of its additional capabilities) must be present in the request's `using` array, otherwise `unknownCapability`.
4. **Applies the ADR-028 access checks**: the capability must be in this account's capabilities (`accountNotSupportedByMethod` if not), a read-only account cannot call a `/set` method (`forbidden`), and an app-password scope can narrow access further (`forbidden`).
5. **Executes the handler** and stores its result so later calls in the same batch can reference it.

Created ids are accumulated across the batch and returned in the response `createdIds`. A failure in one call produces an error response for that call and processing continues with the next; the batch is not aborted.

### Capabilities: v1 and v2 coexist

OxiMail advertises two generations of capability URNs in the same session: the standard `urn:ietf:params:jmap:*` set (v1, RFC 8620 / RFC 8621 and friends) and the OxiMail `urn:oximail:params:jmap:v2:*` set. A v2 handler does not replace its v1 counterpart; it registers its v2 URN as an *additional* capability on the same handler.

<Note>
  v1 and v2 capabilities are **not** mutually exclusive. The dispatcher keeps a list of mutually-exclusive v1 / v2 pairs (`V1_V2_MUTUAL_EXCLUSION_PAIRS`), but on the current line that list is **empty**: every domain that once had a pair (mail, contacts, calendars) has dropped it. A request that lists both the v1 and the v2 URN of a domain in `using` is accepted, and the wire shape is the union of the v1 and v2 properties. The mutex check still runs, so a future v3 surface could re-introduce a pair without re-implementing the rejection path, but today it iterates an empty list.
</Note>

### EventBus: cross-domain without coupling

The `EventBus` is a typed broadcast channel. A crate emits a `DomainEvent` (for example `EmailIngested`, `CalendarEventCreated`, `StateChanged`) and any number of subscribers in other crates react to it. Each event variant carries all the data a subscriber needs, so the subscribing crate never has to import the emitting crate. This is what keeps the mail crate and the calendar crate from depending on each other: an inbound iTIP email becomes an `ITipReceived` event that the calendar subscriber turns into a calendar event.

`StateChanged` is the bridge to push: after a `/set` handler writes its changes, it emits `StateChanged` with the new state, and the push worker turns that into a notification for subscribed clients.

### Push delivery

Push subscriptions (RFC 8620 §7.2) let a client register a URL to be POSTed when state changes. The `StateChange` payload (RFC 8620 §7.1) carries a map of account id to changed type and new state, optionally tagged with a distributed-causality vector so multi-device clients can apply patches in a deterministic order. The Web Push encryption (RFC 8291) and VAPID signing primitives live in this crate; the actual delivery loop runs in the push worker.

### Invariants

* **Never fail silently.** Unparseable ids, unknown capabilities, account mismatches, and bad result references all return a typed error; nothing is dropped on the floor.
* **One source of truth for limits.** Session-advertised limits and dispatch-enforced limits are the same constants.
* **No upward dependencies.** `oximail-core` depends only on `oximail-store`. Cross-domain communication goes through the `EventBus`, never through a direct import.

## Configuration

`oximail-core` reads no configuration files directly; it consumes values resolved by the binary (base URL, capability set, organization plan, account role). The server-level limits it advertises are compile-time constants. Operator-facing knobs that influence the surface this crate builds (the public base URL, TLS, organization plans and roles) are documented in the [configuration reference](/operator/configuration).

## Protocol / JMAP surface

The bulk of the JMAP surface is implemented in the domain crates. `oximail-core` owns the dispatch machinery and these core-level methods:

| Method                                                               | Purpose                                                                            |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `Core/echo`                                                          | RFC 8620 §4.1 — returns its arguments unchanged. The canonical connectivity check. |
| `PushSubscription/get`, `PushSubscription/set`                       | RFC 8620 §7.2 — manage a client's push subscriptions.                              |
| `SavedMessage/get`, `/set`, `/query`, `/queryChanges`, `/changes`    | Bookmarked messages (the `savedmessages` capability).                              |
| `MessageTaskLink/get`, `/set`, `/query`, `/queryChanges`, `/changes` | Associations between messages and tasks (the `tasklinks` capability).              |
| `Core/queryStream`                                                   | JMAP v2 streaming — wraps a `Foo/query` to stream results in chunks.               |
| `Push/catchup`                                                       | JMAP v2 streaming — replays state changes a reconnecting client missed.            |

It also provides `QueryChangesStub`, a generic handler that returns `cannotCalculateChanges` (RFC 8620 §5.6) for `Foo/queryChanges` surfaces that fall back to a full re-query.

The reusable filter and dispatch contracts it exports are the `JmapMethod` trait, the `MethodRegistry`, and the generic `Filter` / `FilterOperator` types. See [JMAP Core](/developer/jmap-core) for the client-facing protocol walk-through.

## Design decisions

* **ADR-011 (Event bus for cross-domain)** — the mail crate never imports the calendar crate; they communicate through the `DomainEvent` broadcast channel defined here.
* **ADR-028 (Dynamic account capabilities)** — per-account capabilities are the intersection of the server capabilities, the organization plan, and the account role, with explicit overrides; the dispatch-time access checks enforce it.
* **ADR-008 (UUIDv7 IDs)** — the `Id` primitive (re-exported from `oximail-store`); a malformed id is never silently dropped.
* **ADR-014 (Blob dedup by content hash)** and **ADR-009 (store raw plus structured)** — the `BlobId` primitive this crate re-exports is the SHA-256 of content.
* **ADR-054 / ADR-056 / ADR-066 (JMAP v2 architecture, capability negotiation, schema evolution)** — the v1 / v2 dual-capability model and the (currently empty) mutual-exclusion list.
* **ADR-072 (Per-collection volume caps)** — the `tooManyEntries` error variants and the advertised resource limits.

ADRs live in the OxiMail server repository; see the [ADR index](/reference/adr-index).

## Standards

* [RFC 8620](https://www.rfc-editor.org/rfc/rfc8620) — JMAP Core (session, dispatch, back-references, capabilities, push, errors). The primary reference for this crate.
* [RFC 6750](https://www.rfc-editor.org/rfc/rfc6750) — Bearer token authentication (the EventSource query-param token, §2.3).
* [RFC 6901](https://www.rfc-editor.org/rfc/rfc6901) — JSON Pointer, used to resolve result-reference paths.
* [RFC 8291](https://www.rfc-editor.org/rfc/rfc8291) — Message Encryption for Web Push.
* [RFC 8292](https://www.rfc-editor.org/rfc/rfc8292) — VAPID, for push authentication.
* [RFC 8887](https://www.rfc-editor.org/rfc/rfc8887) — JMAP over WebSocket (the `websocket` capability).

## Source map & tests

| File (within the crate)                                                                     | What it holds                                                                                                                                                            |
| ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `src/session.rs`                                                                            | The `Session` resource, server limits as constants, shared-account assembly. Guarded by `test_session_full_checklist`.                                                   |
| `src/dispatch.rs`                                                                           | `MethodRegistry`, the `JmapMethod` trait, back-reference resolution, the v1 / v2 mutex list, `Core/echo`, `QueryChangesStub`. Guarded by `test_dispatch_full_checklist`. |
| `src/capabilities.rs`                                                                       | `TenantPlan`, `AccountRole`, and `build_account_capabilities` (the ADR-028 intersection).                                                                                |
| `src/event_bus.rs`                                                                          | `DomainEvent`, `EventBus`, `EventEmitter`.                                                                                                                               |
| `src/jmap_filter.rs`                                                                        | The generic `Filter` / `FilterOperator` combinator and structural validation.                                                                                            |
| `src/push.rs`, `src/push_store.rs`, `src/push_worker.rs`, `src/web_push.rs`, `src/vapid.rs` | Push subscriptions, the `StateChange` payload, Web Push and VAPID.                                                                                                       |
| `src/error.rs`                                                                              | `RequestError`, `MethodError`, `SetError` — the typed JMAP error vocabulary.                                                                                             |
| `src/types.rs`                                                                              | `Account`, plus the `Id`, `BlobId`, `State` re-exports from `oximail-store`.                                                                                             |
| `src/methods/`                                                                              | The core-level method handlers (`SavedMessage/*`, `MessageTaskLink/*`, `Core/queryStream`, `Push/catchup`, `PushSubscription/*`).                                        |
| `tests/concurrency.rs`                                                                      | Integration coverage for concurrent dispatch.                                                                                                                            |

The dispatch and session modules each carry a single "checklist" test that exercises every responsibility of the module in one flow; changing dispatch or session behavior means updating that test.

## Status

Implemented and in production at **v0.30.0**: the session resource, the full dispatch and back-reference machinery, the ADR-028 capability model, the typed error vocabulary, the generic filter combinator, the EventBus, push subscriptions and the `StateChange` payload, and all the core-level methods listed above.

The v2 streaming methods (`Core/queryStream`, `Push/catchup`) and the v2 capability URNs are advertised and wired on the current line. The v1 / v2 mutual-exclusion infrastructure exists but is inert: the pair list is empty, so no request is rejected for pairing v1 and v2 capabilities.
