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

# Distribution groups

> The organization-wide alias that expands to many recipients over JMAP: members of three kinds, nesting with a depth cap and a flat cache, who sees the members, the name guard against shadowing a colleague, historical aliases, and the per-organization fan-out budget.

A `DistributionGroup` is an OxiMail JMAP extension (`urn:oximail:params:jmap:distributiongroups`): an alias at the organization's domain that resolves to N recipients. `team-eng@example.com` reaches `alice`, `bob` and `carol`; `partners@` reaches an external address and another group. It is an **alias**, nothing more: no membership state on the recipient's side, no moderation, no archive. What arrives in a member's Inbox still shows `team-eng@example.com` in `To:`, never the list of members.

## The capability object

```json theme={null}
"urn:oximail:params:jmap:distributiongroups": {
  "maxNestingDepth": 10,
  "maxFlatSize": 1000,
  "maxGroupsPerTenant": 1000,
  "maxGroupsPerOwner": 100
}
```

These are the **hard** caps, announced so a client can refuse an oversized edit before the server does. The operator sets the effective depth below the hard one: `[distribution_groups] max_depth` (3 by default, capped at 10), `max_flat_size` (1000), `fanout_per_minute` (5000), and `enabled`.

## Objects and methods

| Object | Methods | Notes |
| - | - | - |
| `DistributionGroup` | `get`, `set`, `query`, `queryChanges`, `changes` | `id`, `name` (the local part), `displayName`, `description`, `ownerAccountId`, `membersVisibleToTenant`, `memberCount`, `members`, `aliases`, `createdAt`, `updatedAt`. |

A **member** is one of three kinds, tagged by `kind`: `account` (`accountId`; the `email` shown is resolved by the server at read and never read at write, so a client references by id alone), `email` (an external address), `group` (`groupId`, nested; its `name` is a display copy, same rule). An update patches membership with `addMembers` and `removeMembers` rather than replacing the list.

`DistributionGroup/query` takes no filter and no sort yet: a supplied one is refused (`unsupportedFilter`, `unsupportedSort`), never executed as if absent.

## Behaviours worth knowing

* **Anyone may create; the owner or an admin may change.** A create by any member of the organization makes the caller the owner; naming a different `ownerAccountId` requires an admin. Update and destroy are the owner's or an admin's. Every membership mutation and every destroy writes an audit line in the handler's transaction, since a group used in a `shareWith` grant changes the effective rights of N accounts.
* **A group cannot shadow a colleague.** Inbound expansion runs before account resolution, deliberately, so a group named after a colleague's local part would silently divert their mail to the members; create and rename refuse any name already carried by a live group, a historical alias, an account address or an email alias of the organization. The guard is per organization: a group `team` in one organization never expands a message sent to `team@` another organization's domain, which is passed through verbatim.
* **Renaming keeps the old name alive.** The previous `name` becomes a historical alias, served in `aliases` (oldest first), and `old-name@` keeps resolving.
* **Who sees the members.** An admin, the owner (whoever manages the membership must read it), a member, or anyone when `membersVisibleToTenant` is true; everyone else receives `members: null`. `memberCount` is always served.
* **Nesting is bounded and precomputed.** A `set` recomputes the flat expansion of the group **and of every ancestor** in the same transaction, refusing a cycle, a depth over the cap and a flat size over the cap with a typed error; the refused object rolls back to its savepoint while the other objects of the call proceed. Delivery and submission then read the flat cache, one SQL lookup and no recursion.
* **A fan-out budget per organization.** Each expansion consumes N units of a sliding one-minute window (`fanout_per_minute`); over it, the resolution fails rather than sending, so a runaway sender cannot turn a group into a flood.
* **A full member is skipped.** On delivery to a group, a member whose mailbox is over quota is skipped, logged and counted; the other members receive the message ([storage](../operator/mailboxes-storage#quotas)). When a colleague leaves, `oximail account offboard` names the groups they belong to and changes none of them: group mail already follows the address redirection member by member ([CLI](../operator/cli)).

Strictness rules are identical to the [mail surface](./jmap-mail): unknown ids in `notFound`, `invalidProperties` over coercion, `stateMismatch` on `ifInState`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.