urn:ietf:params:jmap:calendars), with events as JSCalendar objects (RFC 8984). The same data is served over CalDAV — one store, two protocols.
Objects and methods
CalendarEvent/counter is an OxiMail addition for occurrence counting.
Recurrence
- The property is
recurrenceRules(plural, RFC 8984) — always. - Recurring events expand through one occurrence-enumeration authority, shared by JMAP queries, CalDAV
time-rangefilters, free-busy, and alarms — an occurrence exists identically everywhere, across DST boundaries (expansion is anchored to the event’s local zone). - Per-occurrence overrides are keyed by civil-local time; overrides created in one protocol are honored (and protected by content-hash ETags) in the other.
- An imported
RRULEthe model cannot represent is kept verbatim and flaggedhasUnmodeledRecurrenceon read — never a half-converted rule.
Time zones
start is a LocalDateTime; the zone lives in timeZone (a UTC instant is stored as local time + Etc/UTC, never a Z-suffixed start). All-day events use showWithoutTime. A floating event resolves through the fallback chain event zone → user zone → organization default → UTC (groupware).
Scheduling (iTIP)
Creating an event with participants triggers invitation mail — under two hard rules: only when the organizer resolves to a local account (RFC 5546: only the organizer’s server sends), and only after the transaction commits (astateMismatch emits nothing). REPLY/CANCEL follow the same discipline; inbound invitations and replies are processed at ingestion and produce CalendarEventNotification objects. A grantee’s edit on a shared calendar notifies the owner the same way.
Availability
Principal/getAvailability composes busy time from the subject’s subscribed calendars whose includeInAvailability is all or attending, returning BusyPeriod objects. Privacy is layered: secret events hide their busy time entirely, private events contribute time but never details, and event details populate only under showDetails and real read access. A caller with free-busy rights on none of the subject’s calendars gets a per-id forbidden, not an empty answer.
Alerts
alerts supports both offset triggers (relativeTo: "start"/"end") and absolute ones (when). They fire server-side (push / notification), once per occurrence. VALARMs round-trip with CalDAV clients; public ICS feed exports deliberately carry none.
Strictness rules (unknown ids in notFound, invalidProperties over coercion, stateMismatch on ifInState) are identical to the mail surface.