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
[distribution_groups] max_depth (3 by default, capped at 10), max_flat_size (1000), fanout_per_minute (5000), and enabled.
Objects and methods
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
ownerAccountIdrequires 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 ashareWithgrant 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
teamin one organization never expands a message sent toteam@another organization’s domain, which is passed through verbatim. - Renaming keeps the old name alive. The previous
namebecomes a historical alias, served inaliases(oldest first), andold-name@keeps resolving. - Who sees the members. An admin, the owner (whoever manages the membership must read it), a member, or anyone when
membersVisibleToTenantis true; everyone else receivesmembers: null.memberCountis always served. - Nesting is bounded and precomputed. A
setrecomputes 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). When a colleague leaves,
oximail account offboardnames the groups they belong to and changes none of them: group mail already follows the address redirection member by member (CLI).
notFound, invalidProperties over coercion, stateMismatch on ifInState.