Skip to main content

JMAP for Calendars
draft-ietf-jmap-calendars-07

The information below is for an old version of the document.
Document Type
This is an older version of an Internet-Draft whose latest revision state is "Active".
Authors Neil Jenkins , Michael Douglass
Last updated 2022-02-03
Replaces draft-jenkins-jmapcalendars
RFC stream Internet Engineering Task Force (IETF)
Formats
Additional resources Mailing list discussion
Stream WG state WG Document
Associated WG milestone
Apr 2024
Submit JMAP Calendars document to the IESG
Document shepherd (None)
IESG IESG state I-D Exists
Consensus boilerplate Yes
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-ietf-jmap-calendars-07
JMAP                                                   N.M. Jenkins, Ed.
Internet-Draft                                                  Fastmail
Intended status: Standards Track                        M. Douglass, Ed.
Expires: 8 August 2022                               Spherical Cow Group
                                                         4 February 2022

                           JMAP for Calendars
                      draft-ietf-jmap-calendars-07

Abstract

   This document specifies a data model for synchronizing calendar data
   with a server using JMAP.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 8 August 2022.

Copyright Notice

   Copyright (c) 2022 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.  Code Components
   extracted from this document must include Revised BSD License text as
   described in Section 4.e of the Trust Legal Provisions and are
   provided without warranty as described in the Revised BSD License.

Jenkins & Douglass        Expires 8 August 2022                 [Page 1]
Internet-Draft               JMAP Calendars                February 2022

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
     1.1.  Notational Conventions  . . . . . . . . . . . . . . . . .   4
     1.2.  The LocalDate Data Type . . . . . . . . . . . . . . . . .   4
     1.3.  Terminology . . . . . . . . . . . . . . . . . . . . . . .   4
     1.4.  Data Model Overview . . . . . . . . . . . . . . . . . . .   5
       1.4.1.  UIDs and CalendarEvent Ids  . . . . . . . . . . . . .   6
     1.5.  Addition to the Capabilities Object . . . . . . . . . . .   6
       1.5.1.  urn:ietf:params:jmap:calendars  . . . . . . . . . . .   6
       1.5.2.  urn:ietf:params:jmap:calendars:preferences  . . . . .   7
       1.5.3.  urn:ietf:params:jmap:principals:availability  . . . .   7
   2.  Principals and Sharing  . . . . . . . . . . . . . . . . . . .   8
     2.1.  Principal Capability urn:ietf:params:jmap:calendars . . .   8
     2.2.  Principal/getAvailability . . . . . . . . . . . . . . . .   8
   3.  Participant Identities  . . . . . . . . . . . . . . . . . . .  10
     3.1.  ParticipantIdentity/get . . . . . . . . . . . . . . . . .  11
     3.2.  ParticipantIdentity/changes . . . . . . . . . . . . . . .  11
     3.3.  ParticipantIdentity/set . . . . . . . . . . . . . . . . .  11
   4.  Calendars . . . . . . . . . . . . . . . . . . . . . . . . . .  11
     4.1.  Calendar/get  . . . . . . . . . . . . . . . . . . . . . .  15
     4.2.  Calendar/changes  . . . . . . . . . . . . . . . . . . . .  16
     4.3.  Calendar/set  . . . . . . . . . . . . . . . . . . . . . .  16
   5.  Calendar Events . . . . . . . . . . . . . . . . . . . . . . .  17
     5.1.  Additional JSCalendar properties  . . . . . . . . . . . .  19
       5.1.1.  mayInviteSelf . . . . . . . . . . . . . . . . . . . .  19
       5.1.2.  mayInviteOthers . . . . . . . . . . . . . . . . . . .  19
       5.1.3.  hideAttendees . . . . . . . . . . . . . . . . . . . .  19
     5.2.  Attachments . . . . . . . . . . . . . . . . . . . . . . .  19
     5.3.  Per-user properties . . . . . . . . . . . . . . . . . . .  20
     5.4.  Recurring events  . . . . . . . . . . . . . . . . . . . .  20
     5.5.  Updating for "this-and-future"  . . . . . . . . . . . . .  21
       5.5.1.  Splitting an event  . . . . . . . . . . . . . . . . .  21
       5.5.2.  Updating the base event and overriding previous . . .  21
     5.6.  CalendarEvent/get . . . . . . . . . . . . . . . . . . . .  21
     5.7.  CalendarEvent/changes . . . . . . . . . . . . . . . . . .  23
     5.8.  CalendarEvent/set . . . . . . . . . . . . . . . . . . . .  23
       5.8.1.  Patching  . . . . . . . . . . . . . . . . . . . . . .  25
       5.8.2.  Sending invitations and responses . . . . . . . . . .  28
     5.9.  CalendarEvent/copy  . . . . . . . . . . . . . . . . . . .  31
     5.10. CalendarEvent/query . . . . . . . . . . . . . . . . . . .  31
       5.10.1.  Filtering  . . . . . . . . . . . . . . . . . . . . .  31
       5.10.2.  Sorting  . . . . . . . . . . . . . . . . . . . . . .  33
     5.11. CalendarEvent/queryChanges  . . . . . . . . . . . . . . .  33
     5.12. Examples  . . . . . . . . . . . . . . . . . . . . . . . .  33
   6.  Alerts  . . . . . . . . . . . . . . . . . . . . . . . . . . .  33
     6.1.  Default alerts  . . . . . . . . . . . . . . . . . . . . .  34
     6.2.  Acknowledging an alert  . . . . . . . . . . . . . . . . .  34

Jenkins & Douglass        Expires 8 August 2022                 [Page 2]
Internet-Draft               JMAP Calendars                February 2022

     6.3.  Snoozing an alert . . . . . . . . . . . . . . . . . . . .  34
     6.4.  Push events . . . . . . . . . . . . . . . . . . . . . . .  35
   7.  Calendar Event Notifications  . . . . . . . . . . . . . . . .  35
     7.1.  Auto-deletion of Notifications  . . . . . . . . . . . . .  36
     7.2.  Object Properties . . . . . . . . . . . . . . . . . . . .  36
     7.3.  CalendarEventNotification/get . . . . . . . . . . . . . .  37
     7.4.  CalendarEventNotification/changes . . . . . . . . . . . .  37
     7.5.  CalendarEventNotification/set . . . . . . . . . . . . . .  37
     7.6.  CalendarEventNotification/query . . . . . . . . . . . . .  37
       7.6.1.  Filtering . . . . . . . . . . . . . . . . . . . . . .  37
       7.6.2.  Sorting . . . . . . . . . . . . . . . . . . . . . . .  37
     7.7.  CalendarEventNotification/queryChanges  . . . . . . . . .  38
   8.  CalendarPreferences . . . . . . . . . . . . . . . . . . . . .  38
     8.1.  CalendarPreferences/get . . . . . . . . . . . . . . . . .  38
     8.2.  CalendarPreferences/set . . . . . . . . . . . . . . . . .  38
   9.  Security Considerations . . . . . . . . . . . . . . . . . . .  39
     9.1.  Privacy . . . . . . . . . . . . . . . . . . . . . . . . .  39
     9.2.  Spoofing  . . . . . . . . . . . . . . . . . . . . . . . .  39
     9.3.  Denial-of-service . . . . . . . . . . . . . . . . . . . .  39
       9.3.1.  Expanding Recurrences . . . . . . . . . . . . . . . .  40
       9.3.2.  Firing alerts . . . . . . . . . . . . . . . . . . . .  40
       9.3.3.  Load spikes . . . . . . . . . . . . . . . . . . . . .  40
     9.4.  Spam  . . . . . . . . . . . . . . . . . . . . . . . . . .  40
   10. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  41
     10.1.  JMAP Capability Registration for "calendars" . . . . . .  41
     10.2.  JMAP Capability Registration for
            "calendars:preferences"  . . . . . . . . . . . . . . . .  41
     10.3.  JMAP Capability Registration for
            "principals:availability"  . . . . . . . . . . . . . . .  41
     10.4.  JSCalendar Property Registrations  . . . . . . . . . . .  42
       10.4.1.  id . . . . . . . . . . . . . . . . . . . . . . . . .  42
       10.4.2.  calendarIds  . . . . . . . . . . . . . . . . . . . .  42
       10.4.3.  isDraft  . . . . . . . . . . . . . . . . . . . . . .  42
       10.4.4.  utcStart . . . . . . . . . . . . . . . . . . . . . .  42
       10.4.5.  utcEnd . . . . . . . . . . . . . . . . . . . . . . .  43
       10.4.6.  mayInviteSelf  . . . . . . . . . . . . . . . . . . .  43
       10.4.7.  mayInviteOthers  . . . . . . . . . . . . . . . . . .  43
       10.4.8.  hideAttendees  . . . . . . . . . . . . . . . . . . .  43
   11. Normative References  . . . . . . . . . . . . . . . . . . . .  44
   12. Informative References  . . . . . . . . . . . . . . . . . . .  44
   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  45

Jenkins & Douglass        Expires 8 August 2022                 [Page 3]
Internet-Draft               JMAP Calendars                February 2022

1.  Introduction

   JMAP ([RFC8620] – (U+2013) JSON Meta Application Protocol) is a
   generic protocol for synchronizing data, such as mail, calendars or
   contacts, between a client and a server.  It is optimized for mobile
   and web environments, and aims to provide a consistent interface to
   different data types.

   This specification defines a data model for synchronizing calendar
   data between a client and a server using JMAP.  The data model is
   designed to allow a server to provide consistent access to the same
   data via CalDAV [RFC4791] as well as JMAP, however the functionality
   offered over the two protocols may differ.  Unlike CalDAV, this
   specification does not define access to tasks or journal entries
   (VTODO or VJOURNAL iCalendar components in CalDAV).

1.1.  Notational Conventions

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in BCP
   14 [RFC2119] [RFC8174] when, and only when, they appear in all
   capitals, as shown here.

   Type signatures, examples, and property descriptions in this document
   follow the conventions established in Section 1.1 of [RFC8620].  Data
   types defined in the core specification are also used in this
   document.

1.2.  The LocalDate Data Type

   Where LocalDate is given as a type, it means a string in the same
   format as Date (see [RFC8620], Section 1.4), but with the time-offset
   omitted from the end.  The interpretation in absolute time depends
   upon the time zone for the event, which may not be a fixed offset
   (for example when daylight saving time occurs).  For example,
   2014-10-30T14:12:00.

1.3.  Terminology

   The same terminology is used in this document as in the core JMAP
   specification, see [RFC8620], Section 1.6.

   The terms ParticipantIdentity, Calendar, CalendarEvent,
   CalendarEventNotification, and CalendarPreferences (with these
   specific capitalizations) are used to refer to the data types defined
   in this document and instances of those data types.

Jenkins & Douglass        Expires 8 August 2022                 [Page 4]
Internet-Draft               JMAP Calendars                February 2022

1.4.  Data Model Overview

   An Account (see [RFC8620], Section 1.6.2) with support for the
   calendar data model contains zero or more Calendar objects, which is
   a named collection of CalendarEvents.  Calendars can also provide
   defaults, such as alerts and a color to apply to events in the
   calendar.  Clients commonly let users toggle visibility of events
   belonging to a particular calendar on/off.  Servers may allow an
   event to belong to multiple Calendars within an account.

   A CalendarEvent is a representation of an event or recurring series
   of events in JSEvent [RFC8984] format.  Simple clients may ask the
   server to expand recurrences for them within a specific time period,
   and optionally convert times into UTC so they do not have to handle
   time zone conversion.  More full-featured clients will want to access
   the full event information and handle recurrence expansion and time
   zone conversion locally.

   CalendarEventNotification objects keep track of the history of
   changes made to a calendar by other users, allowing calendar clients
   to notify the user of changes to their schedule.

   The ParticipantIdentity data type represents the identities of the
   current user within an Account, which determines which events the
   user is a participant of and possibly their permissions related to
   that event.

   The CalendarPreferences object is a singleton in the account that
   stores the user's default calendar and participant identity.

   In servers with support for JMAP Sharing [RFC XXX], data may be
   shared with other users.  Sharing permissions are managed per
   calendar.  For example, an individual may have separate calendars for
   personal and work activities, with both contributing to their free-
   busy availability, but only the work calendar shared in its entirety
   with colleagues.  Principals may also represent schedulable entities,
   such as a meeting room.

   Users can normally subscribe to any calendar to which they have
   access.  This indicates the user wants this calendar to appear in
   their regular list of calendars.  The separate "isVisible" property
   stores whether the user would currently like to view the events in a
   subscribed calendar.

Jenkins & Douglass        Expires 8 August 2022                 [Page 5]
Internet-Draft               JMAP Calendars                February 2022

1.4.1.  UIDs and CalendarEvent Ids

   Each CalendarEvent has a uid property ([RFC8984], Section 4.1.2),
   which is a globally unique identifier that identifies the same event
   in different Accounts, or different instances of the same recurring
   event within an Account.

   An Account MUST NOT contain more than one CalendarEvent with the same
   uid unless all of the CalendarEvent objects have distinct, non-null
   values for their recurrenceId property.  (This situation occurs if
   the principal is added to one or more specific instances of a
   recurring event without being invited to the whole series.)

   Each CalendarEvent also has an id, which is scoped to the JMAP
   Account and used for referencing it in JMAP methods.  There is no
   necessary link between the uid property and the CalendarEvent's id.
   CalendarEvents with the same uid in different Accounts MAY have
   different ids.

1.5.  Addition to the Capabilities Object

   The capabilities object is returned as part of the JMAP Session
   object; see [RFC8620], Section 2.  This document defines two
   additional capability URIs.

1.5.1.  urn:ietf:params:jmap:calendars

   This represents support for the Calendar, CalendarEvent,
   CalendarEventNotification, and ParticipantIdentity data types and
   associated API methods.  The value of this property in the JMAP
   Session capabilities property is an empty object.

   The value of this property in an account’ (U+2019)s
   accountCapabilities property is an object that MUST contain the
   following information on server capabilities and permissions for that
   account:

   *  *shareesActAs*: String This MUST be one of:

      -  self - sharees act as themselves when using calendars in this
         account.
      -  secretary- sharees act as the principal to which this account
         belongs.

Jenkins & Douglass        Expires 8 August 2022                 [Page 6]
Internet-Draft               JMAP Calendars                February 2022

   *  *maxCalendarsPerEvent*: UnsignedInt|null The maximum number of
      Calendars (see Section XXX) that can be can assigned to a single
      CalendarEvent object (see Section XXX).  This MUST be an integer
      >= 1, or null for no limit (or rather, the limit is always the
      number of Calendars in the account).

   *  *minDateTime*: LocalDate The earliest date-time the server is
      willing to accept for any date stored in a CalendarEvent.

   *  *maxDateTime*: LocalDate The latest date-time the server is
      willing to accept for any date stored in a CalendarEvent.

   *  *maxExpandedQueryDuration*: Duration The maximum duration the user
      may query over when asking the server to expand recurrences.

   *  *maxParticipantsPerEvent*: Number|null The maximum number of
      participants a single event may have, or null for no limit.

   *  *mayCreateCalendar*: Boolean If true, the user may create a
      calendar in this account.

1.5.2.  urn:ietf:params:jmap:calendars:preferences

   This represents support for the CalendarPreferences data type and
   associated API methods.  The value of this property in the JMAP
   Session capabilities property and the account’ (U+2019)s
   accountCapabilities property is an empty object.

   Any account with this capability MUST also have the
   urn:ietf:params:jmap:calendars capability.

1.5.3.  urn:ietf:params:jmap:principals:availability

   Represents support for the Principal/getAvailability method.  Any
   account with this capability MUST also have the
   urn:ietf:params:jmap:principals capability (see [RFC XXX]).

   The value of this property in the JMAP Session capabilities property
   is an empty object.

   The value of this property in an account’ (U+2019)s
   accountCapabilities property is an object that MUST contain the
   following information on server capabilities and permissions for that
   account:

   *  *maxAvailabilityDuration*: The maximum duration over which the
      server is prepared to calculate availability in a single call (see
      Section XXX).

Jenkins & Douglass        Expires 8 August 2022                 [Page 7]
Internet-Draft               JMAP Calendars                February 2022

2.  Principals and Sharing

   For systems that also support JMAP Sharing [RFC XXX], the calendars
   capability is used to indicate that this principal may be used with
   calendaring.  A new method is defined to allow users to query
   availability when scehduling events.

2.1.  Principal Capability urn:ietf:params:jmap:calendars

   A "urn:ietf:params:jmap:calendars" property is added to the Principal
   "capabilities" object, the value of which is an object with the
   following properties:

   *  *accountId*: Id|null Id of Account with the
      urn:ietf:params:jmap:calendars capability that contains the
      calendar data for this principal, or null if none (e.g. the
      Principal is a group just used for permissions management), or the
      user does not have access to any data in the account (with the
      exception of free/busy, which is governed by the
      mayGetAvailability property).
   *  *account*: Account|null The JMAP Account object corresponding to
      the accountId, null if none.
   *  *mayGetAvailability*: Boolean May the user call the "Principal/
      getAvailability" method with this Principal?
   *  *mayShareWith*: Boolean May the user add this principal as a
      calendar sharee (by adding them to the shareWith property of a
      calendar, see Section XXX)?
   *  *sendTo*: String[String]|null If this principal may be added as a
      participant to an event, this is the map of methods for adding it,
      in the same format as Participant#sendTo in JSEvent (see
      [RFC8984], Section 4.4.5).

2.2.  Principal/getAvailability

   This method calculates the availability of the principal for
   scheduling within a requested time period.  It takes the following
   arguments:

   *  *accountId*: Id The id of the account to use.
   *  *id*: Id The id of the Principal to calculate availability for.
   *  *utcStart*: UTCDate The start time (inclusive) of the period for
      which to return availability.
   *  *utcEnd*: UTCDate The end time (exclusive) of the period for which
      to return availability.
   *  *showDetails*: Boolean If true, event details will be returned if
      the user has permission to view them.

Jenkins & Douglass        Expires 8 August 2022                 [Page 8]
Internet-Draft               JMAP Calendars                February 2022

   *  *eventProperties*: String[]|null A list of properties to include
      in any JSEvent object returned.  If null, all properties of the
      event will be returned.  Otherwise, only properties with names in
      the given list will be returned.

   The server will first find all relevant events, expanding any
   recurring events.  Relevant events are ones where all of the
   following is true:

   *  The principal is subscribed to the calendar.
   *  Either the calendar belongs to the principal or the calendar
      account's "shareesActAs" property is "self".
   *  The "includeInAvailability" property of the calendar for the
      principal is "all" or "attending".
   *  The user has the "mayReadFreeBusy" permission for the calendar.
   *  The event finishes after the "utcStart" argument and starts before
      the "utcEnd" argument.
   *  The event's "privacy" property is not "secret".
   *  The "freeBusyStatus" property of the event is "busy" (or omitted,
      as this is the default).
   *  The "status" property of the event is not "cancelled".
   *  If the "includeInAvailability" property of the calendar is
      "attending", then the principal is a participant of the event, and
      has a "participationStatus" of "accepted" or "tentative".

   If an event is in more than one calendar, it is relevant if all of
   the above are true for any one calendar that it is in.

   The server then generates a BusyPeriod object for each of these
   events.  A *BusyPeriod* object has the following properties:

   *  *utcStart*: UTCDate The start time (inclusive) of the period this
      represents.

   *  *utcEnd*: UTCDate The end time (exclusive) of the period this
      represents.

   *  *busyStatus*: String (optional, default "unavailable") This MUST
      be one of

      -  confirmed: The event status is "confirmed".
      -  tentative: The event status is "tentative".
      -  unavailable: The principal is not available for scheduling at
         this time for any other reason.

   *  *event*: JSEvent|null The JSEvent representation of the event, or
      null if any of the following are true:

Jenkins & Douglass        Expires 8 August 2022                 [Page 9]
Internet-Draft               JMAP Calendars                February 2022

      -  The "showDetails" argument is false.
      -  The "privacy" property of the event is "private".
      -  The user does not have the "mayReadItems" permission for any of
         the calendars the event is in.

      If an eventProperties argument was given, any properties in the
      JSEvent that are not in the eventProperties list are removed from
      the returned representation.

   The server MAY also generate BusyPeriod objects based on other
   information it has about the principal's availability, such as office
   hours.

   Finally, the server MUST merge and split BusyPeriod objects where the
   "event" property is null, such that none of them overlap and either
   there is a gap in time between any two objects (the utcEnd of one
   does not equal the utcStart of another) or those objects have a
   different busyStatus property.  If there are overlapping BusyPeriod
   time ranges with different "busyStatus" properties the server MUST
   choose the value in the following order: confirmed > unavailable >
   tentative.

   The response has the following argument:

   *  *list*: BusyPeriod[] The list of BusyPeriod objects calculated as
      described above.

   The following additional errors may be returned instead of the
   "Principal/getAvailability" response:

   notFound: No principal with this id exists, or the user does not have
   permission to see that this principal exists.

   forbidden: The user does not have permission to query this
   principal's availability.

   tooLarge: The duration between utcStart an utcEnd is longer than the
   server is willing to calculate availability for.

   rateLimit: Too many availability requests have been made recently and
   the user is being rate limited.  It may work to try again later.

3.  Participant Identities

   A ParticipantIdentity stores information about a URI that represents
   the user within that account in an event's participants.  It has the
   following properties:

Jenkins & Douglass        Expires 8 August 2022                [Page 10]
Internet-Draft               JMAP Calendars                February 2022

   *  *id*: Id (immutable; server-set) The id of the
      ParticipantIdentity.

   *  *name*: String (default: "") The display name of the participant
      to use when adding this participant to an event, e.g.  "Joe
      Bloggs".

   *  *sendTo*: String[String] Represents methods by which the
      participant may receive invitations and updates to an event.

      The keys in the property value are the available methods and MUST
      only contain ASCII alphanumeric characters (A-Za-z0-9).  The value
      is a URI for the method specified in the key.

   A participant in an event corresponds to a ParticipantIdentity if any
   of the method/uri pairs in the sendTo property of the participant are
   identical to a method/uri pair in the sendTo property of the
   identity.

   The following JMAP methods are supported.

3.1.  ParticipantIdentity/get

   This is a standard "/get" method as described in [RFC8620],
   Section 5.1.  The _ids_ argument may be null to fetch all at once.

3.2.  ParticipantIdentity/changes

   This is a standard "/changes" method as described in [RFC8620],
   Section 5.2.

3.3.  ParticipantIdentity/set

   This is a standard "/set" method as described in [RFC8620],
   Section 5.3.  The server MAY restrict the uri values the user may
   claim, for example only allowing mailto: URIs with email addresses
   that belong to the user.  A standard forbidden error is returned to
   reject non-permissible changes.

   A participant identity may be destroyed that is referenced as the
   "defaultParticipantIdentityId" in the CalenderPreferences object for
   the same account.  Doing so updates the defaultParticipantIdentityId
   property on the CalendarPreferences to null.

4.  Calendars

   A Calendar is a named collection of events.  All events are
   associated with at least one calendar.

Jenkins & Douglass        Expires 8 August 2022                [Page 11]
Internet-Draft               JMAP Calendars                February 2022

   A *Calendar* object has the following properties:

   *  *id*: Id (immutable; server-set) The id of the calendar.
   *  *name*: String The user-visible name of the calendar.  This may be
      any UTF-8 string of at least 1 character in length and maximum 255
      octets in size.
   *  *description*: String|null (default: null) An optional longer-form
      description of the calendar, to provide context in shared
      environments where users need more than just the name.
   *  *color*: String|null (default: null) A color to be used when
      displaying events associated with the calendar.

   If not null, the value MUST be a case-insensitive color name taken
   from the set of names defined in Section 4.3 of CSS Color Module
   Level 3 COLORS (https://www.w3.org/TR/css-color-3/), or an RGB value
   in hexadecimal notation, as defined in Section 4.2.1 of CSS Color
   Module Level 3.

The color SHOULD have sufficient contrast to be used as text on a white background.

   *  *sortOrder*: UnsignedInt (default: 0) Defines the sort order of
      calendars when presented in the client's UI, so it is consistent
      between devices.  The number MUST be an integer in the range 0 <=
      sortOrder < 2^(31.)

      A calendar with a lower order should be displayed before a
      calendar with a higher order in any list of calendars in the
      client's UI.  Calendars with equal order SHOULD be sorted in
      alphabetical order by name.  The sorting should take into account
      locale-specific character order convention.

   *  *isSubscribed*: Boolean Has the user indicated they wish to see
      this Calendar in their client?  This SHOULD default to false for
      Calendars in shared accounts the user has access to and true for
      any new Calendars created by the user themself.

      If false, the calendar should only be displayed when the user
      explicitly requests it or to offer it for the user to subscribe
      to.

   *  *isVisible*: Boolean (default: true) Should the calendar's events
      be displayed to the user at the moment?  Clients MUST ignore this
      property if isSubscribed is false.  If an event is in multiple
      calendars, it should be displayed if isVisible is true for any of
      those calendars.

Jenkins & Douglass        Expires 8 August 2022                [Page 12]
Internet-Draft               JMAP Calendars                February 2022

   *  *includeInAvailability*: String (default: all) Should the
      calendar's events be used as part of availability calculation?
      This MUST be one of:

      -  all: all events are considered.
      -  attending: events the user is a confirmed or tentative
         participant of are considered.
      -  none: all events are ignored (but may be considered if also in
         another calendar).

   *  *defaultAlertsWithTime*: Id[Alert]|null (default: null) A map of
      alert ids to Alert objects (see [RFC8984], Section 4.5.2) to apply
      for events where "showWithoutTime" is false and "useDefaultAlerts"
      is true.  Ids MUST be unique across all default alerts in the
      account, including those in other calendars; a UUID is
      recommended.

   *  *defaultAlertsWithoutTime*: Id[Alert]|null (default: null) A map
      of alert ids to Alert objects (see [RFC8984], Section 4.5.2) to
      apply for events where "showWithoutTime" is true and
      "useDefaultAlerts" is true.  Ids MUST be unique across all default
      alerts in the account, including those in other calendars; a UUID
      is recommended.

   *  *timeZone*: String|null (default: null) The time zone to use for
      events without a time zone when the server needs to resolve them
      into absolute time, e.g., for alerts or availability calculation.
      The value MUST be a time zone id from the IANA Time Zone Database
      TZDB (https://www.iana.org/time-zones).  If null, the timeZone of
      the account's associated Principal will be used.  Clients SHOULD
      use this as the default for new events in this calendar if set.

   *  *shareWith*: Id[CalendarRights]|null (default: null) A map of
      Principal id to rights for principals this calendar is shared
      with.  The principal to which this calendar belongs MUST NOT be in
      this set.  This is null if the user requesting the object does not
      have the mayAdmin right, or if the calendar is not shared with
      anyone.  May be modified only if the user has the mayAdmin right.
      The account id for the principals may be found in the
      urn:ietf:params:jmap:principals:owner capability of the Account to
      which the calendar belongs.

   *  *myRights*: CalendarRights (server-set) The set of access rights
      the user has in relation to this Calendar.  If any event is in
      multiple calendars, the user has the following rights:

      -  The user may fetch the event if they have the mayReadItems
         right on any calendar the event is in.

Jenkins & Douglass        Expires 8 August 2022                [Page 13]
Internet-Draft               JMAP Calendars                February 2022

      -  The user may remove an event from a calendar (by modifying the
         event's "calendarIds" property) if the user has the appropriate
         permission for that calendar.
      -  The user may make other changes to the event if they have the
         right to do so in _all_ calendars to which the event belongs.

   A *CalendarRights* object has the following properties:

   *  *mayReadFreeBusy*: Boolean The user may read the free-busy
      information for this calendar as part of a call to Principal/
      getAvailability (see Section XXX).

   *  *mayReadItems*: Boolean The user may fetch the events in this
      calendar.

   *  *mayWriteAll*: Boolean The user may create, modify or destroy all
      events in this calendar, or move events to or from this calendar.
      If this is true, the mayWriteOwn, mayUpdatePrivate and mayRSVP
      properties MUST all also be true.

   *  *mayWriteOwn*: Boolean The user may create, modify or destroy an
      event on this calendar if either they are the owner of the event
      or the event has no owner.  This means the user may also transfer
      ownership by updating an event so they are no longer an owner.

   *  *mayUpdatePrivate*: Boolean The user may modify the following
      properties on all events in the calendar, even if they would not
      otherwise have permission to modify that event.  If the
      shareesActAs account capability is "self", these properties MUST
      all be stored per-user, and changes do not affect any other user
      of the calendar.  If shareesActAs is "secretary", the values are
      shared between all users.

      -  keywords
      -  color
      -  freeBusyStatus
      -  useDefaultAlerts
      -  alerts

      The user may also modify the above on a per-occurrence basis for
      recurring events (updating the recurrenceOverrides property of the
      event to do so).

   *  *mayRSVP*: Boolean The user may modify the following properties of
      any Participant object that corresponds to one of the user's
      ParticipantIdentity objects in the account, even if they would not
      otherwise have permission to modify that event:

Jenkins & Douglass        Expires 8 August 2022                [Page 14]
Internet-Draft               JMAP Calendars                February 2022

      -  participationStatus
      -  participationComment
      -  expectReply
      -  scheduleAgent
      -  scheduleSequence
      -  scheduleUpdated

      If the event has its "mayInviteSelf" property set to true (see
      Section XXX), then the user may also add a new Participant to the
      event with a sendTo property that is the same as the sendTo
      property of one of the user's ParticipantIdentity objects in the
      account.  The roles property of the participant MUST only contain
      "attendee".

      If the event has its "mayInviteOthers" property set to true (see
      Section XXX) and there is an existing Participant in the event
      corresponding to one of the user's ParticipantIdentity objects in
      the account, then the user may also add new participants.  The
      roles property of any new participant MUST only contain
      "attendee".

      The user may also do all of the above on a per-occurrence basis
      for recurring events (updating the recurrenceOverrides property of
      the event to do so).

   *  *mayAdmin*: Boolean The user may modify sharing for this calendar.

   *  *mayDelete*: Boolean (server-set) The user may delete the calendar
      itself.  This property MUST be false if the account to which this
      calendar belongs has the _isReadOnly_ property set to true.

   The user is an *owner* for an event if the CalendarEvent object has a
   "participants" property, and one of the Participant objects both:

a) Has the "owner" role.
b) Corresponds to one of the user's ParticipantIdentity objects in the account.

   An event has no owner if its participants property is null or
   omitted, or if none of the Participant objects have the "owner" role.

4.1.  Calendar/get

   This is a standard "/get" method as described in [RFC8620],
   Section 5.1.  The _ids_ argument may be null to fetch all at once.

Jenkins & Douglass        Expires 8 August 2022                [Page 15]
Internet-Draft               JMAP Calendars                February 2022

   If mayReadFreeBusy is the only permission the user has, the calendar
   MUST NOT be returned in Calendar/get and Calendar/query; it must
   behave as though it did not exist.  The data is just used as part of
   Principal/getAvailability.

4.2.  Calendar/changes

   This is a standard "/changes" method as described in [RFC8620],
   Section 5.2.

4.3.  Calendar/set

   This is a standard "/set" method as described in [RFC8620],
   Section 5.3 but with the following additional request argument:

   *  *onDestroyRemoveEvents*: Boolean (default: false)

   If false, any attempt to destroy a Calendar that still has
   CalendarEvents in it will be rejected with a calendarHasEvent
   SetError.  If true, any CalendarEvents that were in the Calendar will
   be removed from it, and if in no other Calendars they will be
   destroyed.  This SHOULD NOT send scheduling messages to participants
   or create CalendarEventNotification objects.

   The "shareWith" property may only be set by users that have the
   mayAdmin right.  The value is shared across all users, although users
   without the mayAdmin right cannot see the value.

   When modifying the shareWith property, the user cannot give a right
   to a principal if the principal did not already have that right and
   the user making the change also does not have that right.  Any
   attempt to do so must be rejected with a forbidden SetError.

   Users can subscribe or unsubscribe to a calendar by setting the
   "isSubscribed" property.  The server MAY forbid users from
   subscribing to certain calendars even though they have permission to
   see them, rejecting the update with a forbidden SetError.

   The "timeZone", "includeInAvailability", "defaultAlertsWithoutTime"
   and "defaultAlertsWithTime" properties are stored per-user if the
   calendar account's "shareesActAs" capability is "self", and may be
   set by any user who is subscribed to the calendar.  Otherwise, these
   properties are shared, and may only be set by users that have the
   mayAdmin right.

   The following properties may be set by anyone who is subscribed to
   the calendar and are all stored per-user:

Jenkins & Douglass        Expires 8 August 2022                [Page 16]
Internet-Draft               JMAP Calendars                February 2022

   *  name
   *  color
   *  sortOrder
   *  isVisible

   These properties are initially inherited from the owner's copy of the
   calendar, but if set by a sharee that user gets their own copy of the
   property; it does not change for any other principals.  If the value
   of the property in the owner's calendar changes after this, it does
   not overwrite the sharee's value.

   A calendar may be destroyed that is referenced as the
   "defaultCalendarId" in the CalenderPreferences object for the same
   account.  Doing so updates the defaultCalendarId property on the
   CalendarPreferences to null.

   The following extra SetError types are defined:

   For "destroy":

   *  *calendarHasEvent*: The Calendar has at least one CalendarEvent
      assigned to it, and the "onDestroyRemoveEvents" argument was
      false.

5.  Calendar Events

   A *CalendarEvent* object contains information about an event, or
   recurring series of events, that takes place at a particular time.
   It is a JSEvent object, as defined in [RFC8984], with the following
   additional properties:

   *  *id*: Id (immutable; server-set) The id of the CalendarEvent.  The
      id uniquely identifies a JSEvent with a particular "uid" and
      "recurrenceId" within a particular account.

   *  *baseEventId*: Id|null (immutable; server-set) This is only
      defined if the _id_ property is a synthetic id, generated by the
      server to represent a particular instance of a recurring event
      (see Section XXX).  This property gives the id of the "real"
      CalendarEvent this was generated from.

   *  *calendarIds*: Id[Boolean] The set of Calendar ids this event
      belongs to.  An event MUST belong to one or more Calendars at all
      times (until it is destroyed).  The set is represented as an
      object, with each key being a _Calendar id_. The value for each
      key in the object MUST be true.

Jenkins & Douglass        Expires 8 August 2022                [Page 17]
Internet-Draft               JMAP Calendars                February 2022

   *  *isDraft*: Boolean (default: false) If true, this event is to be
      considered a draft.  The server will not send any scheduling
      messages to participants or send push notifications for alerts.
      This may only be set to true upon creation.  Once set to false,
      the value cannot be updated to true.  This property MUST NOT
      appear in "recurrenceOverrides".

   *  *utcStart*: UTCDate For simple clients that do not or cannot
      implement time zone support.  Clients should only use this if also
      asking the server to expand recurrences, as you cannot accurately
      expand a recurrence without the original time zone.

      This property is calculated at fetch time by the server.  Time
      zones are political and they can and do change at any time.
      Fetching exactly the same property again may return a different
      results if the time zone data has been updated on the server.
      Time zone data changes are not considered "updates" to the event.

      If set, server will convert to the event's current time zone using
      its current time zone data and store the local time.

      This is not included by default and must be requested explicitly.

      Floating events (events without a time zone) will be interpreted
      as per the time zone given as a CalendarEvent/get argument.

      Note that it is not possible to accurately calculate the expansion
      of recurrence rules or recurrence overrides with the utcStart
      property rather than the local start time.  Even simple
      recurrences such as "repeat weekly" may cross a daylight-savings
      boundary and end up at a different UTC time.  Clients that wish to
      use "utcStart" are RECOMMENDED to request the server expand
      recurrences (see Section XXX).

   *  *utcEnd*: UTCDate The server calculates the end time in UTC from
      the start/timeZone/duration properties of the event.  This is not
      included by default and must be requested explicitly.  Like
      utcStart, this is calculated at fetch time if requested and may
      change due to time zone data changes.  Floating events will be
      interpreted as per the time zone given as a CalendarEvent/get
      argument.

   CalendarEvent objects MUST NOT have a "method" property as this is
   only used when representing iTIP [RFC5546] scheduling messages, not
   events in a data store.

Jenkins & Douglass        Expires 8 August 2022                [Page 18]
Internet-Draft               JMAP Calendars                February 2022

5.1.  Additional JSCalendar properties

   This document defines three new JSCalendar properties.

5.1.1.  mayInviteSelf

   Type: Boolean (default: false)

   If true, any user may add themselves to the event as a participant
   with the "attendee" role.  This property MUST NOT be altered in the
   recurrenceOverrides; it may only be set on the base object.

   This indicates the owner will accept "party crasher" RSVPs via iTIP,
   subject to any other domain-specific restrictions, and users may add
   themselves to the event via JMAP as long as they have the mayRSVP
   permission for the calendar.

5.1.2.  mayInviteOthers

   Type: Boolean (default: false)

   If true, any current participant with the "attendee" role may add new
   participants with the "attendee" role to the event.  This property
   MUST NOT be altered in the recurrenceOverrides; it may only be set on
   the base object.

   The mayRSVP permission for the calendar is also required in
   conjunction with this event property for users to be allowed to make
   this change via JMAP.

5.1.3.  hideAttendees

   Type: Boolean (default: false)

   If true, only the owners of the event may see the full set of
   participants.  Other sharees of the event may only see the owners and
   themselves.  This property MUST NOT be altered in the
   recurrenceOverrides; it may only be set on the base object.

5.2.  Attachments

   The Link object, as defined in [RFC8984] Section 4.2.7, with a "rel"
   property equal to "enclosure" is used to represent attachments.
   Instead of mandating an "href" property, clients may set a "blobId"
   property instead to reference a blob of binary data in the account,
   as per [RFC8620] Section 6.

Jenkins & Douglass        Expires 8 August 2022                [Page 19]
Internet-Draft               JMAP Calendars                February 2022

   The server MUST translate this to an embedded data: URL [RFC2397]
   when sending the event to a system that cannot access the blob.
   Servers that support CalDAV access to the same data are recommended
   to expose these files as managed attachments [?@RFC8607].

5.3.  Per-user properties

   In shared calendars where the account's "shareesActAs" capability is
   "self", the following properties MUST be stored per-user:

   *  keywords
   *  color
   *  freeBusyStatus
   *  useDefaultAlerts
   *  alerts

   The user may also modify these properties on a per-occurrence basis
   for recurring events; again, these MUST be stored per-user.

   When writing only per-user properties, the "updated" property MUST
   also be stored just for that user.  When fetching the "updated"
   property, the value to return is whichever is later of the per-user
   updated time or the updated time of the base event.

5.4.  Recurring events

   Events may recur, in which case they represent multiple occurrences
   or instances.  The data store will either contain a single base
   event, containing a recurrence rule and/or recurrence overrides; or,
   a set of individual instances (when invited to specific occurrences
   only).

   The client may ask the server to expand recurrences within a specific
   time range in "CalendarEvent/query".  This will generate synthetic
   ids representing individual instances in the requested time range.
   The client can fetch and update the objects using these ids and the
   server will make the appropriate changes to the base event.
   Synthetic ids do not appear in "CalendarEvent/changes" responses;
   only the ids of events as actually stored on the server.

   If the user is invited to specific instances then later added to the
   base event, "CalendarEvent/changes" will show the ids of all the
   individual instances being destroyed and the id for the base event
   being created.

Jenkins & Douglass        Expires 8 August 2022                [Page 20]
Internet-Draft               JMAP Calendars                February 2022

5.5.  Updating for "this-and-future"

   When editing a recurring event, you can either update the base event
   (affecting all instances unless overriden) or update an override for
   a specific occurrence.  To update all occurrences from a specific
   point onwards, there are therefore two options: split the event, or
   update the base event and override all occurrences before the split
   point back to their original values.

5.5.1.  Splitting an event

   If the event is not scheduled (has no participants), the simplest
   thing to do is to duplicate the event, modifying the recurrence rules
   of the original so it finishes before the split point, and the
   duplicate so it starts at the split point.  As per JSCalendar
   [RFC8984] Section 4.1.3, a "next" and "first" relation MUST be set on
   the new objects respectively.

   Splitting an event however is problematic in the case of a scheduled
   event, because the iTIP messages generated make it appear like two
   unrelated changes, which can be confusing.

5.5.2.  Updating the base event and overriding previous

   For scheduled events, a better approach is to avoid splitting and
   instead update the base event with the new property value for "this
   and future", then create overrides for all occurrences before the
   split point to restore the property to its previous value.  Indeed,
   this may be the only option the user has permission to do if not an
   owner of the event.

   Clients may choose to skip creating the overrides if the old data is
   not important, for example if the "alerts" property is being updated,
   it is probably not important to create overrides for events in the
   past with the alerts that have already fired.

5.6.  CalendarEvent/get

   This is a standard "/get" method as described in [RFC8620],
   Section 5.1, with three extra arguments:

   *  *recurrenceOverridesBefore*: UTCDate|null If given, only
      recurrence overrides with a recurrence id before this date (when
      translated into UTC) will be returned.
   *  *recurrenceOverridesAfter*: UTCDate|null If given, only recurrence
      overrides with a recurrence id on or after this date (when
      translated into UTC) will be returned.

Jenkins & Douglass        Expires 8 August 2022                [Page 21]
Internet-Draft               JMAP Calendars                February 2022

   *  *reduceParticipants*: Boolean (default: false) If true, only
      participants with the "owner" role or corresponding to the user's
      participant identities will be returned in the "participants"
      property of the base event and any recurrence overrides.  If
      false, all participants will be returned.
   *  *timeZone*: String (default "Etc/UTC") The time zone to use when
      calculating the utcStart/utcEnd property of floating events.  This
      argument has no effect if those properties are not requested.

   A CalendarEvent object is a JSEvent object so may have arbitrary
   properties.  If the client makes a "CalendarEvent/get" call with a
   null or omitted "properties" argument, all properties defined on the
   JSEvent object in the store are returned, along with the "id",
   "calendarIds", and "isDraft" properties.  The "utcStart" and "utcEnd"
   computed properties are only returned if explicitly requested.  If
   either are requested, the "recurrenceOverrides" property MUST NOT be
   requested (recurrence overrides cannot be interpreted accurately with
   just the UTC times).

   If specific properties are requested from the JSEvent and the
   property is not present on the object in the server's store, the
   server SHOULD return the default value if known for that property.

   A requested id may represent a single instance of a recurring event
   if the client asked the server to expand recurrences in
   "CalendarEvent/query".  In such a case, the server will resolve any
   overrides and set the appropriate "start" and "recurrenceId"
   properties on the CalendarEvent object returned to the client.  The
   "recurrenceRule" and "recurrenceOverrides" properties MUST be
   returned as null if requested for such an event.

   An event with the same uid/recurrenceId may appear in different
   accounts.  Clients may coalesce the view of such events, but must be
   aware that the data may be different in the different accounts due to
   per-user properties, difference in permissions etc.

   The "privacy" property of a JSEvent object allows the owner to
   override how sharees of the calendar see the event.  If this is set
   to "private", when a sharee fetches the event the server MUST only
   return the basic time and metadata properties of the JSEvent object
   as specified in [RFC8984], Section 4.4.3.  If set to "secret", the
   server MUST behave as though the event does not exist for all users
   other than the owner.

Jenkins & Douglass        Expires 8 August 2022                [Page 22]
Internet-Draft               JMAP Calendars                February 2022

   This "hideAttendees" property of a JSEvent object allows the owner to
   reduce the visibility of sharees into the set of participants.  If
   this is true, when a non-owner sharee fetches the event, the server
   MUST only return participants with the "owner" role or corresponding
   to the user's participant identities.

5.7.  CalendarEvent/changes

   This is a standard "/changes" method as described in [RFC8620],
   Section 5.2.

   Synthetic ids generated by the server expanding recurrences in
   "CalendarEvent/query" do not appear in "CalendarEvent/changes"
   responses; only the ids of events as actually stored on the server.

5.8.  CalendarEvent/set

   This is a standard "/set" method as described in [RFC8620],
   Section 5.3, with the following extra argument:

   *  *sendSchedulingMessages*: Boolean (default: false) If true then
      any changes to scheduled events will be sent to all the
      participants (if the user is an owner of the event) or back to the
      owners (otherwise).  If false, the changes only affect this
      account and no scheduling messages will be sent.

   For recurring events, an id may represent the base event or a
   specific instance.  When the id for a specific instance is given, the
   server MUST process an update as an update to the recurrence override
   for that instance on the base event, and a destroy as removing just
   that instance.

   Clients MUST NOT send an update/destroy to both the base event and a
   specific instance in a single "/set" request; the result of this is
   undefined.

   Servers MUST enforce the user's permissions as returned in the
   "myRights" property of the Calendar objects and reject changes with a
   forbidden SetError if not allowed.

   The "privacy" property of a JSEvent object allows the owner to
   override how sharees of the calendar see the event.  If this is set
   to "private", a sharee may not delete or update the event (even if
   only modifying per-user properties); any attempt to modify such an
   event MUST be rejected with a forbidden SetError.  If set to
   "secret", the server MUST behave as though the event does not exist
   for all users other than the owner.

Jenkins & Douglass        Expires 8 August 2022                [Page 23]
Internet-Draft               JMAP Calendars                February 2022

   The "privacy" property MUST NOT be set to anything other than
   "public" (the default) for events in a calendar that does not belong
   to the user (e.g. a shared team calendar).  The server MUST reject
   this with an invalidProperties SetError.

   If omitted on create, the server MUST set the following properties to
   an appropriate value:

   *  @type
   *  uid
   *  created

   The "updated" property MUST be set to the current time by the server
   whenever an event is created or updated.  If the client tries to set
   a value for this property it is not an error, but it MUST be
   overridden and replaced with the server's time.  If the event is
   being created and the overridden "updated" time is now earlier than a
   client-supplied "created" time, the "created" time MUST also be
   overridden to the server's time.

   When updating an event, if all of: * a property has been changed
   other than "calendarIds", "isDraft" or a per-user property (see
   Section XXX); and * the server is the source of the event (see
   Section XXX); and * the "sequence" property is not explicitly set in
   the update, or the given value is less than or equal to the current
   "sequence" value on the server; then the server MUST increment the
   "sequence" value by one.

   The "created" property MUST NOT be updated after creation.  The
   "method" property MUST NOT be set.  Any attempt to do these is
   rejected with a standard invalidProperties SetError.

   If "utcStart" is set, this is translated into a "start" property
   using the server's current time zone information.  It MUST NOT be set
   in addition to a "start" property and it cannot be set inside
   "recurrenceOverrides"; this MUST be rejected with an
   invalidProperties SetError.

   Similarly, the "utcEnd" property is translated into a "duration"
   property if set.  It MUST NOT be set in addition to a "duration"
   property and it cannot be set inside "recurrenceOverrides"; this MUST
   be rejected with an invalidProperties SetError.

   The server does not automatically reset the "partipationStatus" or
   "expectReply" properties of a Participant when changing other event
   details.  Clients should either be intelligent about whether the
   change necessitates resending RSVP requests, or ask the user whether
   to send them.

Jenkins & Douglass        Expires 8 August 2022                [Page 24]
Internet-Draft               JMAP Calendars                February 2022

   The server MAY enforce that all events have an owner, for example in
   team calendars.  If the user tries to create an event without
   participants in such a calendar, the server MUST automatically add a
   participant with the "owner" role corresponding to one of the user's
   ParticipantIdentities (see Section XXX).

   When creating an event with participants, or adding participants to
   an event that previously did not have participants, the server MUST
   set the "replyTo" property of the event if not present.  Clients
   SHOULD NOT set the replyTo property for events when the user adds
   participants; the server is better positioned to add all the methods
   it supports to receive replies.

5.8.1.  Patching

   The JMAP "/set" method allows you to update an object by sending a
   patch, rather than having to supply the whole object.  When doing so,
   care must be taken if updating a property of a CalendarEvent where
   the value is itself a PatchObject, e.g. inside "localizations" or
   "recurrenceOverrides".  In particular, you cannot add a property with
   value null to the CalendarEvent using a direct patch on that
   property, as this is interpreted instead as a patch to remove the
   property.  This is more easily understood with an example.  Suppose
   you have a CalendarEvent object like so:

Jenkins & Douglass        Expires 8 August 2022                [Page 25]
Internet-Draft               JMAP Calendars                February 2022

   {
     "id": "123",
     "title": "FooBar team meeting",
     "start": "2018-01-08T09:00:00",
     "recurrenceRules": [{
      "@type": "RecurrenceRule",
      "frequency": "weekly"
     }],
     "replyTo": {
      "imip": "mailto:6489-4f14-a57f-c1@schedule.example.com"
     },
     "participants": {
      "dG9tQGZvb2Jhci5xlLmNvbQ": {
        "@type": "Participant",
        "name": "Tom",
        "email": "tom@foobar.example.com",
        "sendTo": {
          "imip": "mailto:6489-4f14-a57f-c1@calendar.example.com"
        },
        "participationStatus": "accepted",
        "roles": {
          "attendee": true
        }
      },
      "em9lQGZvb2GFtcGxlLmNvbQ": {
        "@type": "Participant",
        "name": "Zoe",
        "email": "zoe@foobar.example.com",
        "sendTo": {
          "imip": "mailto:zoe@foobar.example.com"
        },
        "participationStatus": "accepted",
        "roles": {
          "owner": true,
          "attendee": true,
          "chair": true
        }
      },
      "recurrenceOverrides": {
        "2018-03-08T09:00:00": {
          "start": "2018-03-08T10:00:00",
          "participants/dG9tQGZvb2Jhci5xlLmNvbQ/participationStatus":
                                                              "declined"
        }
      }
     }
   }

Jenkins & Douglass        Expires 8 August 2022                [Page 26]
Internet-Draft               JMAP Calendars                February 2022

   In this example, Tom is normally going to the weekly meeting but has
   declined the occurrence on 2018-03-08, which starts an hour later
   than normal.  Now, if Zoe too were to decline that meeting, she could
   update the event by just sending a patch like so:

  [[ "CalendarEvent/set", {
    "accountId": "ue150411c",
    "update": {
      "123": {
        "recurrenceOverrides/2018-03-08T09:00:00/
            participants~1em9lQGZvb2GFtcGxlLmNvbQ~1participationStatus":
                "declined"
      }
    }
  }, "0" ]]

   This patches the "2018-03-08T09:00:00" PatchObject in
   recurrenceOverrides so that it ends up like this:

   "recurrenceOverrides": {
     "2018-03-08T09:00:00": {
       "start": "2018-03-08T10:00:00",
       "participants/dG9tQGZvb2Jhci5xlLmNvbQ/participationStatus":
                                                          "declined",
       "participants/em9lQGZvb2GFtcGxlLmNvbQ/participationStatus":
                                                          "declined"
     }
   }

   Now if Tom were to change his mind and remove his declined status
   override (thus meaning he is attending, as inherited from the top-
   level event), he might remove his patch from the overrides like so:

[[ "CalendarEvent/set", {
  "accountId": "ue150411c",
  "update": {
    "123": {
      "recurrenceOverrides/2018-03-08T09:00:00/
          participants~1dG9tQGZvb2Jhci5xlLmNvbQ~1participationStatus": null
    }
  }
}, "0" ]]

   However, if you instead want to remove Tom from this instance
   altogether, you could not send this patch:

Jenkins & Douglass        Expires 8 August 2022                [Page 27]
Internet-Draft               JMAP Calendars                February 2022

   [[ "CalendarEvent/set", {
     "accountId": "ue150411c",
     "update": {
       "123": {
         "recurrenceOverrides/2018-03-08T09:00:00/
             participants~1dG9tQGZvb2Jhci5xlLmNvbQ": null
       }
     }
   }, "0" ]]

   This would mean remove the "participants/dG9tQGZvb2Jhci5xlLmNvbQ"
   property at path "recurrenceOverrides" -> "2018-03-08T09:00:00"
   inside the object; but this doesn't exist.  We actually we want to
   add this property and make it map to null.  The client must instead
   send the full object that contains the property mapping to null, like
   so:

   [[ "CalendarEvent/set", {
     "accountId": "ue150411c",
     "update": {
       "123": {
         "recurrenceOverrides/2018-03-08T09:00:00": {
           "start": "2018-03-08T10:00:00",
           "participants/em9lQGZvb2GFtcGxlLmNvbQ/participationStatus":
                                                          "declined"
           "participants/dG9tQGZvb2Jhci5xlLmNvbQ": null
         }
       }
     }
   }, "0" ]]

5.8.2.  Sending invitations and responses

   If "sendSchedulingMessages" is true, the server MUST send appropriate
   iTIP [RFC5546] scheduling messages after successfuly creating,
   updating or destroying a calendar event.

   When determining which scheduling messages to send, the server must
   first establish whether it is the _source_ of the event.  The server
   is the source if it will receive messages sent to any of the methods
   specified in the "replyTo" property of the event.

   Messages are only sent to participants with a "scheduleAgent"
   property set to "server" or omitted.  If the effective
   "scheduleAgent" property is changed:

   *  to "server" from something else: send messages to this participant
      as though the event had just been created.

Jenkins & Douglass        Expires 8 August 2022                [Page 28]
Internet-Draft               JMAP Calendars                February 2022

   *  from "server" to something else: send messages to this participant
      as though the event had just been destroyed.
   *  any other change: do not send any messages to this participant.

   The server may send the scheduling message via any of the methods
   defined on the sendTo property of a participant (if the server is the
   source) or the replyTo property of the event (otherwise) that it
   supports.  If no supported methods are available, the server MUST
   reject the change with a noSupportedScheduleMethods SetError.

   If the server is the source of the event it MUST NOT send messages to
   any participant corresponding to a ParticipantIdentitity in that
   account (see Section XXX).

   If sending via iMIP [RFC6047], the server MAY choose to only send
   updates it deems "essential" to avoid flooding the recipient's email
   with changes they do not care about.  For example, changes to the
   participationStatus of another participant, or changes to events
   solely in the past may be omitted.

5.8.2.1.  REQUEST

   When the server is the source for the event, a REQUEST message
   ([RFC5546], Section 3.2.2) is sent to all current participants if
   either:

   *  The event is being created; or
   *  Any non per-user property (see Section XXX) is updated on the
      event (including adding/removing participants), except if just
      modifying the recurrenceOverrides such that CANCEL messages are
      generated (see the next section).

   Note, if the only change is adding an additional instance (not
   generated by the event's recurrence rule) to the recurrenceOverrides,
   this MAY be handled via sending an ADD message ([RFC5546],
   Section 3.2.4) for the single instance rather than a REQUEST message
   for the base event.  However, for interoperability reasons this is
   not recommended due to poor support in the wild for this type of
   message.

Jenkins & Douglass        Expires 8 August 2022                [Page 29]
Internet-Draft               JMAP Calendars                February 2022

   The server MUST ensure participants are only sent information about
   recurrence instances they are added to when sending scheduling
   messages for recurring events.  If the participant is not invited to
   the full recurring event but only individual instances, scheduling
   messages MUST be sent for just those expanded occurrences
   individually.  If a participant is invited to a recurring event, but
   removed via a recurrence override from a particular instance, any
   scheduling messages to this participant MUST return the instance as
   "excluded" (if it matches a recurrence rule for the event) or omit
   the instance entirely (otherwise).

   If the event's "hideAttendees" property is set to true, the recipient
   MUST be the only attendee in the message; all others are omitted.

5.8.2.2.  CANCEL

   When the server is the source for the event, a CANCEL message
   ([RFC5546], Section 3.2.5) is sent if any of:

   *  A participant is removed from either the base event or a single
      instance (the message is only sent to this participant; remaining
      participants will get a REQUEST, as described above).
   *  The event is destroyed.
   *  An exclusion is added to recurrenceOverrides to remove an instance
      generated by the event's recurrence rule.
   *  An additional instance (not generated by the event's recurrence
      rule) is removed from the recurrenceOverrides.

   In each of the latter 3 cases, the message is sent to all
   participants.

5.8.2.3.  REPLY

   When the server is _not_ the source for the event, a REPLY message
   ([RFC5546], Section 3.2.3) is sent for any participant corresponding
   to one of the user's ParticipantIdentitities in the account if either
   of the following changes are made:

   *  The "participationStatus" property of the participant is changed,
      either for the base event or a specific instance.
   *  The event is created and the participationStatus is not "needs-
      action".

   If the participationStatus property is changed for just a single
   instance of the event (i.e., set in recurrenceOverrides), the REPLY
   message SHOULD be sent for just that recurrence id.

Jenkins & Douglass        Expires 8 August 2022                [Page 30]
Internet-Draft               JMAP Calendars                February 2022

5.9.  CalendarEvent/copy

   This is a standard "/copy" method as described in [RFC8620],
   Section 5.4.

5.10.  CalendarEvent/query

   This is a standard "/query" method as described in [RFC8620],
   Section 5.5, with two extra arguments:

   *  *expandRecurrences*: Boolean (default: false) If true, the server
      will expand any recurring event.  If true, the filter MUST be just
      a FilterCondition (not a FilterOperator) and MUST include both a
      before and after property.  This ensures the server is not asked
      to return an infinite number of results.
   *  *timeZone*: String The time zone for before/after filter
      conditions (default: "Etc/UTC")

   If expandRecurrences is true, a separate id will be returned for each
   instance of a recurring event that matches the query.  This synthetic
   id is opaque to the client, but allows the server to resolve the id +
   recurrence id for "/get" and "/set" operations.  Otherwise, a single
   id will be returned for matching recurring events that represents the
   entire event.

   There is no necessary correspondence between the ids of different
   instances of the same expanded event.

   The following additional error may be returned instead of the
   "CalendarEvent/query" response:

   cannotCalculateOccurrences: the server cannot expand a recurrence
   required to return the results for this query.

5.10.1.  Filtering

   A *FilterCondition* object has the following properties:

   *  *inCalendars*: Id[]|null A list of calendar ids.  An event must be
      in ANY of these calendars to match the condition.
   *  *after*: LocalDate|null The end of the event, or any recurrence of
      the event, in the time zone given as the timeZone argument, must
      be after this date to match the condition.
   *  *before*: LocalDate|null The start of the event, or any recurrence
      of the event, in the time zone given as the timeZone argument,
      must be before this date to match the condition.

Jenkins & Douglass        Expires 8 August 2022                [Page 31]
Internet-Draft               JMAP Calendars                February 2022

   *  *text*: String|null Looks for the text in the _title_,
      _description_, _locations_ (matching name/description),
      _participants_ (matching name/email) and any other textual
      properties of the event or any recurrence of the event.
   *  *title*: String|null Looks for the text in the _title_ property of
      the event, or the overridden _title_ property of a recurrence.
   *  *description*: String|null Looks for the text in the _description_
      property of the event, or the overridden _description_ property of
      a recurrence.
   *  *location*: String|null Looks for the text in the _locations_
      property of the event (matching name/description of a location),
      or the overridden _locations_ property of a recurrence.
   *  *owner*: String|null Looks for the text in the name or email
      fields of a participant in the _participants_ property of the
      event, or the overridden _participants_ property of a recurrence,
      where the participant has a role of "owner".
   *  *attendee*: String|null Looks for the text in the name or email
      fields of a participant in the _participants_ property of the
      event, or the overridden _participants_ property of a recurrence,
      where the participant has a role of "attendee".
   *  *participationStatus*: Must match.  If owner/attendee condition,
      status must be of that participant.  Otherwise any.
   *  *uid*: String The uid of the event is exactly the given string.

   If expandRecurrences is true, all conditions must match against the
   same instance of a recurring event for the instance to match.  If
   expandRecurrences is false, all conditions must match, but they may
   each match any instance of the event.

   If zero properties are specified on the FilterCondition, the
   condition MUST always evaluate to true.  If multiple properties are
   specified, ALL must apply for the condition to be true (it is
   equivalent to splitting the object into one-property conditions and
   making them all the child of an AND filter operator).

   The exact semantics for matching String fields is *deliberately not
   defined* to allow for flexibility in indexing implementation, subject
   to the following:

   *  Text SHOULD be matched in a case-insensitive manner.
   *  Text contained in either (but matched) single or double quotes
      SHOULD be treated as a *phrase search*, that is a match is
      required for that exact sequence of words, excluding the
      surrounding quotation marks.  Use \", \' and \\ to match a literal
      ", ' and \ respectively in a phrase.
   *  Outside of a phrase, white-space SHOULD be treated as dividing
      separate tokens that may be searched for separately in the event,
      but MUST all be present for the event to match the filter.

Jenkins & Douglass        Expires 8 August 2022                [Page 32]
Internet-Draft               JMAP Calendars                February 2022

   *  Tokens MAY be matched on a whole-word basis using stemming (so for
      example a text search for bus would match "buses" but not
      "business").

5.10.2.  Sorting

   The following properties MUST be supported for sorting:

   *  start
   *  uid
   *  recurrenceId

   The following properties SHOULD be supported for sorting:

   *  created
   *  updated

5.11.  CalendarEvent/queryChanges

   This is a standard "/queryChanges" method as described in [RFC8620],
   Section 5.6.

5.12.  Examples

   TODO: Add example of how to get event by uid: query uid=foo and
   backref.  Return multiple with recurrenceId set (user invited to
   specific instances of recurring event).

6.  Alerts

   Alerts may be specified on events as described in [RFC8984],
   Section 4.5.

   Alerts MUST only be triggered for events in calendars where the user
   is subscribed and either the user owns the calendar or the calendar
   account's "shareesActAs" capability is "self".

   When an alert with an "email" action is triggered, the server MUST
   send an email to the user to notify them of the event.  The contents
   of the email is implementation specific.  Clients MUST NOT perform an
   action for these alerts.

   When an alert with a "display" action is triggered, clients SHOULD
   display an alert in a platform-appropriate manner to the user to
   remind them of the event.  Clients with a full offline cache of
   events may choose to calculate when alerts should trigger locally.
   Alternatively, they can subscribe to push events from the server.

Jenkins & Douglass        Expires 8 August 2022                [Page 33]
Internet-Draft               JMAP Calendars                February 2022

6.1.  Default alerts

   If the "useDefaultAlerts" property of an event is true, the alerts
   are taken from the "defaultAlertsWithTime" or
   "defaultAlertsWithoutTime" property of all Calendars the event is in,
   as described in Section XXX, rather than the "alerts" property of the
   CalendarEvent.

   When using default alerts, the "alerts" property of the event is
   ignored except for the following:

   *  The "acknowledged" time for an alert is stored here when a default
      alert for the event is dismissed.  The id of the alert MUST be the
      same as the id of the default alert in the calendar.  See
      Section XXX on acknowledging alerts.
   *  If an alert has a relatedTo property where the parent is the id of
      one of the calendar default alerts, it is processed as normal and
      not ignored.  This is to support snoozing default alerts; see
      Section XXX.

6.2.  Acknowledging an alert

   To dismiss an alert, clients set the "acknowledged" property of the
   Alert object to the current date-time.  If the alert was a calendar
   default, it may need to be added to the event at this point in order
   to acknowledge it.  When other clients fetch the updated
   CalendarEvent they SHOULD automatically dismiss or suppress duplicate
   alerts (alerts with the same alert id that triggered on or before the
   "acknowledged" date-time) and alerts that have been removed from the
   event.

   Setting the "acknowledged" property MUST NOT create a new recurrence
   override.  For a recurring calendar object, the "acknowledged"
   property of the parent object MUST be updated, unless the alert is
   already overridden in the "recurrenceOverrides" property.

6.3.  Snoozing an alert

   Users may wish to dismiss an alert temporarily and have it come back
   after a specific period of time.  To do this, clients MUST:

   1.  Acknowledge the alert as described in Section XXX.
   2.  Add a new alert to the event with an AbsoluteTrigger for the
       date-time the alert has been snoozed until.  Add a "relatedTo"
       property to the new alert, setting the "parent" relation to point
       to the original alert.  This MUST NOT create a new recurrence
       override; it is added to the same "alerts" property that contains
       the alert that was acknowledged in step 1.

Jenkins & Douglass        Expires 8 August 2022                [Page 34]
Internet-Draft               JMAP Calendars                February 2022

   When acknowledging a snoozed alert (i.e. one with a parent relatedTo
   pointing to the original alert), the client SHOULD delete the alert
   rather than setting the "acknowledged" property.

6.4.  Push events

   Servers that support the urn:ietf:params:jmap:calendars capability
   MUST support registering for the pseudo-type "CalendarAlert" in push
   subscriptions and event source connections, as described in
   [RFC8620], Sections 7.2 and 7.3.

   If requested, a CalendarAlert notification will be pushed whenever an
   alert is triggered for the user.  For Event Source connections, this
   notification is pushed as an event called "calendarAlert".

   A *CalendarAlert* object has the following properties:

   *  *@type*: String This MUST be the string "CalendarAlert".
   *  *accountId*: String The account id for the calendar in which the
      alert triggered.
   *  *calendarEventId*: String The CalendarEvent id for the alert that
      triggered.
   *  *uid*: String The uid property of the CalendarEvent for the alert
      that triggered.
   *  *recurrenceId*: String|null The recurrenceId for the instance of
      the event for which this alert is being triggered, or null if the
      event is not recurring.
   *  *alertId*: String The id for the alert that triggered.

7.  Calendar Event Notifications

   The CalendarEventNotification data type records changes made by
   external entities to events in calendars the user is subscribed to.
   Notifications are stored in the same Account as the CalendarEvent
   that was changed.

   Notifications are only created by the server; users cannot create
   them directly.  Clients SHOULD present the list of notifications to
   the user and allow them to dismiss them.  To dismiss a notification
   you use a standard "/set" call to destroy it.

   The server SHOULD create a CalendarEventNotification whenever an
   event is added, updated or destroyed by another user or due to
   receiving an iTIP [RFC5546] or other scheduling message in a calendar
   this user is subscribed to.  The server SHOULD NOT create
   notifications for events implicitly deleted due to the containing
   calendar being deleted.

Jenkins & Douglass        Expires 8 August 2022                [Page 35]
Internet-Draft               JMAP Calendars                February 2022

   The CalendarEventNotification does not have any per-user data.  A
   single instance may therefore be maintained on the server for all
   sharees of the notification.  The server need only keep track of
   which users have yet to destroy the notification.

7.1.  Auto-deletion of Notifications

   The server MAY limit the maximum number of notifications it will
   store for a user.  When the limit is reached, any new notification
   will cause the previously oldest notification to be automatically
   deleted.

   The server MAY coalesce events if appropriate, or remove events that
   it deems are no longer relevant or after a certain period of time.
   The server SHOULD automatically destroy a notification about an event
   if the user updates or destroys that event (e.g. if the user sends an
   RSVP for the event).

7.2.  Object Properties

   The *CalendarEventNotification* object has the following properties:

   *  *id*: String The id of the CalendarEventNotification.
   *  *created*: UTCDate The time this notification was created.
   *  *changedBy*: Person Who made the change.
      -  *name*: String The name of the person who made the change.
      -  *email*: String The email of the person who made the change, or
         null if no email is available.
      -  *principalId*: String|null The id of the calendar principal
         corresponding to the person who made the change, if any.  This
         will be null if the change was due to receving an iTIP message.
   *  *comment*: String|null Comment sent along with the change by the
      user that made it. (e.g.  COMMENT property in an iTIP message).
   *  *type*: String This MUST be one of
      -  created
      -  updated
      -  destroyed
   *  *calendarEventId*: String The id of the CalendarEvent that this
      notification is about.
   *  *isDraft*: Boolean (created/updated only) Is this event a draft?
   *  *event*: JSEvent The data before the change (if updated or
      destroyed), or the data after creation (if created).
   *  *eventPatch*: PatchObject (updated only) A patch encoding the
      change between the data in the event property, and the data after
      the update.

Jenkins & Douglass        Expires 8 August 2022                [Page 36]
Internet-Draft               JMAP Calendars                February 2022

   To reduce data, if the change only affects a single instance of a
   recurring event, the server MAY set the event and eventPatch
   properties for the instance; the calendarEventId MUST still be for
   the base event.

7.3.  CalendarEventNotification/get

   This is a standard "/get" method as described in [RFC8620],
   Section 5.1.

7.4.  CalendarEventNotification/changes

   This is a standard "/changes" method as described in [RFC8620],
   Section 5.2.

7.5.  CalendarEventNotification/set

   This is a standard "/changes" method as described in [RFC8620],
   Section 5.3.

   Only destroy is supported; any attempt to create/update MUST be
   rejected with a forbidden SetError.

7.6.  CalendarEventNotification/query

   This is a standard "/query" method as described in [RFC8620],
   Section 5.5.

7.6.1.  Filtering

   A *FilterCondition* object has the following properties:

   *  *after*: UTCDate|null The creation date must be on or after this
      date to match the condition.
   *  *before*: UTCDate|null The creation date must be before this date
      to match the condition.
   *  *type*: String The type property must be the same to match the
      condition.
   *  *calendarEventIds*: Id[]|null A list of event ids.  The
      calendarEventId property of the notification must be in this list
      to match the condition.

7.6.2.  Sorting

   The "created" property MUST be supported for sorting.

Jenkins & Douglass        Expires 8 August 2022                [Page 37]
Internet-Draft               JMAP Calendars                February 2022

7.7.  CalendarEventNotification/queryChanges

   This is a standard "/queryChanges" method as described in [RFC8620],
   Section 5.6.

8.  CalendarPreferences

   A CalendarPreferences object stores information about the principal's
   preferences and defaults.

   *  *id*: Id (immutable; server-set) The id of the object.  There is
      only ever one CalendarPreferences object, and its id is
      "singleton".

   *  *defaultCalendarId*: Id|null The id of the principal's default
      calendar.  If set, clients should default to this calendar when
      creating new events in this account, unless overridden by a local
      preference.  When the principal is invited to an event, this is
      the calendar to which it will be added by the server.

      If null, no default is defined and clients/servers may choose any
      calendar.

   *  *defaultParticipantIdentityId*: Id|null The default participant
      identity to use for the principal when adding participants to an
      event.  If set, when the user adds an invitee to an event without
      an owner, the client should use this participant identity to add
      the principal as an owner participant of the event.

      If null, no default is defined and clients/servers may choose any
      participant identity.

   The following JMAP methods are supported.

8.1.  CalendarPreferences/get

   This is a standard "/get" method as described in [RFC8620],
   Section 5.1.

   There MUST only be exactly one CalendarPreferences object in an
   account.  It MUST have the id "singleton".

8.2.  CalendarPreferences/set

   This is a standard "/set" method as described in [RFC8620],
   Section 5.3.

Jenkins & Douglass        Expires 8 August 2022                [Page 38]
Internet-Draft               JMAP Calendars                February 2022

9.  Security Considerations

   All security considerations of JMAP [RFC8620] and JSCalendar
   [RFC8984] apply to this specification.  Additional considerations
   specific to the data types and functionality introduced by this
   document are described in the following subsections.

9.1.  Privacy

   Calendars often contain the precise movements, activities, and
   contacts of people, and is therefore intensely private data.  Privacy
   leaks can have real world consequences, and calendar servers and
   clients MUST be mindful of the need to keep all data secure.

   Servers MUST enforce the ACLs set on calendars to ensure only
   authorised data is shared.  The additional restrictions specified by
   the "privacy" property of a JSEvent object (see [RFC8984]
   Section 4.4.3) MUST also be enforced.

   Users may have multiple Participant Identities that they use for
   areas of their life kept private from one another.  Using one
   identity with an event MUST NOT leak the existence of any other
   identity.  For example, sending an RSVP from identity
   worklife@example.com MUST NOT reveal anything about another identity
   present in the account such as privatelife@example.org.

   Severs SHOULD enforce that invitations sent to external systems are
   only transmitted via secure encrypted and signed connections to
   protect against eavesdropping and modification of data.

9.2.  Spoofing

   When receiving events and updates from external systems, it can be
   hard to verify that the identity of the author is who they claim to
   be.  When receiving events via email, DKIM [RFC6376] and S/MIME
   [RFC8551] are two mechanisms that may be used to verify certain
   properties about the email data, which can be correlated with the
   event information.

9.3.  Denial-of-service

   There are many ways in which a calendar user can make a request
   liable to cause a calendar server to spend an inordinate amount of
   processing time.  Care must be taken to limit resources allocated to
   any one user to ensure the system does not become unresponsive.  The
   following subsections list particularly hazardous areas.

Jenkins & Douglass        Expires 8 August 2022                [Page 39]
Internet-Draft               JMAP Calendars                February 2022

9.3.1.  Expanding Recurrences

   Recurrence rules can be crafted to occur as frequently as every
   second.  Servers MUST be careful to not allow resources to be
   exhausted when expanding, and limit the number of expansions they
   will create.  Equally, rules can be generated that never create any
   occurrences at all.  Servers MUST be careful to limit the work spent
   iterating in search of the next occurrence.

9.3.2.  Firing alerts

   An alert firing for an event can cause a notification to be pused to
   the user's devices, or to send them an email.  Servers MUST rate
   limit the number of alerts sent for any one user.  The combination of
   recurring events with multiple alerts can in particular define
   unreasonably frequent alerts, leading to denial of service for either
   the server processing them or the user's devices receiving them.

   Similarly, clients generating alerts from the data on device must
   take the same precautions.

   The "email" alert type (see RFC8984, Section 4.5.2) causes an email
   to be sent when triggered.  Clients MUST ignore this alert type; the
   email is sent only be the calendar server.  There is no mechanism in
   JSCalendar to specify a particular email address: the server MUST
   only allow alerts to be sent to an address it has verified as
   belonging to the user to avoid this being used as a spamming vector.

9.3.3.  Load spikes

   Since most events are likely to start on the hour mark, a large spike
   of activity is often seen at these times, with particularly large
   spikes at certain common times in the time zone of the server's user
   base.  In particular, a large number of alerts (across different
   users and events) will be triggered at the same time.  Servers may
   mitigate this somewhat by adding jitter to the triggering of the
   alerts; it is RECOMMENDED to fire them slightly early rather than
   slightly late if needed to spread load.

9.4.  Spam

   Invitations received from an untrusted source may be spam.  If this
   is added to the user's calendar automatically it can be very
   obtrusive, especially if it is a recurring event that now appears
   every day.  Incoming invitations to events should be subject to spam
   scanning, and suspicious events should not be added to the calendar
   automatically.

Jenkins & Douglass        Expires 8 August 2022                [Page 40]
Internet-Draft               JMAP Calendars                February 2022

   Servers should strip any alerts on invitations when adding to the
   user's calendar; the useDefaultAlerts property should be set instead
   to apply the user's preferences.

   Similarly, a malicious user may use a calendar system to send spam by
   inviting people to an event.  Outbound iTIP should be subject to all
   the same controls used on outbound email systems, and rate limited as
   appropriate.  A rate limit on the number of distinct recipients as
   well as overall messages is recommended.

10.  IANA Considerations

10.1.  JMAP Capability Registration for "calendars"

   IANA will register the "calendars" JMAP Capability as follows:

   Capability Name: urn:ietf:params:jmap:calendars

   Specification document: this document

   Intended use: common

   Change Controller: IETF

   Security and privacy considerations: this document, Section XXX

10.2.  JMAP Capability Registration for "calendars:preferences"

   IANA will register the "calendars:preferences" JMAP Capability as
   follows:

   Capability Name: urn:ietf:params:jmap:calendars:preferences

   Specification document: this document

   Intended use: common

   Change Controller: IETF

   Security and privacy considerations: this document, Section XXX

10.3.  JMAP Capability Registration for "principals:availability"

   IANA will register the "principals:availability" JMAP Capability as
   follows:

   Capability Name: urn:ietf:params:jmap:principals:availability

Jenkins & Douglass        Expires 8 August 2022                [Page 41]
Internet-Draft               JMAP Calendars                February 2022

   Specification document: this document

   Intended use: common

   Change Controller: IETF

   Security and privacy considerations: this document, Section XXX

10.4.  JSCalendar Property Registrations

   IANA will register the following additional properties in the
   JSCalendar Properties Registry.

10.4.1.  id

   Property Name: id

   Property Type: Id

   Property Context: JSEvent, JSTask

   Intended Use: Reserved

10.4.2.  calendarIds

   Property Name: calendarIds

   Property Type: Id[Boolean]

   Property Context: JSEvent, JSTask

   Intended Use: Reserved

10.4.3.  isDraft

   Property Name: isDraft

   Property Type: Boolean

   Property Context: JSEvent, JSTask

   Intended Use: Reserved

10.4.4.  utcStart

   Property Name: utcStart

   Property Type: UTCDateTime

Jenkins & Douglass        Expires 8 August 2022                [Page 42]
Internet-Draft               JMAP Calendars                February 2022

   Property Context: JSEvent, JSTask

   Intended Use: Reserved

10.4.5.  utcEnd

   Property Name: utcEnd

   Property Type: UTCDateTime

   Property Context: JSEvent, JSTask

   Intended Use: Reserved

10.4.6.  mayInviteSelf

   Property Name: mayInviteSelf

   Property Type: Boolean (default: false)

   Property Context: JSEvent, JSTask

   Reference: This document, Section XXX.

   Intended Use: Common

10.4.7.  mayInviteOthers

   Property Name: mayInviteOthers

   Property Type: Boolean (default: false)

   Property Context: JSEvent, JSTask

   Reference: This document, Section XXX.

   Intended Use: Common

10.4.8.  hideAttendees

   Property Name: hideAttendees

   Property Type: Boolean (default: false)

   Property Context: JSEvent, JSTask

   Reference: This document, Section XXX.

Jenkins & Douglass        Expires 8 August 2022                [Page 43]
Internet-Draft               JMAP Calendars                February 2022

   Intended Use: Common

11.  Normative References

   [RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
              Requirement Levels", BCP 14, RFC 2119,
              DOI 10.17487/RFC2119, March 1997,
              <https://www.rfc-editor.org/info/rfc2119>.

   [RFC2397]  Masinter, L., "The "data" URL scheme", RFC 2397,
              DOI 10.17487/RFC2397, August 1998,
              <https://www.rfc-editor.org/info/rfc2397>.

   [RFC6376]  Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed.,
              "DomainKeys Identified Mail (DKIM) Signatures", STD 76,
              RFC 6376, DOI 10.17487/RFC6376, September 2011,
              <https://www.rfc-editor.org/info/rfc6376>.

   [RFC8174]  Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
              2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
              May 2017, <https://www.rfc-editor.org/info/rfc8174>.

   [RFC8551]  Schaad, J., Ramsdell, B., and S. Turner, "Secure/
              Multipurpose Internet Mail Extensions (S/MIME) Version 4.0
              Message Specification", RFC 8551, DOI 10.17487/RFC8551,
              April 2019, <https://www.rfc-editor.org/info/rfc8551>.

   [RFC8620]  Jenkins, N. and C. Newman, "The JSON Meta Application
              Protocol (JMAP)", RFC 8620, DOI 10.17487/RFC8620, July
              2019, <https://www.rfc-editor.org/info/rfc8620>.

   [RFC8984]  Jenkins, N. and R. Stepanek, "JSCalendar: A JSON
              Representation of Calendar Data", RFC 8984,
              DOI 10.17487/RFC8984, July 2021,
              <https://www.rfc-editor.org/info/rfc8984>.

12.  Informative References

   [RFC4791]  Daboo, C., Desruisseaux, B., and L. Dusseault,
              "Calendaring Extensions to WebDAV (CalDAV)", RFC 4791,
              DOI 10.17487/RFC4791, March 2007,
              <https://www.rfc-editor.org/info/rfc4791>.

   [RFC5546]  Daboo, C., Ed., "iCalendar Transport-Independent
              Interoperability Protocol (iTIP)", RFC 5546,
              DOI 10.17487/RFC5546, December 2009,
              <https://www.rfc-editor.org/info/rfc5546>.

Jenkins & Douglass        Expires 8 August 2022                [Page 44]
Internet-Draft               JMAP Calendars                February 2022

   [RFC6047]  Melnikov, A., Ed., "iCalendar Message-Based
              Interoperability Protocol (iMIP)", RFC 6047,
              DOI 10.17487/RFC6047, December 2010,
              <https://www.rfc-editor.org/info/rfc6047>.

Authors' Addresses

   Neil Jenkins (editor)
   Fastmail
   PO Box 234, Collins St West
   Melbourne  VIC 8007
   Australia

   Email: neilj@fastmailteam.com
   URI:   https://www.fastmail.com

   Michael Douglass (editor)
   Spherical Cow Group
   226 3rd Street
   Troy,  NY 12180
   United States of America

   Email: mdouglass@sphericalcowgroup.com
   URI:   http://sphericalcowgroup.com

Jenkins & Douglass        Expires 8 August 2022                [Page 45]