···1+2+3+4+5+6+7+Internet Engineering Task Force (IETF) N. Jenkins
8+Request for Comments: 8620 Fastmail
9+Category: Standards Track C. Newman
10+ISSN: 2070-1721 Oracle
11+ July 2019
12+13+14+ The JSON Meta Application Protocol (JMAP)
15+16+Abstract
17+18+ This document specifies a protocol for clients to efficiently query,
19+ fetch, and modify JSON-based data objects, with support for push
20+ notification of changes and fast resynchronisation and for out-of-
21+ band binary data upload/download.
22+23+Status of This Memo
24+25+ This is an Internet Standards Track document.
26+27+ This document is a product of the Internet Engineering Task Force
28+ (IETF). It represents the consensus of the IETF community. It has
29+ received public review and has been approved for publication by the
30+ Internet Engineering Steering Group (IESG). Further information on
31+ Internet Standards is available in Section 2 of RFC 7841.
32+33+ Information about the current status of this document, any errata,
34+ and how to provide feedback on it may be obtained at
35+ https://www.rfc-editor.org/info/rfc8620.
36+37+Copyright Notice
38+39+ Copyright (c) 2019 IETF Trust and the persons identified as the
40+ document authors. All rights reserved.
41+42+ This document is subject to BCP 78 and the IETF Trust's Legal
43+ Provisions Relating to IETF Documents
44+ (https://trustee.ietf.org/license-info) in effect on the date of
45+ publication of this document. Please review these documents
46+ carefully, as they describe your rights and restrictions with respect
47+ to this document. Code Components extracted from this document must
48+ include Simplified BSD License text as described in Section 4.e of
49+ the Trust Legal Provisions and are provided without warranty as
50+ described in the Simplified BSD License.
51+52+53+54+55+56+57+58+Jenkins & Newman Standards Track [Page 1]
59+60+RFC 8620 JMAP July 2019
61+62+63+Table of Contents
64+65+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
66+ 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 4
67+ 1.2. The Id Data Type . . . . . . . . . . . . . . . . . . . . 6
68+ 1.3. The Int and UnsignedInt Data Types . . . . . . . . . . . 6
69+ 1.4. The Date and UTCDate Data Types . . . . . . . . . . . . . 7
70+ 1.5. JSON as the Data Encoding Format . . . . . . . . . . . . 7
71+ 1.6. Terminology . . . . . . . . . . . . . . . . . . . . . . . 7
72+ 1.6.1. User . . . . . . . . . . . . . . . . . . . . . . . . 7
73+ 1.6.2. Accounts . . . . . . . . . . . . . . . . . . . . . . 7
74+ 1.6.3. Data Types and Records . . . . . . . . . . . . . . . 8
75+ 1.7. The JMAP API Model . . . . . . . . . . . . . . . . . . . 8
76+ 1.8. Vendor-Specific Extensions . . . . . . . . . . . . . . . 9
77+ 2. The JMAP Session Resource . . . . . . . . . . . . . . . . . . 9
78+ 2.1. Example . . . . . . . . . . . . . . . . . . . . . . . . . 14
79+ 2.2. Service Autodiscovery . . . . . . . . . . . . . . . . . . 15
80+ 3. Structured Data Exchange . . . . . . . . . . . . . . . . . . 16
81+ 3.1. Making an API Request . . . . . . . . . . . . . . . . . . 16
82+ 3.2. The Invocation Data Type . . . . . . . . . . . . . . . . 16
83+ 3.3. The Request Object . . . . . . . . . . . . . . . . . . . 16
84+ 3.3.1. Example Request . . . . . . . . . . . . . . . . . . . 18
85+ 3.4. The Response Object . . . . . . . . . . . . . . . . . . . 18
86+ 3.4.1. Example Response . . . . . . . . . . . . . . . . . . 19
87+ 3.5. Omitting Arguments . . . . . . . . . . . . . . . . . . . 19
88+ 3.6. Errors . . . . . . . . . . . . . . . . . . . . . . . . . 19
89+ 3.6.1. Request-Level Errors . . . . . . . . . . . . . . . . 20
90+ 3.6.2. Method-Level Errors . . . . . . . . . . . . . . . . . 21
91+ 3.7. References to Previous Method Results . . . . . . . . . . 22
92+ 3.8. Localisation of User-Visible Strings . . . . . . . . . . 27
93+ 3.9. Security . . . . . . . . . . . . . . . . . . . . . . . . 28
94+ 3.10. Concurrency . . . . . . . . . . . . . . . . . . . . . . . 28
95+ 4. The Core/echo Method . . . . . . . . . . . . . . . . . . . . 28
96+ 4.1. Example . . . . . . . . . . . . . . . . . . . . . . . . . 28
97+ 5. Standard Methods and Naming Convention . . . . . . . . . . . 29
98+ 5.1. /get . . . . . . . . . . . . . . . . . . . . . . . . . . 29
99+ 5.2. /changes . . . . . . . . . . . . . . . . . . . . . . . . 30
100+ 5.3. /set . . . . . . . . . . . . . . . . . . . . . . . . . . 34
101+ 5.4. /copy . . . . . . . . . . . . . . . . . . . . . . . . . . 40
102+ 5.5. /query . . . . . . . . . . . . . . . . . . . . . . . . . 42
103+ 5.6. /queryChanges . . . . . . . . . . . . . . . . . . . . . . 48
104+ 5.7. Examples . . . . . . . . . . . . . . . . . . . . . . . . 51
105+ 5.8. Proxy Considerations . . . . . . . . . . . . . . . . . . 58
106+ 6. Binary Data . . . . . . . . . . . . . . . . . . . . . . . . . 58
107+ 6.1. Uploading Binary Data . . . . . . . . . . . . . . . . . . 59
108+ 6.2. Downloading Binary Data . . . . . . . . . . . . . . . . . 60
109+ 6.3. Blob/copy . . . . . . . . . . . . . . . . . . . . . . . . 61
110+111+112+113+114+Jenkins & Newman Standards Track [Page 2]
115+116+RFC 8620 JMAP July 2019
117+118+119+ 7. Push . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
120+ 7.1. The StateChange Object . . . . . . . . . . . . . . . . . 63
121+ 7.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 64
122+ 7.2. PushSubscription . . . . . . . . . . . . . . . . . . . . 64
123+ 7.2.1. PushSubscription/get . . . . . . . . . . . . . . . . 67
124+ 7.2.2. PushSubscription/set . . . . . . . . . . . . . . . . 68
125+ 7.2.3. Example . . . . . . . . . . . . . . . . . . . . . . . 69
126+ 7.3. Event Source . . . . . . . . . . . . . . . . . . . . . . 71
127+ 8. Security Considerations . . . . . . . . . . . . . . . . . . . 73
128+ 8.1. Transport Confidentiality . . . . . . . . . . . . . . . . 73
129+ 8.2. Authentication Scheme . . . . . . . . . . . . . . . . . . 73
130+ 8.3. Service Autodiscovery . . . . . . . . . . . . . . . . . . 73
131+ 8.4. JSON Parsing . . . . . . . . . . . . . . . . . . . . . . 74
132+ 8.5. Denial of Service . . . . . . . . . . . . . . . . . . . . 74
133+ 8.6. Connection to Unknown Push Server . . . . . . . . . . . . 74
134+ 8.7. Push Encryption . . . . . . . . . . . . . . . . . . . . . 75
135+ 8.8. Traffic Analysis . . . . . . . . . . . . . . . . . . . . 76
136+ 9. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 76
137+ 9.1. Assignment of jmap Service Name . . . . . . . . . . . . . 76
138+ 9.2. Registration of Well-Known URI Suffix for JMAP . . . . . 76
139+ 9.3. Registration of the jmap URN Sub-namespace . . . . . . . 77
140+ 9.4. Creation of "JMAP Capabilities" Registry . . . . . . . . 77
141+ 9.4.1. Preliminary Community Review . . . . . . . . . . . . 77
142+ 9.4.2. Submit Request to IANA . . . . . . . . . . . . . . . 78
143+ 9.4.3. Designated Expert Review . . . . . . . . . . . . . . 78
144+ 9.4.4. Change Procedures . . . . . . . . . . . . . . . . . . 78
145+ 9.4.5. JMAP Capabilities Registry Template . . . . . . . . . 79
146+ 9.4.6. Initial Registration for JMAP Core . . . . . . . . . 79
147+ 9.4.7. Registration for JMAP Error Placeholder in JMAP
148+ Capabilities Registry . . . . . . . . . . . . . . . . 80
149+ 9.5. Creation of "JMAP Error Codes" Registry . . . . . . . . . 80
150+ 9.5.1. Expert Review . . . . . . . . . . . . . . . . . . . . 80
151+ 9.5.2. JMAP Error Codes Registry Template . . . . . . . . . 81
152+ 9.5.3. Initial Contents for the JMAP Error Codes Registry . 81
153+ 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 86
154+ 10.1. Normative References . . . . . . . . . . . . . . . . . . 86
155+ 10.2. Informative References . . . . . . . . . . . . . . . . . 89
156+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 90
157+158+159+160+161+162+163+164+165+166+167+168+169+170+Jenkins & Newman Standards Track [Page 3]
171+172+RFC 8620 JMAP July 2019
173+174+175+1. Introduction
176+177+ The JSON Meta Application Protocol (JMAP) is used for synchronising
178+ data, such as mail, calendars, or contacts, between a client and a
179+ server. It is optimised for mobile and web environments and aims to
180+ provide a consistent interface to different data types.
181+182+ This specification is for the generic mechanism of data
183+ synchronisation. Further specifications define the data models for
184+ different data types that may be synchronised via JMAP.
185+186+ JMAP is designed to make efficient use of limited network resources.
187+ Multiple API calls may be batched in a single request to the server,
188+ reducing round trips and improving battery life on mobile devices.
189+ Push connections remove the need for polling, and an efficient delta
190+ update mechanism ensures a minimum amount of data is transferred.
191+192+ JMAP is designed to be horizontally scalable to a very large number
193+ of users. This is facilitated by separate endpoints for users after
194+ login, the separation of binary and structured data, and a data model
195+ for sharing that does not allow data dependencies between accounts.
196+197+1.1. Notational Conventions
198+199+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
200+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
201+ "OPTIONAL" in this document are to be interpreted as described in
202+ BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all
203+ capitals, as shown here.
204+205+ The underlying format used for this specification is JSON.
206+ Consequently, the terms "object" and "array" as well as the four
207+ primitive types (strings, numbers, booleans, and null) are to be
208+ interpreted as described in Section 1 of [RFC8259]. Unless otherwise
209+ noted, all the property names and values are case sensitive.
210+211+ Some examples in this document contain "partial" JSON documents used
212+ for illustrative purposes. In these examples, three periods "..."
213+ are used to indicate a portion of the document that has been removed
214+ for compactness.
215+216+ For compatibility with publishing requirements, line breaks have been
217+ inserted inside long JSON strings, with the following continuation
218+ lines indented. To form the valid JSON example, any line breaks
219+ inside a string must be replaced with a space and any other white
220+ space after the line break removed.
221+222+223+224+225+226+Jenkins & Newman Standards Track [Page 4]
227+228+RFC 8620 JMAP July 2019
229+230+231+ Unless otherwise specified, examples of API exchanges only show the
232+ methodCalls array of the Request object or the methodResponses array
233+ of the Response object. For compactness, the rest of the Request/
234+ Response object is omitted.
235+236+ Type signatures are given for all JSON values in this document. The
237+ following conventions are used:
238+239+ o "*" - The type is undefined (the value could be any type, although
240+ permitted values may be constrained by the context of this value).
241+242+ o "String" - The JSON string type.
243+244+ o "Number" - The JSON number type.
245+246+ o "Boolean" - The JSON boolean type.
247+248+ o "A[B]" - A JSON object where the keys are all of type "A", and the
249+ values are all of type "B".
250+251+ o "A[]" - An array of values of type "A".
252+253+ o "A|B" - The value is either of type "A" or of type "B".
254+255+ Other types may also be given, with their representation defined
256+ elsewhere in this document.
257+258+ Object properties may also have a set of attributes defined along
259+ with the type signature. These have the following meanings:
260+261+ o "server-set" -- Only the server can set the value for this
262+ property. The client MUST NOT send this property when creating a
263+ new object of this type.
264+265+ o "immutable" -- The value MUST NOT change after the object is
266+ created.
267+268+ o "default" -- (This is followed by a JSON value). The value that
269+ will be used for this property if it is omitted in an argument or
270+ when creating a new object of this type.
271+272+273+274+275+276+277+278+279+280+281+282+Jenkins & Newman Standards Track [Page 5]
283+284+RFC 8620 JMAP July 2019
285+286+287+1.2. The Id Data Type
288+289+ All record ids are assigned by the server and are immutable.
290+291+ Where "Id" is given as a data type, it means a "String" of at least 1
292+ and a maximum of 255 octets in size, and it MUST only contain
293+ characters from the "URL and Filename Safe" base64 alphabet, as
294+ defined in Section 5 of [RFC4648], excluding the pad character ("=").
295+ This means the allowed characters are the ASCII alphanumeric
296+ characters ("A-Za-z0-9"), hyphen ("-"), and underscore ("_").
297+298+ These characters are safe to use in almost any context (e.g.,
299+ filesystems, URIs, and IMAP atoms). For maximum safety, servers
300+ SHOULD also follow defensive allocation strategies to avoid creating
301+ risks where glob completion or data type detection may be present
302+ (e.g., on filesystems or in spreadsheets). In particular, it is wise
303+ to avoid:
304+305+ o Ids starting with a dash
306+307+ o Ids starting with digits
308+309+ o Ids that contain only digits
310+311+ o Ids that differ only by ASCII case (for example, A vs. a)
312+313+ o the specific sequence of three characters "NIL" (because this
314+ sequence can be confused with the IMAP protocol expression of the
315+ null value)
316+317+ A good solution to these issues is to prefix every id with a single
318+ alphabetical character.
319+320+1.3. The Int and UnsignedInt Data Types
321+322+ Where "Int" is given as a data type, it means an integer in the range
323+ -2^53+1 <= value <= 2^53-1, the safe range for integers stored in a
324+ floating-point double, represented as a JSON "Number".
325+326+ Where "UnsignedInt" is given as a data type, it means an "Int" where
327+ the value MUST be in the range 0 <= value <= 2^53-1.
328+329+330+331+332+333+334+335+336+337+338+Jenkins & Newman Standards Track [Page 6]
339+340+RFC 8620 JMAP July 2019
341+342+343+1.4. The Date and UTCDate Data Types
344+345+ Where "Date" is given as a type, it means a string in "date-time"
346+ format [RFC3339]. To ensure a normalised form, the "time-secfrac"
347+ MUST always be omitted if zero, and any letters in the string (e.g.,
348+ "T" and "Z") MUST be uppercase. For example,
349+ "2014-10-30T14:12:00+08:00".
350+351+ Where "UTCDate" is given as a type, it means a "Date" where the
352+ "time-offset" component MUST be "Z" (i.e., it must be in UTC time).
353+ For example, "2014-10-30T06:12:00Z".
354+355+1.5. JSON as the Data Encoding Format
356+357+ JSON is a text-based data interchange format as specified in
358+ [RFC8259]. The Internet JSON (I-JSON) format defined in [RFC7493] is
359+ a strict subset of this, adding restrictions to avoid potentially
360+ confusing scenarios (for example, it mandates that an object MUST NOT
361+ have two members with the same name).
362+363+ All data sent from the client to the server or from the server to the
364+ client (except binary file upload/download) MUST be valid I-JSON
365+ according to the RFC and is therefore case sensitive and encoded in
366+ UTF-8 [RFC3629].
367+368+1.6. Terminology
369+370+1.6.1. User
371+372+ A user is a person accessing data via JMAP. A user has a set of
373+ permissions determining the data that they can see.
374+375+1.6.2. Accounts
376+377+ An account is a collection of data. A single account may contain an
378+ arbitrary set of data types, for example, a collection of mail,
379+ contacts, and calendars. Most JMAP methods take a mandatory
380+ "accountId" argument that specifies on which account the operations
381+ are to take place.
382+383+ An account is not the same as a user, although it is common for a
384+ primary account to directly belong to the user. For example, you may
385+ have an account that contains data for a group or business, to which
386+ multiple users have access.
387+388+389+390+391+392+393+394+Jenkins & Newman Standards Track [Page 7]
395+396+RFC 8620 JMAP July 2019
397+398+399+ A single set of credentials may provide access to multiple accounts,
400+ for example, if another user is sharing their work calendar with the
401+ authenticated user or if there is a group mailbox for a support-desk
402+ inbox.
403+404+ In the event of a severe internal error, a server may have to
405+ reallocate ids or do something else that violates standard JMAP data
406+ constraints for an account. In this situation, the data on the
407+ server is no longer compatible with cached data the client may have
408+ from before. The server MUST treat this as though the account has
409+ been deleted and then recreated with a new account id. Clients will
410+ then be forced to throw away any data with the old account id and
411+ refetch all data from scratch.
412+413+1.6.3. Data Types and Records
414+415+ JMAP provides a uniform interface for creating, retrieving, updating,
416+ and deleting various types of objects. A "data type" is a collection
417+ of named, typed properties, just like the schema for a database
418+ table. Each instance of a data type is called a "record".
419+420+ The id of a record is immutable and assigned by the server. The id
421+ MUST be unique among all records of the *same type* within the *same
422+ account*. Ids may clash across accounts or for two records of
423+ different types within the same account.
424+425+1.7. The JMAP API Model
426+427+ JMAP uses HTTP [RFC7230] to expose API, push, upload, and download
428+ resources. All HTTP requests MUST use the "https://" scheme (HTTP
429+ over TLS [RFC2818]). All HTTP requests MUST be authenticated.
430+431+ An authenticated client can fetch the user's Session object with
432+ details about the data and capabilities the server can provide as
433+ shown in Section 2. The client may then exchange data with the
434+ server in the following ways:
435+436+ 1. The client may make an API request to the server to get or set
437+ structured data. This request consists of an ordered series of
438+ method calls. These are processed by the server, which then
439+ returns an ordered series of responses. This is described in
440+ Sections 3, 4, and 5.
441+442+ 2. The client may download or upload binary files from/to the
443+ server. This is detailed in Section 6.
444+445+ 3. The client may connect to a push channel on the server, to be
446+ notified when data has changed. This is explained in Section 7.
447+448+449+450+Jenkins & Newman Standards Track [Page 8]
451+452+RFC 8620 JMAP July 2019
453+454+455+1.8. Vendor-Specific Extensions
456+457+ Individual services will have custom features they wish to expose
458+ over JMAP. This may take the form of extra data types and/or methods
459+ not in the spec, extra arguments to JMAP methods, or extra properties
460+ on existing data types (which may also appear in arguments to methods
461+ that take property names).
462+463+ The server can advertise custom extensions it supports by including
464+ the identifiers in the capabilities object. Identifiers for vendor
465+ extensions MUST be a URL belonging to a domain owned by the vendor,
466+ to avoid conflict. The URL SHOULD resolve to documentation for the
467+ changes the extension makes.
468+469+ The client MUST opt in to use an extension by passing the appropriate
470+ capability identifier in the "using" array of the Request object, as
471+ described in Section 3.3. The server MUST only follow the
472+ specifications that are opted into and behave as though it does not
473+ implement anything else when processing a request. This is to ensure
474+ compatibility with clients that don't know about a specific custom
475+ extension and for compatibility with future versions of JMAP.
476+477+2. The JMAP Session Resource
478+479+ You need two things to connect to a JMAP server:
480+481+ 1. The URL for the JMAP Session resource. This may be requested
482+ directly from the user or discovered automatically based on a
483+ username domain (see Section 2.2 below).
484+485+ 2. Credentials to authenticate with. How to obtain credentials is
486+ out of scope for this document.
487+488+ A successful authenticated GET request to the JMAP Session resource
489+ MUST return a JSON-encoded *Session* object, giving details about the
490+ data and capabilities the server can provide to the client given
491+ those credentials. It has the following properties:
492+493+ o capabilities: "String[Object]"
494+495+ An object specifying the capabilities of this server. Each key is
496+ a URI for a capability supported by the server. The value for
497+ each of these keys is an object with further information about the
498+ server's capabilities in relation to that capability.
499+500+ The client MUST ignore any properties it does not understand.
501+502+503+504+505+506+Jenkins & Newman Standards Track [Page 9]
507+508+RFC 8620 JMAP July 2019
509+510+511+ The capabilities object MUST include a property called
512+ "urn:ietf:params:jmap:core". The value of this property is an
513+ object that MUST contain the following information on server
514+ capabilities (suggested minimum values for limits are supplied
515+ that allow clients to make efficient use of the network):
516+517+ * maxSizeUpload: "UnsignedInt"
518+519+ The maximum file size, in octets, that the server will accept
520+ for a single file upload (for any purpose). Suggested minimum:
521+ 50,000,000.
522+523+ * maxConcurrentUpload: "UnsignedInt"
524+525+ The maximum number of concurrent requests the server will
526+ accept to the upload endpoint. Suggested minimum: 4.
527+528+ * maxSizeRequest: "UnsignedInt"
529+530+ The maximum size, in octets, that the server will accept for a
531+ single request to the API endpoint. Suggested minimum:
532+ 10,000,000.
533+534+ * maxConcurrentRequests: "UnsignedInt"
535+536+ The maximum number of concurrent requests the server will
537+ accept to the API endpoint. Suggested minimum: 4.
538+539+ * maxCallsInRequest: "UnsignedInt"
540+541+ The maximum number of method calls the server will accept in a
542+ single request to the API endpoint. Suggested minimum: 16.
543+544+ * maxObjectsInGet: "UnsignedInt"
545+546+ The maximum number of objects that the client may request in a
547+ single /get type method call. Suggested minimum: 500.
548+549+ * maxObjectsInSet: "UnsignedInt"
550+551+ The maximum number of objects the client may send to create,
552+ update, or destroy in a single /set type method call. This is
553+ the combined total, e.g., if the maximum is 10, you could not
554+ create 7 objects and destroy 6, as this would be 13 actions,
555+ which exceeds the limit. Suggested minimum: 500.
556+557+558+559+560+561+562+Jenkins & Newman Standards Track [Page 10]
563+564+RFC 8620 JMAP July 2019
565+566+567+ * collationAlgorithms: "String[]"
568+569+ A list of identifiers for algorithms registered in the
570+ collation registry, as defined in [RFC4790], that the server
571+ supports for sorting when querying records.
572+573+ Specifications for future capabilities will define their own
574+ properties on the capabilities object.
575+576+ Servers MAY advertise vendor-specific JMAP extensions, as
577+ described in Section 1.8. To avoid conflict, an identifier for a
578+ vendor-specific extension MUST be a URL with a domain owned by the
579+ vendor. Clients MUST opt in to any capability it wishes to use
580+ (see Section 3.3).
581+582+ o accounts: "Id[Account]"
583+584+ A map of an account id to an Account object for each account (see
585+ Section 1.6.2) the user has access to. An *Account* object has
586+ the following properties:
587+588+ * name: "String"
589+590+ A user-friendly string to show when presenting content from
591+ this account, e.g., the email address representing the owner of
592+ the account.
593+594+ * isPersonal: "Boolean"
595+596+ This is true if the account belongs to the authenticated user
597+ rather than a group account or a personal account of another
598+ user that has been shared with them.
599+600+ * isReadOnly: "Boolean"
601+602+ This is true if the entire account is read-only.
603+604+ * accountCapabilities: "String[Object]"
605+606+ The set of capability URIs for the methods supported in this
607+ account. Each key is a URI for a capability that has methods
608+ you can use with this account. The value for each of these
609+ keys is an object with further information about the account's
610+ permissions and restrictions with respect to this capability,
611+ as defined in the capability's specification.
612+613+ The client MUST ignore any properties it does not understand.
614+615+616+617+618+Jenkins & Newman Standards Track [Page 11]
619+620+RFC 8620 JMAP July 2019
621+622+623+ The server advertises the full list of capabilities it supports
624+ in the capabilities object, as defined above. If the
625+ capability defines new methods, the server MUST include it in
626+ the accountCapabilities object if the user may use those
627+ methods with this account. It MUST NOT include it in the
628+ accountCapabilities object if the user cannot use those methods
629+ with this account.
630+631+ For example, you may have access to your own account with mail,
632+ calendars, and contacts data and also a shared account that
633+ only has contacts data (a business address book, for example).
634+ In this case, the accountCapabilities property on the first
635+ account would include something like
636+ "urn:ietf:params:jmap:mail", "urn:ietf:params:jmap:calendars",
637+ and "urn:ietf:params:jmap:contacts", while the second account
638+ would just have the last of these.
639+640+ Attempts to use the methods defined in a capability with one of
641+ the accounts that does not support that capability are rejected
642+ with an "accountNotSupportedByMethod" error (see "Method-Level
643+ Errors", Section 3.6.2).
644+645+ o primaryAccounts: "String[Id]"
646+647+ A map of capability URIs (as found in accountCapabilities) to the
648+ account id that is considered to be the user's main or default
649+ account for data pertaining to that capability. If no account
650+ being returned belongs to the user, or in any other way there is
651+ no appropriate way to determine a default account, there MAY be no
652+ entry for a particular URI, even though that capability is
653+ supported by the server (and in the capabilities object).
654+ "urn:ietf:params:jmap:core" SHOULD NOT be present.
655+656+ o username: "String"
657+658+ The username associated with the given credentials, or the empty
659+ string if none.
660+661+ o apiUrl: "String"
662+663+ The URL to use for JMAP API requests.
664+665+666+667+668+669+670+671+672+673+674+Jenkins & Newman Standards Track [Page 12]
675+676+RFC 8620 JMAP July 2019
677+678+679+ o downloadUrl: "String"
680+681+ The URL endpoint to use when downloading files, in URI Template
682+ (level 1) format [RFC6570]. The URL MUST contain variables called
683+ "accountId", "blobId", "type", and "name". The use of these
684+ variables is described in Section 6.2. Due to potential encoding
685+ issues with slashes in content types, it is RECOMMENDED to put the
686+ "type" variable in the query section of the URL.
687+688+ o uploadUrl: "String"
689+690+ The URL endpoint to use when uploading files, in URI Template
691+ (level 1) format [RFC6570]. The URL MUST contain a variable
692+ called "accountId". The use of this variable is described in
693+ Section 6.1.
694+695+ o eventSourceUrl: "String"
696+697+ The URL to connect to for push events, as described in
698+ Section 7.3, in URI Template (level 1) format [RFC6570]. The URL
699+ MUST contain variables called "types", "closeafter", and "ping".
700+ The use of these variables is described in Section 7.3.
701+702+ o state: "String"
703+704+ A (preferably short) string representing the state of this object
705+ on the server. If the value of any other property on the Session
706+ object changes, this string will change. The current value is
707+ also returned on the API Response object (see Section 3.4),
708+ allowing clients to quickly determine if the session information
709+ has changed (e.g., an account has been added or removed), so they
710+ need to refetch the object.
711+712+ To ensure future compatibility, other properties MAY be included on
713+ the Session object. Clients MUST ignore any properties they are not
714+ expecting.
715+716+ Implementors must take care to avoid inappropriate caching of the
717+ Session object at the HTTP layer. Since the client should only
718+ refetch when it detects there is a change (via the sessionState
719+ property of an API response), it is RECOMMENDED to disable HTTP
720+ caching altogether, for example, by setting "Cache-Control: no-cache,
721+ no-store, must-revalidate" on the response.
722+723+724+725+726+727+728+729+730+Jenkins & Newman Standards Track [Page 13]
731+732+RFC 8620 JMAP July 2019
733+734+735+2.1. Example
736+737+ In the following example Session object, the user has access to their
738+ own mail and contacts via JMAP, as well as read-only access to shared
739+ mail from another user. The server is advertising a custom
740+ "https://example.com/apis/foobar" capability.
741+742+ {
743+ "capabilities": {
744+ "urn:ietf:params:jmap:core": {
745+ "maxSizeUpload": 50000000,
746+ "maxConcurrentUpload": 8,
747+ "maxSizeRequest": 10000000,
748+ "maxConcurrentRequest": 8,
749+ "maxCallsInRequest": 32,
750+ "maxObjectsInGet": 256,
751+ "maxObjectsInSet": 128,
752+ "collationAlgorithms": [
753+ "i;ascii-numeric",
754+ "i;ascii-casemap",
755+ "i;unicode-casemap"
756+ ]
757+ },
758+ "urn:ietf:params:jmap:mail": {}
759+ "urn:ietf:params:jmap:contacts": {},
760+ "https://example.com/apis/foobar": {
761+ "maxFoosFinangled": 42
762+ }
763+ },
764+ "accounts": {
765+ "A13824": {
766+ "name": "john@example.com",
767+ "isPersonal": true,
768+ "isReadOnly": false,
769+ "accountCapabilities": {
770+ "urn:ietf:params:jmap:mail": {
771+ "maxMailboxesPerEmail": null,
772+ "maxMailboxDepth": 10,
773+ ...
774+ },
775+ "urn:ietf:params:jmap:contacts": {
776+ ...
777+ }
778+ }
779+ },
780+781+782+783+784+785+786+Jenkins & Newman Standards Track [Page 14]
787+788+RFC 8620 JMAP July 2019
789+790+791+ "A97813": {
792+ "name": "jane@example.com",
793+ "isPersonal": false,
794+ "isReadOnly": true,
795+ "accountCapabilities": {
796+ "urn:ietf:params:jmap:mail": {
797+ "maxMailboxesPerEmail": 1,
798+ "maxMailboxDepth": 10,
799+ ...
800+ }
801+ }
802+ }
803+ },
804+ "primaryAccounts": {
805+ "urn:ietf:params:jmap:mail": "A13824",
806+ "urn:ietf:params:jmap:contacts": "A13824"
807+ },
808+ "username": "john@example.com",
809+ "apiUrl": "https://jmap.example.com/api/",
810+ "downloadUrl": "https://jmap.example.com
811+ /download/{accountId}/{blobId}/{name}?accept={type}",
812+ "uploadUrl": "https://jmap.example.com/upload/{accountId}/",
813+ "eventSourceUrl": "https://jmap.example.com
814+ /eventsource/?types={types}&closeafter={closeafter}&ping={ping}",
815+ "state": "75128aab4b1b"
816+ }
817+818+2.2. Service Autodiscovery
819+820+ There are two standardised autodiscovery methods in use for Internet
821+ protocols:
822+823+ o DNS SRV (see [RFC2782], [RFC6186], and [RFC6764])
824+825+ o .well-known/servicename (see [RFC8615])
826+827+ A JMAP-supporting host for the domain "example.com" SHOULD publish a
828+ SRV record "_jmap._tcp.example.com" that gives a hostname and port
829+ (usually port "443"). The JMAP Session resource is then
830+ "https://${hostname}[:${port}]/.well-known/jmap" (following any
831+ redirects).
832+833+ If the client has a username in the form of an email address, it MAY
834+ use the domain portion of this to attempt autodiscovery of the JMAP
835+ server.
836+837+838+839+840+841+842+Jenkins & Newman Standards Track [Page 15]
843+844+RFC 8620 JMAP July 2019
845+846+847+3. Structured Data Exchange
848+849+ The client may make an API request to the server to get or set
850+ structured data. This request consists of an ordered series of
851+ method calls. These are processed by the server, which then returns
852+ an ordered series of responses.
853+854+3.1. Making an API Request
855+856+ To make an API request, the client makes an authenticated POST
857+ request to the API resource, which is defined by the "apiUrl"
858+ property in the Session object (see Section 2).
859+860+ The request MUST be of type "application/json" and consist of a
861+ single JSON-encoded "Request" object, as defined in Section 3.3. If
862+ successful, the response MUST also be of type "application/json" and
863+ consist of a single "Response" object, as defined in Section 3.4.
864+865+3.2. The Invocation Data Type
866+867+ Method calls and responses are represented by the *Invocation* data
868+ type. This is a tuple, represented as a JSON array containing three
869+ elements:
870+871+ 1. A "String" *name* of the method to call or of the response.
872+873+ 2. A "String[*]" object containing named *arguments* for that method
874+ or response.
875+876+ 3. A "String" *method call id*: an arbitrary string from the client
877+ to be echoed back with the responses emitted by that method call
878+ (a method may return 1 or more responses, as it may make implicit
879+ calls to other methods; all responses initiated by this method
880+ call get the same method call id in the response).
881+882+3.3. The Request Object
883+884+ A *Request* object has the following properties:
885+886+ o using: "String[]"
887+888+ The set of capabilities the client wishes to use. The client MAY
889+ include capability identifiers even if the method calls it makes
890+ do not utilise those capabilities. The server advertises the set
891+ of specifications it supports in the Session object (see
892+ Section 2), as keys on the "capabilities" property.
893+894+895+896+897+898+Jenkins & Newman Standards Track [Page 16]
899+900+RFC 8620 JMAP July 2019
901+902+903+ o methodCalls: "Invocation[]"
904+905+ An array of method calls to process on the server. The method
906+ calls MUST be processed sequentially, in order.
907+908+ o createdIds: "Id[Id]" (optional)
909+910+ A map of a (client-specified) creation id to the id the server
911+ assigned when a record was successfully created.
912+913+ As described later in this specification, some records may have a
914+ property that contains the id of another record. To allow more
915+ efficient network usage, you can set this property to reference a
916+ record created earlier in the same API request. Since the real id
917+ is unknown when the request is created, the client can instead
918+ specify the creation id it assigned, prefixed with a "#" (see
919+ Section 5.3 for more details).
920+921+ As the server processes API requests, any time it successfully
922+ creates a new record, it adds the creation id to this map (see the
923+ "create" argument to /set in Section 5.3), with the server-
924+ assigned real id as the value. If it comes across a reference to
925+ a creation id in a create/update, it looks it up in the map and
926+ replaces the reference with the real id, if found.
927+928+ The client can pass an initial value for this map as the
929+ "createdIds" property of the Request object. This may be an empty
930+ object. If given in the request, the response will also include a
931+ createdIds property. This allows proxy servers to easily split a
932+ JMAP request into multiple JMAP requests to send to different
933+ servers. For example, it could send the first two method calls to
934+ server A, then the third to server B, before sending the fourth to
935+ server A again. By passing the createdIds of the previous
936+ response to the next request, it can ensure all of these still
937+ resolve. See Section 5.8 for further discussion of proxy
938+ considerations.
939+940+ Future specifications MAY add further properties to the Request
941+ object to extend the semantics. To ensure forwards compatibility, a
942+ server MUST ignore any other properties it does not understand on the
943+ JMAP Request object.
944+945+946+947+948+949+950+951+952+953+954+Jenkins & Newman Standards Track [Page 17]
955+956+RFC 8620 JMAP July 2019
957+958+959+3.3.1. Example Request
960+961+{
962+ "using": [ "urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail" ],
963+ "methodCalls": [
964+ [ "method1", {
965+ "arg1": "arg1data",
966+ "arg2": "arg2data"
967+ }, "c1" ],
968+ [ "method2", {
969+ "arg1": "arg1data"
970+ }, "c2" ],
971+ [ "method3", {}, "c3" ]
972+ ]
973+}
974+975+3.4. The Response Object
976+977+ A *Response* object has the following properties:
978+979+ o methodResponses: "Invocation[]"
980+981+ An array of responses, in the same format as the "methodCalls" on
982+ the Request object. The output of the methods MUST be added to
983+ the "methodResponses" array in the same order that the methods are
984+ processed.
985+986+ o createdIds: "Id[Id]" (optional; only returned if given in the
987+ request)
988+989+ A map of a (client-specified) creation id to the id the server
990+ assigned when a record was successfully created. This MUST
991+ include all creation ids passed in the original createdIds
992+ parameter of the Request object, as well as any additional ones
993+ added for newly created records.
994+995+ o sessionState: "String"
996+997+ The current value of the "state" string on the Session object, as
998+ described in Section 2. Clients may use this to detect if this
999+ object has changed and needs to be refetched.
1000+1001+ Unless otherwise specified, if the method call completed
1002+ successfully, its response name is the same as the method name in the
1003+ request.
1004+1005+1006+1007+1008+1009+1010+Jenkins & Newman Standards Track [Page 18]
1011+1012+RFC 8620 JMAP July 2019
1013+1014+1015+3.4.1. Example Response
1016+1017+ {
1018+ "methodResponses": [
1019+ [ "method1", {
1020+ "arg1": 3,
1021+ "arg2": "foo"
1022+ }, "c1" ],
1023+ [ "method2", {
1024+ "isBlah": true
1025+ }, "c2" ],
1026+ [ "anotherResponseFromMethod2", {
1027+ "data": 10,
1028+ "yetmoredata": "Hello"
1029+ }, "c2"],
1030+ [ "error", {
1031+ "type":"unknownMethod"
1032+ }, "c3" ]
1033+ ],
1034+ "sessionState": "75128aab4b1b"
1035+ }
1036+1037+3.5. Omitting Arguments
1038+1039+ An argument to a method may be specified to have a default value. If
1040+ omitted by the client, the server MUST treat the method call the same
1041+ as if the default value had been specified. Similarly, the server
1042+ MAY omit any argument in a response that has the default value.
1043+1044+ Unless otherwise specified in a method description, null is the
1045+ default value for any argument in a request or response where this is
1046+ allowed by the type signature. Other arguments may only be omitted
1047+ if an explicit default value is defined in the method description.
1048+1049+3.6. Errors
1050+1051+ There are three different levels of granularity at which an error may
1052+ be returned in JMAP.
1053+1054+ When an API request is made, the request as a whole may be rejected
1055+ due to rate limiting, malformed JSON, request for an unknown
1056+ capability, etc. In this case, the entire request is rejected with
1057+ an appropriate HTTP error response code and an additional JSON body
1058+ with more detail for the client.
1059+1060+ Provided the request itself is syntactically valid (the JSON is valid
1061+ and when decoded, it matches the type signature of a Request object),
1062+ the methods within it are executed sequentially by the server. Each
1063+1064+1065+1066+Jenkins & Newman Standards Track [Page 19]
1067+1068+RFC 8620 JMAP July 2019
1069+1070+1071+ method may individually fail, for example, if invalid arguments are
1072+ given or an unknown method name is called.
1073+1074+ Finally, methods that make changes to the server state often act upon
1075+ a number of different records within a single call. Each record
1076+ change may be separately rejected with a SetError, as described in
1077+ Section 5.3.
1078+1079+3.6.1. Request-Level Errors
1080+1081+ When an HTTP error response is returned to the client, the server
1082+ SHOULD return a JSON "problem details" object as the response body,
1083+ as per [RFC7807].
1084+1085+ The following problem types are defined:
1086+1087+ o "urn:ietf:params:jmap:error:unknownCapability"
1088+ The client included a capability in the "using" property of the
1089+ request that the server does not support.
1090+1091+ o "urn:ietf:params:jmap:error:notJSON"
1092+ The content type of the request was not "application/json" or the
1093+ request did not parse as I-JSON.
1094+1095+ o "urn:ietf:params:jmap:error:notRequest"
1096+ The request parsed as JSON but did not match the type signature of
1097+ the Request object.
1098+1099+ o "urn:ietf:params:jmap:error:limit"
1100+ The request was not processed as it would have exceeded one of the
1101+ request limits defined on the capability object, such as
1102+ maxSizeRequest, maxCallsInRequest, or maxConcurrentRequests. A
1103+ "limit" property MUST also be present on the "problem details"
1104+ object, containing the name of the limit being applied.
1105+1106+3.6.1.1. Example
1107+1108+ {
1109+ "type": "urn:ietf:params:jmap:error:unknownCapability",
1110+ "status": 400,
1111+ "detail": "The Request object used capability
1112+ 'https://example.com/apis/foobar', which is not supported
1113+ by this server."
1114+ }
1115+1116+1117+1118+1119+1120+1121+1122+Jenkins & Newman Standards Track [Page 20]
1123+1124+RFC 8620 JMAP July 2019
1125+1126+1127+ Another example:
1128+1129+ {
1130+ "type": "urn:ietf:params:jmap:error:limit",
1131+ "limit": "maxSizeRequest",
1132+ "status": 400,
1133+ "detail": "The request is larger than the server is willing to
1134+ process."
1135+ }
1136+1137+3.6.2. Method-Level Errors
1138+1139+ If a method encounters an error, the appropriate "error" response
1140+ MUST be inserted at the current point in the "methodResponses" array
1141+ and, unless otherwise specified, further processing MUST NOT happen
1142+ within that method call.
1143+1144+ Any further method calls in the request MUST then be processed as
1145+ normal. Errors at the method level MUST NOT generate an HTTP-level
1146+ error.
1147+1148+ An "error" response looks like this:
1149+1150+ [ "error", {
1151+ "type": "unknownMethod"
1152+ }, "call-id" ]
1153+1154+ The response name is "error", and it MUST have a type property.
1155+ Other properties may be present with further information; these are
1156+ detailed in the error type descriptions where appropriate.
1157+1158+ With the exception of when the "serverPartialFail" error is returned,
1159+ the externally visible state of the server MUST NOT have changed if
1160+ an error is returned at the method level.
1161+1162+ The following error types are defined, which may be returned for any
1163+ method call where appropriate:
1164+1165+ "serverUnavailable": Some internal server resource was temporarily
1166+ unavailable. Attempting the same operation later (perhaps after a
1167+ backoff with a random factor) may succeed.
1168+1169+ "serverFail": An unexpected or unknown error occurred during the
1170+ processing of the call. A "description" property should provide more
1171+ details about the error. The method call made no changes to the
1172+ server's state. Attempting the same operation again is expected to
1173+ fail again. Contacting the service administrator is likely necessary
1174+ to resolve this problem if it is persistent.
1175+1176+1177+1178+Jenkins & Newman Standards Track [Page 21]
1179+1180+RFC 8620 JMAP July 2019
1181+1182+1183+ "serverPartialFail": Some, but not all, expected changes described by
1184+ the method occurred. The client MUST resynchronise impacted data to
1185+ determine server state. Use of this error is strongly discouraged.
1186+1187+ "unknownMethod": The server does not recognise this method name.
1188+1189+ "invalidArguments": One of the arguments is of the wrong type or is
1190+ otherwise invalid, or a required argument is missing. A
1191+ "description" property MAY be present to help debug with an
1192+ explanation of what the problem was. This is a non-localised string,
1193+ and it is not intended to be shown directly to end users.
1194+1195+ "invalidResultReference": The method used a result reference for one
1196+ of its arguments (see Section 3.7), but this failed to resolve.
1197+1198+ "forbidden": The method and arguments are valid, but executing the
1199+ method would violate an Access Control List (ACL) or other
1200+ permissions policy.
1201+1202+ "accountNotFound": The accountId does not correspond to a valid
1203+ account.
1204+1205+ "accountNotSupportedByMethod": The accountId given corresponds to a
1206+ valid account, but the account does not support this method or data
1207+ type.
1208+1209+ "accountReadOnly": This method modifies state, but the account is
1210+ read-only (as returned on the corresponding Account object in the
1211+ JMAP Session resource).
1212+1213+ Further possible errors for a particular method are specified in the
1214+ method descriptions.
1215+1216+ Further general errors MAY be defined in future RFCs. Should a
1217+ client receive an error type it does not understand, it MUST treat it
1218+ the same as the "serverFail" type.
1219+1220+3.7. References to Previous Method Results
1221+1222+ To allow clients to make more efficient use of the network and avoid
1223+ round trips, an argument to one method can be taken from the result
1224+ of a previous method call in the same request.
1225+1226+ To do this, the client prefixes the argument name with "#" (an
1227+ octothorpe). The value is a ResultReference object as described
1228+ below. When processing a method call, the server MUST first check
1229+ the arguments object for any names beginning with "#". If found, the
1230+ result reference should be resolved and the value used as the "real"
1231+1232+1233+1234+Jenkins & Newman Standards Track [Page 22]
1235+1236+RFC 8620 JMAP July 2019
1237+1238+1239+ argument. The method is then processed as normal. If any result
1240+ reference fails to resolve, the whole method MUST be rejected with an
1241+ "invalidResultReference" error. If an arguments object contains the
1242+ same argument name in normal and referenced form (e.g., "foo" and
1243+ "#foo"), the method MUST return an "invalidArguments" error.
1244+1245+ A *ResultReference* object has the following properties:
1246+1247+ o resultOf: "String"
1248+1249+ The method call id (see Section 3.2) of a previous method call in
1250+ the current request.
1251+1252+ o name: "String"
1253+1254+ The required name of a response to that method call.
1255+1256+ o path: "String"
1257+1258+ A pointer into the arguments of the response selected via the name
1259+ and resultOf properties. This is a JSON Pointer [RFC6901], except
1260+ it also allows the use of "*" to map through an array (see the
1261+ description below).
1262+1263+ To resolve:
1264+1265+ 1. Find the first response with a method call id identical to the
1266+ "resultOf" property of the ResultReference in the
1267+ "methodResponses" array from previously processed method calls in
1268+ the same request. If none, evaluation fails.
1269+1270+ 2. If the response name is not identical to the "name" property of
1271+ the ResultReference, evaluation fails.
1272+1273+ 3. Apply the "path" to the arguments object of the response (the
1274+ second item in the response array) following the JSON Pointer
1275+ algorithm [RFC6901], except with the following addition in
1276+ "Evaluation" (see Section 4):
1277+1278+ If the currently referenced value is a JSON array, the reference
1279+ token may be exactly the single character "*", making the new
1280+ referenced value the result of applying the rest of the JSON
1281+ Pointer tokens to every item in the array and returning the
1282+ results in the same order in a new array. If the result of
1283+ applying the rest of the pointer tokens to each item was itself
1284+ an array, the contents of this array are added to the output
1285+ rather than the array itself (i.e., the result is flattened from
1286+ an array of arrays to a single array). If the result of applying
1287+1288+1289+1290+Jenkins & Newman Standards Track [Page 23]
1291+1292+RFC 8620 JMAP July 2019
1293+1294+1295+ the rest of the pointer tokens to a value was itself an array,
1296+ its items should be included individually in the output rather
1297+ than including the array itself (i.e., the result is flattened
1298+ from an array of arrays to a single array).
1299+1300+ As a simple example, suppose we have the following API request
1301+ "methodCalls":
1302+1303+ [[ "Foo/changes", {
1304+ "accountId": "A1",
1305+ "sinceState": "abcdef"
1306+ }, "t0" ],
1307+ [ "Foo/get", {
1308+ "accountId": "A1",
1309+ "#ids": {
1310+ "resultOf": "t0",
1311+ "name": "Foo/changes",
1312+ "path": "/created"
1313+ }
1314+ }, "t1" ]]
1315+1316+ After executing the first method call, the "methodResponses" array
1317+ is:
1318+1319+ [[ "Foo/changes", {
1320+ "accountId": "A1",
1321+ "oldState": "abcdef",
1322+ "newState": "123456",
1323+ "hasMoreChanges": false,
1324+ "created": [ "f1", "f4" ],
1325+ "updated": [],
1326+ "destroyed": []
1327+ }, "t0" ]]
1328+1329+ To execute the "Foo/get" call, we look through the arguments and find
1330+ there is one with a "#" prefix. To resolve this, we apply the
1331+ algorithm above:
1332+1333+ 1. Find the first response with method call id "t0". The "Foo/
1334+ changes" response fulfils this criterion.
1335+1336+ 2. Check that the response name is the same as in the result
1337+ reference. It is, so this is fine.
1338+1339+ 3. Apply the "path" as a JSON Pointer to the arguments object. This
1340+ simply selects the "created" property, so the result of
1341+ evaluating is: [ "f1", "f4" ].
1342+1343+1344+1345+1346+Jenkins & Newman Standards Track [Page 24]
1347+1348+RFC 8620 JMAP July 2019
1349+1350+1351+ The JMAP server now continues to process the "Foo/get" call as though
1352+ the arguments were:
1353+1354+ {
1355+ "accountId": "A1",
1356+ "ids": [ "f1", "f4" ]
1357+ }
1358+1359+ Now, a more complicated example using the JMAP Mail data model: fetch
1360+ the "from"/"date"/"subject" for every Email in the first 10 Threads
1361+ in the inbox (sorted newest first):
1362+1363+ [[ "Email/query", {
1364+ "accountId": "A1",
1365+ "filter": { "inMailbox": "id_of_inbox" },
1366+ "sort": [{ "property": "receivedAt", "isAscending": false }],
1367+ "collapseThreads": true,
1368+ "position": 0,
1369+ "limit": 10,
1370+ "calculateTotal": true
1371+ }, "t0" ],
1372+ [ "Email/get", {
1373+ "accountId": "A1",
1374+ "#ids": {
1375+ "resultOf": "t0",
1376+ "name": "Email/query",
1377+ "path": "/ids"
1378+ },
1379+ "properties": [ "threadId" ]
1380+ }, "t1" ],
1381+ [ "Thread/get", {
1382+ "accountId": "A1",
1383+ "#ids": {
1384+ "resultOf": "t1",
1385+ "name": "Email/get",
1386+ "path": "/list/*/threadId"
1387+ }
1388+ }, "t2" ],
1389+ [ "Email/get", {
1390+ "accountId": "A1",
1391+ "#ids": {
1392+ "resultOf": "t2",
1393+ "name": "Thread/get",
1394+ "path": "/list/*/emailIds"
1395+ },
1396+ "properties": [ "from", "receivedAt", "subject" ]
1397+ }, "t3" ]]
1398+1399+1400+1401+1402+Jenkins & Newman Standards Track [Page 25]
1403+1404+RFC 8620 JMAP July 2019
1405+1406+1407+ After executing the first 3 method calls, the "methodResponses" array
1408+ might be:
1409+1410+ [[ "Email/query", {
1411+ "accountId": "A1",
1412+ "queryState": "abcdefg",
1413+ "canCalculateChanges": true,
1414+ "position": 0,
1415+ "total": 101,
1416+ "ids": [ "msg1023", "msg223", "msg110", "msg93", "msg91",
1417+ "msg38", "msg36", "msg33", "msg11", "msg1" ]
1418+ }, "t0" ],
1419+ [ "Email/get", {
1420+ "accountId": "A1",
1421+ "state": "123456",
1422+ "list": [{
1423+ "id": "msg1023",
1424+ "threadId": "trd194"
1425+ }, {
1426+ "id": "msg223",
1427+ "threadId": "trd114"
1428+ },
1429+ ...
1430+ ],
1431+ "notFound": []
1432+ }, "t1" ],
1433+ [ "Thread/get", {
1434+ "accountId": "A1",
1435+ "state": "123456",
1436+ "list": [{
1437+ "id": "trd194",
1438+ "emailIds": [ "msg1020", "msg1021", "msg1023" ]
1439+ }, {
1440+ "id": "trd114",
1441+ "emailIds": [ "msg201", "msg223" ]
1442+ },
1443+ ...
1444+ ],
1445+ "notFound": []
1446+ }, "t2" ]]
1447+1448+ To execute the final "Email/get" call, we look through the arguments
1449+ and find there is one with a "#" prefix. To resolve this, we apply
1450+ the algorithm:
1451+1452+ 1. Find the first response with method call id "t2". The "Thread/
1453+ get" response fulfils this criterion.
1454+1455+1456+1457+1458+Jenkins & Newman Standards Track [Page 26]
1459+1460+RFC 8620 JMAP July 2019
1461+1462+1463+ 2. "Thread/get" is the name specified in the result reference, so
1464+ this is fine.
1465+1466+ 3. Apply the "path" as a JSON Pointer to the arguments object.
1467+ Token by token:
1468+1469+ 1. "list": get the array of thread objects
1470+1471+ 2. "*": for each of the items in the array:
1472+1473+ a. "emailIds": get the array of Email ids
1474+1475+ b. Concatenate these into a single array of all the ids in
1476+ the result.
1477+1478+ The JMAP server now continues to process the "Email/get" call as
1479+ though the arguments were:
1480+1481+{
1482+ "accountId": "A1",
1483+ "ids": [ "msg1020", "msg1021", "msg1023", "msg201", "msg223", ... ],
1484+ "properties": [ "from", "receivedAt", "subject" ]
1485+}
1486+1487+ The ResultReference performs a similar role to that of the creation
1488+ id, in that it allows a chained method call to refer to information
1489+ not available when the request is generated. However, they are
1490+ different things and not interchangeable; the only commonality is the
1491+ octothorpe used to indicate them.
1492+1493+3.8. Localisation of User-Visible Strings
1494+1495+ If returning a custom string to be displayed to the user, for
1496+ example, an error message, the server SHOULD use information from the
1497+ Accept-Language header of the request (as defined in Section 5.3.5 of
1498+ [RFC7231]) to choose the best available localisation. The Content-
1499+ Language header of the response (see Section 3.1.3.2 of [RFC7231])
1500+ SHOULD indicate the language being used for user-visible strings.
1501+1502+ For example, suppose a request was made with the following header:
1503+1504+ Accept-Language: fr-CH, fr;q=0.9, de;q=0.8, en;q=0.7, *;q=0.5
1505+1506+ and a method generated an error to display to the user. The server
1507+ has translations of the error message in English and German. Looking
1508+ at the Accept-Language header, the user's preferred language is
1509+ French. Since we don't have a translation for this, we look at the
1510+1511+1512+1513+1514+Jenkins & Newman Standards Track [Page 27]
1515+1516+RFC 8620 JMAP July 2019
1517+1518+1519+ next most preferred, which is German. We have a German translation,
1520+ so the server returns this and indicates the language chosen in a
1521+ Content-Language header like so:
1522+1523+ Content-Language: de
1524+1525+3.9. Security
1526+1527+ As always, the server must be strict about data received from the
1528+ client. Arguments need to be checked for validity; a malicious user
1529+ could attempt to find an exploit through the API. In case of invalid
1530+ arguments (unknown/insufficient/wrong type for data, etc.), the
1531+ method MUST return an "invalidArguments" error and terminate.
1532+1533+3.10. Concurrency
1534+1535+ Method calls within a single request MUST be executed in order.
1536+ However, method calls from different concurrent API requests may be
1537+ interleaved. This means that the data on the server may change
1538+ between two method calls within a single API request.
1539+1540+4. The Core/echo Method
1541+1542+ The "Core/echo" method returns exactly the same arguments as it is
1543+ given. It is useful for testing if you have a valid authenticated
1544+ connection to a JMAP API endpoint.
1545+1546+4.1. Example
1547+1548+ Request:
1549+1550+ [[ "Core/echo", {
1551+ "hello": true,
1552+ "high": 5
1553+ }, "b3ff" ]]
1554+1555+ Response:
1556+1557+ [[ "Core/echo", {
1558+ "hello": true,
1559+ "high": 5
1560+ }, "b3ff" ]]
1561+1562+1563+1564+1565+1566+1567+1568+1569+1570+Jenkins & Newman Standards Track [Page 28]
1571+1572+RFC 8620 JMAP July 2019
1573+1574+1575+5. Standard Methods and Naming Convention
1576+1577+ JMAP provides a uniform interface for creating, retrieving, updating,
1578+ and deleting objects of a particular type. For a "Foo" data type,
1579+ records of that type would be fetched via a "Foo/get" call and
1580+ modified via a "Foo/set" call. Delta updates may be fetched via a
1581+ "Foo/changes" call. These methods all follow a standard format as
1582+ described below.
1583+1584+ Some types may not have all these methods. Specifications defining
1585+ types MUST specify which methods are available for the type.
1586+1587+5.1. /get
1588+1589+ Objects of type Foo are fetched via a call to "Foo/get".
1590+1591+ It takes the following arguments:
1592+1593+ o accountId: "Id"
1594+1595+ The id of the account to use.
1596+1597+ o ids: "Id[]|null"
1598+1599+ The ids of the Foo objects to return. If null, then *all* records
1600+ of the data type are returned, if this is supported for that data
1601+ type and the number of records does not exceed the
1602+ "maxObjectsInGet" limit.
1603+1604+ o properties: "String[]|null"
1605+1606+ If supplied, only the properties listed in the array are returned
1607+ for each Foo object. If null, all properties of the object are
1608+ returned. The id property of the object is *always* returned,
1609+ even if not explicitly requested. If an invalid property is
1610+ requested, the call MUST be rejected with an "invalidArguments"
1611+ error.
1612+1613+ The response has the following arguments:
1614+1615+ o accountId: "Id"
1616+1617+ The id of the account used for the call.
1618+1619+1620+1621+1622+1623+1624+1625+1626+Jenkins & Newman Standards Track [Page 29]
1627+1628+RFC 8620 JMAP July 2019
1629+1630+1631+ o state: "String"
1632+1633+ A (preferably short) string representing the state on the server
1634+ for *all* the data of this type in the account (not just the
1635+ objects returned in this call). If the data changes, this string
1636+ MUST change. If the Foo data is unchanged, servers SHOULD return
1637+ the same state string on subsequent requests for this data type.
1638+ When a client receives a response with a different state string to
1639+ a previous call, it MUST either throw away all currently cached
1640+ objects for the type or call "Foo/changes" to get the exact
1641+ changes.
1642+1643+ o list: "Foo[]"
1644+1645+ An array of the Foo objects requested. This is the *empty array*
1646+ if no objects were found or if the "ids" argument passed in was
1647+ also an empty array. The results MAY be in a different order to
1648+ the "ids" in the request arguments. If an identical id is
1649+ included more than once in the request, the server MUST only
1650+ include it once in either the "list" or the "notFound" argument of
1651+ the response.
1652+1653+ o notFound: "Id[]"
1654+1655+ This array contains the ids passed to the method for records that
1656+ do not exist. The array is empty if all requested ids were found
1657+ or if the "ids" argument passed in was either null or an empty
1658+ array.
1659+1660+ The following additional error may be returned instead of the "Foo/
1661+ get" response:
1662+1663+ "requestTooLarge": The number of ids requested by the client exceeds
1664+ the maximum number the server is willing to process in a single
1665+ method call.
1666+1667+5.2. /changes
1668+1669+ When the state of the set of Foo records in an account changes on the
1670+ server (whether due to creation, updates, or deletion), the "state"
1671+ property of the "Foo/get" response will change. The "Foo/changes"
1672+ method allows a client to efficiently update the state of its Foo
1673+ cache to match the new state on the server. It takes the following
1674+ arguments:
1675+1676+ o accountId: "Id"
1677+1678+ The id of the account to use.
1679+1680+1681+1682+Jenkins & Newman Standards Track [Page 30]
1683+1684+RFC 8620 JMAP July 2019
1685+1686+1687+ o sinceState: "String"
1688+1689+ The current state of the client. This is the string that was
1690+ returned as the "state" argument in the "Foo/get" response. The
1691+ server will return the changes that have occurred since this
1692+ state.
1693+1694+ o maxChanges: "UnsignedInt|null"
1695+1696+ The maximum number of ids to return in the response. The server
1697+ MAY choose to return fewer than this value but MUST NOT return
1698+ more. If not given by the client, the server may choose how many
1699+ to return. If supplied by the client, the value MUST be a
1700+ positive integer greater than 0. If a value outside of this range
1701+ is given, the server MUST reject the call with an
1702+ "invalidArguments" error.
1703+1704+ The response has the following arguments:
1705+1706+ o accountId: "Id"
1707+1708+ The id of the account used for the call.
1709+1710+ o oldState: "String"
1711+1712+ This is the "sinceState" argument echoed back; it's the state from
1713+ which the server is returning changes.
1714+1715+ o newState: "String"
1716+1717+ This is the state the client will be in after applying the set of
1718+ changes to the old state.
1719+1720+ o hasMoreChanges: "Boolean"
1721+1722+ If true, the client may call "Foo/changes" again with the
1723+ "newState" returned to get further updates. If false, "newState"
1724+ is the current server state.
1725+1726+ o created: "Id[]"
1727+1728+ An array of ids for records that have been created since the old
1729+ state.
1730+1731+ o updated: "Id[]"
1732+1733+ An array of ids for records that have been updated since the old
1734+ state.
1735+1736+1737+1738+Jenkins & Newman Standards Track [Page 31]
1739+1740+RFC 8620 JMAP July 2019
1741+1742+1743+ o destroyed: "Id[]"
1744+1745+ An array of ids for records that have been destroyed since the old
1746+ state.
1747+1748+ If a record has been created AND updated since the old state, the
1749+ server SHOULD just return the id in the "created" list but MAY return
1750+ it in the "updated" list as well.
1751+1752+ If a record has been updated AND destroyed since the old state, the
1753+ server SHOULD just return the id in the "destroyed" list but MAY
1754+ return it in the "updated" list as well.
1755+1756+ If a record has been created AND destroyed since the old state, the
1757+ server SHOULD remove the id from the response entirely. However, it
1758+ MAY include it in just the "destroyed" list or in both the
1759+ "destroyed" and "created" lists.
1760+1761+ If a "maxChanges" is supplied, or set automatically by the server,
1762+ the server MUST ensure the number of ids returned across "created",
1763+ "updated", and "destroyed" does not exceed this limit. If there are
1764+ more changes than this between the client's state and the current
1765+ server state, the server SHOULD generate an update to take the client
1766+ to an intermediate state, from which the client can continue to call
1767+ "Foo/changes" until it is fully up to date. If it is unable to
1768+ calculate an intermediate state, it MUST return a
1769+ "cannotCalculateChanges" error response instead.
1770+1771+ When generating intermediate states, the server may choose how to
1772+ divide up the changes. For many types, it will provide a better user
1773+ experience to return the more recent changes first, as this is more
1774+ likely to be what the user is most interested in. The client can
1775+ then continue to page in the older changes while the user is viewing
1776+ the newer data. For example, suppose a server went through the
1777+ following states:
1778+1779+ A -> B -> C -> D -> E
1780+1781+ And a client asks for changes from state "B". The server might first
1782+ get the ids of records created, updated, or destroyed between states
1783+ D and E, returning them with:
1784+1785+ state: "B-D-E"
1786+ hasMoreChanges: true
1787+1788+1789+1790+1791+1792+1793+1794+Jenkins & Newman Standards Track [Page 32]
1795+1796+RFC 8620 JMAP July 2019
1797+1798+1799+ The client will then ask for the change from state "B-D-E", and the
1800+ server can return the changes between states C and D, returning:
1801+1802+ state: "B-C-E"
1803+ hasMoreChanges: true
1804+1805+ Finally, the client will request the changes from "B-C-E", and the
1806+ server can return the changes between states B and C, returning:
1807+1808+ state: "E"
1809+ hasMoreChanges: false
1810+1811+ Should the state on the server be modified in the middle of all this
1812+ (to "F"), the server still does the same, but now when the update to
1813+ state "E" is returned, it would indicate that it still has more
1814+ changes for the client to fetch.
1815+1816+ Where multiple changes to a record are split across different
1817+ intermediate states, the server MUST NOT return a record as created
1818+ after a response that deems it as updated or destroyed, and it MUST
1819+ NOT return a record as destroyed before a response that deems it as
1820+ created or updated. The server may have to coalesce multiple changes
1821+ to a record to satisfy this requirement.
1822+1823+ The following additional errors may be returned instead of the "Foo/
1824+ changes" response:
1825+1826+ "cannotCalculateChanges": The server cannot calculate the changes
1827+ from the state string given by the client. Usually, this is due to
1828+ the client's state being too old or the server being unable to
1829+ produce an update to an intermediate state when there are too many
1830+ updates. The client MUST invalidate its Foo cache.
1831+1832+ Maintaining state to allow calculation of "Foo/changes" can be
1833+ expensive for the server, but always returning
1834+ "cannotCalculateChanges" severely increases network traffic and
1835+ resource usage for the client. To allow efficient sync, servers
1836+ SHOULD be able to calculate changes from any state string that was
1837+ given to a client within the last 30 days (but of course may support
1838+ calculating updates from states older than this).
1839+1840+1841+1842+1843+1844+1845+1846+1847+1848+1849+1850+Jenkins & Newman Standards Track [Page 33]
1851+1852+RFC 8620 JMAP July 2019
1853+1854+1855+5.3. /set
1856+1857+ Modifying the state of Foo objects on the server is done via the
1858+ "Foo/set" method. This encompasses creating, updating, and
1859+ destroying Foo records. This allows the server to sort out ordering
1860+ and dependencies that may exist if doing multiple operations at once
1861+ (for example, to ensure there is always a minimum number of a certain
1862+ record type).
1863+1864+ The "Foo/set" method takes the following arguments:
1865+1866+ o accountId: "Id"
1867+1868+ The id of the account to use.
1869+1870+ o ifInState: "String|null"
1871+1872+ This is a state string as returned by the "Foo/get" method
1873+ (representing the state of all objects of this type in the
1874+ account). If supplied, the string must match the current state;
1875+ otherwise, the method will be aborted and a "stateMismatch" error
1876+ returned. If null, any changes will be applied to the current
1877+ state.
1878+1879+ o create: "Id[Foo]|null"
1880+1881+ A map of a *creation id* (a temporary id set by the client) to Foo
1882+ objects, or null if no objects are to be created.
1883+1884+ The Foo object type definition may define default values for
1885+ properties. Any such property may be omitted by the client.
1886+1887+ The client MUST omit any properties that may only be set by the
1888+ server (for example, the "id" property on most object types).
1889+1890+ o update: "Id[PatchObject]|null"
1891+1892+ A map of an id to a Patch object to apply to the current Foo
1893+ object with that id, or null if no objects are to be updated.
1894+1895+ A *PatchObject* is of type "String[*]" and represents an unordered
1896+ set of patches. The keys are a path in JSON Pointer format
1897+ [RFC6901], with an implicit leading "/" (i.e., prefix each key
1898+ with "/" before applying the JSON Pointer evaluation algorithm).
1899+1900+ All paths MUST also conform to the following restrictions; if
1901+ there is any violation, the update MUST be rejected with an
1902+ "invalidPatch" error:
1903+1904+1905+1906+Jenkins & Newman Standards Track [Page 34]
1907+1908+RFC 8620 JMAP July 2019
1909+1910+1911+ * The pointer MUST NOT reference inside an array (i.e., you MUST
1912+ NOT insert/delete from an array; the array MUST be replaced in
1913+ its entirety instead).
1914+1915+ * All parts prior to the last (i.e., the value after the final
1916+ slash) MUST already exist on the object being patched.
1917+1918+ * There MUST NOT be two patches in the PatchObject where the
1919+ pointer of one is the prefix of the pointer of the other, e.g.,
1920+ "alerts/1/offset" and "alerts".
1921+1922+ The value associated with each pointer determines how to apply
1923+ that patch:
1924+1925+ * If null, set to the default value if specified for this
1926+ property; otherwise, remove the property from the patched
1927+ object. If the key is not present in the parent, this a no-op.
1928+1929+ * Anything else: The value to set for this property (this may be
1930+ a replacement or addition to the object being patched).
1931+1932+ Any server-set properties MAY be included in the patch if their
1933+ value is identical to the current server value (before applying
1934+ the patches to the object). Otherwise, the update MUST be
1935+ rejected with an "invalidProperties" SetError.
1936+1937+ This patch definition is designed such that an entire Foo object
1938+ is also a valid PatchObject. The client may choose to optimise
1939+ network usage by just sending the diff or may send the whole
1940+ object; the server processes it the same either way.
1941+1942+ o destroy: "Id[]|null"
1943+1944+ A list of ids for Foo objects to permanently delete, or null if no
1945+ objects are to be destroyed.
1946+1947+ Each creation, modification, or destruction of an object is
1948+ considered an atomic unit. It is permissible for the server to
1949+ commit changes to some objects but not others; however, it MUST NOT
1950+ only commit part of an update to a single record (e.g., update a
1951+ "name" property but not a "count" property, if both are supplied in
1952+ the update object).
1953+1954+ The final state MUST be valid after the "Foo/set" is finished;
1955+ however, the server may have to transition through invalid
1956+ intermediate states (not exposed to the client) while processing the
1957+ individual create/update/destroy requests. For example, suppose
1958+ there is a "name" property that must be unique. A single method call
1959+1960+1961+1962+Jenkins & Newman Standards Track [Page 35]
1963+1964+RFC 8620 JMAP July 2019
1965+1966+1967+ could rename an object A => B and simultaneously rename another
1968+ object B => A. If the final state is valid, this is allowed.
1969+ Otherwise, each creation, modification, or destruction of an object
1970+ should be processed sequentially and accepted/rejected based on the
1971+ current server state.
1972+1973+ If a create, update, or destroy is rejected, the appropriate error
1974+ MUST be added to the notCreated/notUpdated/notDestroyed property of
1975+ the response, and the server MUST continue to the next create/update/
1976+ destroy. It does not terminate the method.
1977+1978+ If an id given cannot be found, the update or destroy MUST be
1979+ rejected with a "notFound" set error.
1980+1981+ The server MAY skip an update (rejecting it with a "willDestroy"
1982+ SetError) if that object is destroyed in the same /set request.
1983+1984+ Some records may hold references to other records (foreign keys).
1985+ That reference may be set (via create or update) in the same request
1986+ as the referenced record is created. To do this, the client refers
1987+ to the new record using its creation id prefixed with a "#". The
1988+ order of the method calls in the request by the client MUST be such
1989+ that the record being referenced is created in the same or an earlier
1990+ call. Thus, the server never has to look ahead. Instead, while
1991+ processing a request, the server MUST keep a simple map for the
1992+ duration of the request of creation id to record id for each newly
1993+ created record, so it can substitute in the correct value if
1994+ necessary in later method calls. In the case of records with
1995+ references to the same type, the server MUST order the creates and
1996+ updates within a single method call so that creates happen before
1997+ their creation ids are referenced by another create/update/destroy in
1998+ the same call.
1999+2000+ Creation ids are not scoped by type but are a single map for all
2001+ types. A client SHOULD NOT reuse a creation id anywhere in the same
2002+ API request. If a creation id is reused, the server MUST map the
2003+ creation id to the most recently created item with that id. To allow
2004+ easy proxying of API requests, an initial set of creation id to real
2005+ id values may be passed with a request (see "The Request Object",
2006+ Section 3.3) and the final state of the map passed out with the
2007+ response (see "The Response Object", Section 3.4).
2008+2009+ The response has the following arguments:
2010+2011+ o accountId: "Id"
2012+2013+ The id of the account used for the call.
2014+2015+2016+2017+2018+Jenkins & Newman Standards Track [Page 36]
2019+2020+RFC 8620 JMAP July 2019
2021+2022+2023+ o oldState: "String|null"
2024+2025+ The state string that would have been returned by "Foo/get" before
2026+ making the requested changes, or null if the server doesn't know
2027+ what the previous state string was.
2028+2029+ o newState: "String"
2030+2031+ The state string that will now be returned by "Foo/get".
2032+2033+ o created: "Id[Foo]|null"
2034+2035+ A map of the creation id to an object containing any properties of
2036+ the created Foo object that were not sent by the client. This
2037+ includes all server-set properties (such as the "id" in most
2038+ object types) and any properties that were omitted by the client
2039+ and thus set to a default by the server.
2040+2041+ This argument is null if no Foo objects were successfully created.
2042+2043+ o updated: "Id[Foo|null]|null"
2044+2045+ The keys in this map are the ids of all Foos that were
2046+ successfully updated.
2047+2048+ The value for each id is a Foo object containing any property that
2049+ changed in a way *not* explicitly requested by the PatchObject
2050+ sent to the server, or null if none. This lets the client know of
2051+ any changes to server-set or computed properties.
2052+2053+ This argument is null if no Foo objects were successfully updated.
2054+2055+ o destroyed: "Id[]|null"
2056+2057+ A list of Foo ids for records that were successfully destroyed, or
2058+ null if none.
2059+2060+ o notCreated: "Id[SetError]|null"
2061+2062+ A map of the creation id to a SetError object for each record that
2063+ failed to be created, or null if all successful.
2064+2065+ o notUpdated: "Id[SetError]|null"
2066+2067+ A map of the Foo id to a SetError object for each record that
2068+ failed to be updated, or null if all successful.
2069+2070+2071+2072+2073+2074+Jenkins & Newman Standards Track [Page 37]
2075+2076+RFC 8620 JMAP July 2019
2077+2078+2079+ o notDestroyed: "Id[SetError]|null"
2080+2081+ A map of the Foo id to a SetError object for each record that
2082+ failed to be destroyed, or null if all successful.
2083+2084+ A *SetError* object has the following properties:
2085+2086+ o type: "String"
2087+2088+ The type of error.
2089+2090+ o description: "String|null"
2091+2092+ A description of the error to help with debugging that includes an
2093+ explanation of what the problem was. This is a non-localised
2094+ string and is not intended to be shown directly to end users.
2095+2096+ The following SetError types are defined and may be returned for set
2097+ operations on any record type where appropriate:
2098+2099+ o "forbidden": (create; update; destroy). The create/update/destroy
2100+ would violate an ACL or other permissions policy.
2101+2102+ o "overQuota": (create; update). The create would exceed a server-
2103+ defined limit on the number or total size of objects of this type.
2104+2105+ o "tooLarge": (create; update). The create/update would result in
2106+ an object that exceeds a server-defined limit for the maximum size
2107+ of a single object of this type.
2108+2109+ o "rateLimit": (create). Too many objects of this type have been
2110+ created recently, and a server-defined rate limit has been
2111+ reached. It may work if tried again later.
2112+2113+ o "notFound": (update; destroy). The id given to update/destroy
2114+ cannot be found.
2115+2116+ o "invalidPatch": (update). The PatchObject given to update the
2117+ record was not a valid patch (see the patch description).
2118+2119+ o "willDestroy": (update). The client requested that an object be
2120+ both updated and destroyed in the same /set request, and the
2121+ server has decided to therefore ignore the update.
2122+2123+2124+2125+2126+2127+2128+2129+2130+Jenkins & Newman Standards Track [Page 38]
2131+2132+RFC 8620 JMAP July 2019
2133+2134+2135+ o "invalidProperties": (create; update). The record given is
2136+ invalid in some way. For example:
2137+2138+ * It contains properties that are invalid according to the type
2139+ specification of this record type.
2140+2141+ * It contains a property that may only be set by the server
2142+ (e.g., "id") and is different to the current value. Note, to
2143+ allow clients to pass whole objects back, it is not an error to
2144+ include a server-set property in an update as long as the value
2145+ is identical to the current value on the server.
2146+2147+ * There is a reference to another record (foreign key), and the
2148+ given id does not correspond to a valid record.
2149+2150+ The SetError object SHOULD also have a property called
2151+ "properties" of type "String[]" that lists *all* the properties
2152+ that were invalid.
2153+2154+ Individual methods MAY specify more specific errors for certain
2155+ conditions that would otherwise result in an invalidProperties
2156+ error. If the condition of one of these is met, it MUST be
2157+ returned instead of the invalidProperties error.
2158+2159+ o "singleton": (create; destroy). This is a singleton type, so you
2160+ cannot create another one or destroy the existing one.
2161+2162+ Other possible SetError types MAY be given in specific method
2163+ descriptions. Other properties MAY also be present on the SetError
2164+ object, as described in the relevant methods.
2165+2166+ The following additional errors may be returned instead of the "Foo/
2167+ set" response:
2168+2169+ "requestTooLarge": The total number of objects to create, update, or
2170+ destroy exceeds the maximum number the server is willing to process
2171+ in a single method call.
2172+2173+ "stateMismatch": An "ifInState" argument was supplied, and it does
2174+ not match the current state.
2175+2176+2177+2178+2179+2180+2181+2182+2183+2184+2185+2186+Jenkins & Newman Standards Track [Page 39]
2187+2188+RFC 8620 JMAP July 2019
2189+2190+2191+5.4. /copy
2192+2193+ The only way to move Foo records *between* two different accounts is
2194+ to copy them using the "Foo/copy" method; once the copy has
2195+ succeeded, delete the original. The "onSuccessDestroyOriginal"
2196+ argument allows you to try to do this in one method call; however,
2197+ note that the two different actions are not atomic, so it is possible
2198+ for the copy to succeed but the original not to be destroyed for some
2199+ reason.
2200+2201+ The copy is conceptually in three phases:
2202+2203+ 1. Reading the current values from the "from" account.
2204+2205+ 2. Writing the new copies to the other account.
2206+2207+ 3. Destroying the originals in the "from" account, if requested.
2208+2209+ Data may change in between phases due to concurrent requests.
2210+2211+ The "Foo/copy" method takes the following arguments:
2212+2213+ o fromAccountId: "Id"
2214+2215+ The id of the account to copy records from.
2216+2217+ o ifFromInState: "String|null"
2218+2219+ This is a state string as returned by the "Foo/get" method. If
2220+ supplied, the string must match the current state of the account
2221+ referenced by the fromAccountId when reading the data to be
2222+ copied; otherwise, the method will be aborted and a
2223+ "stateMismatch" error returned. If null, the data will be read
2224+ from the current state.
2225+2226+ o accountId: "Id"
2227+2228+ The id of the account to copy records to. This MUST be different
2229+ to the "fromAccountId".
2230+2231+ o ifInState: "String|null"
2232+2233+ This is a state string as returned by the "Foo/get" method. If
2234+ supplied, the string must match the current state of the account
2235+ referenced by the accountId; otherwise, the method will be aborted
2236+ and a "stateMismatch" error returned. If null, any changes will
2237+ be applied to the current state.
2238+2239+2240+2241+2242+Jenkins & Newman Standards Track [Page 40]
2243+2244+RFC 8620 JMAP July 2019
2245+2246+2247+ o create: "Id[Foo]"
2248+2249+ A map of the *creation id* to a Foo object. The Foo object MUST
2250+ contain an "id" property, which is the id (in the fromAccount) of
2251+ the record to be copied. When creating the copy, any other
2252+ properties included are used instead of the current value for that
2253+ property on the original.
2254+2255+ o onSuccessDestroyOriginal: "Boolean" (default: false)
2256+2257+ If true, an attempt will be made to destroy the original records
2258+ that were successfully copied: after emitting the "Foo/copy"
2259+ response, but before processing the next method, the server MUST
2260+ make a single call to "Foo/set" to destroy the original of each
2261+ successfully copied record; the output of this is added to the
2262+ responses as normal, to be returned to the client.
2263+2264+ o destroyFromIfInState: "String|null"
2265+2266+ This argument is passed on as the "ifInState" argument to the
2267+ implicit "Foo/set" call, if made at the end of this request to
2268+ destroy the originals that were successfully copied.
2269+2270+ Each record copy is considered an atomic unit that may succeed or
2271+ fail individually.
2272+2273+ The response has the following arguments:
2274+2275+ o fromAccountId: "Id"
2276+2277+ The id of the account records were copied from.
2278+2279+ o accountId: "Id"
2280+2281+ The id of the account records were copied to.
2282+2283+ o oldState: "String|null"
2284+2285+ The state string that would have been returned by "Foo/get" on the
2286+ account records that were copied to before making the requested
2287+ changes, or null if the server doesn't know what the previous
2288+ state string was.
2289+2290+ o newState: "String"
2291+2292+ The state string that will now be returned by "Foo/get" on the
2293+ account records were copied to.
2294+2295+2296+2297+2298+Jenkins & Newman Standards Track [Page 41]
2299+2300+RFC 8620 JMAP July 2019
2301+2302+2303+ o created: "Id[Foo]|null"
2304+2305+ A map of the creation id to an object containing any properties of
2306+ the copied Foo object that are set by the server (such as the "id"
2307+ in most object types; note, the id is likely to be different to
2308+ the id of the object in the account it was copied from).
2309+2310+ This argument is null if no Foo objects were successfully copied.
2311+2312+ o notCreated: "Id[SetError]|null"
2313+2314+ A map of the creation id to a SetError object for each record that
2315+ failed to be copied, or null if none.
2316+2317+ The SetError may be any of the standard set errors returned for a
2318+ create or update. In addition, the following SetError is defined:
2319+2320+ "alreadyExists": The server forbids duplicates, and the record
2321+ already exists in the target account. An "existingId" property of
2322+ type "Id" MUST be included on the SetError object with the id of the
2323+ existing record.
2324+2325+ The following additional errors may be returned instead of the "Foo/
2326+ copy" response:
2327+2328+ "fromAccountNotFound": The "fromAccountId" does not correspond to a
2329+ valid account.
2330+2331+ "fromAccountNotSupportedByMethod": The "fromAccountId" given
2332+ corresponds to a valid account, but the account does not support this
2333+ data type.
2334+2335+ "stateMismatch": An "ifInState" argument was supplied and it does not
2336+ match the current state, or an "ifFromInState" argument was supplied
2337+ and it does not match the current state in the from account.
2338+2339+5.5. /query
2340+2341+ For data sets where the total amount of data is expected to be very
2342+ small, clients can just fetch the complete set of data and then do
2343+ any sorting/filtering locally. However, for large data sets (e.g.,
2344+ multi-gigabyte mailboxes), the client needs to be able to
2345+ search/sort/window the data type on the server.
2346+2347+ A query on the set of Foos in an account is made by calling "Foo/
2348+ query". This takes a number of arguments to determine which records
2349+ to include, how they should be sorted, and which part of the result
2350+2351+2352+2353+2354+Jenkins & Newman Standards Track [Page 42]
2355+2356+RFC 8620 JMAP July 2019
2357+2358+2359+ should be returned (the full list may be *very* long). The result is
2360+ returned as a list of Foo ids.
2361+2362+ A call to "Foo/query" takes the following arguments:
2363+2364+ o accountId: "Id"
2365+2366+ The id of the account to use.
2367+2368+ o filter: "FilterOperator|FilterCondition|null"
2369+2370+ Determines the set of Foos returned in the results. If null, all
2371+ objects in the account of this type are included in the results.
2372+ A *FilterOperator* object has the following properties:
2373+2374+ * operator: "String"
2375+2376+ This MUST be one of the following strings:
2377+2378+ + "AND": All of the conditions must match for the filter to
2379+ match.
2380+2381+ + "OR": At least one of the conditions must match for the
2382+ filter to match.
2383+2384+ + "NOT": None of the conditions must match for the filter to
2385+ match.
2386+2387+ * conditions: "(FilterOperator|FilterCondition)[]"
2388+2389+ The conditions to evaluate against each record.
2390+2391+ A *FilterCondition* is an "object" whose allowed properties and
2392+ semantics depend on the data type and is defined in the /query
2393+ method specification for that type. It MUST NOT have an
2394+ "operator" property.
2395+2396+ o sort: "Comparator[]|null"
2397+2398+ Lists the names of properties to compare between two Foo records,
2399+ and how to compare them, to determine which comes first in the
2400+ sort. If two Foo records have an identical value for the first
2401+ comparator, the next comparator will be considered, and so on. If
2402+ all comparators are the same (this includes the case where an
2403+ empty array or null is given as the "sort" argument), the sort
2404+ order is server dependent, but it MUST be stable between calls to
2405+ "Foo/query". A *Comparator* has the following properties:
2406+2407+2408+2409+2410+Jenkins & Newman Standards Track [Page 43]
2411+2412+RFC 8620 JMAP July 2019
2413+2414+2415+ * property: "String"
2416+2417+ The name of the property on the Foo objects to compare.
2418+2419+ * isAscending: "Boolean" (optional; default: true)
2420+2421+ If true, sort in ascending order. If false, reverse the
2422+ comparator's results to sort in descending order.
2423+2424+ * collation: "String" (optional; default is server-dependent)
2425+2426+ The identifier, as registered in the collation registry defined
2427+ in [RFC4790], for the algorithm to use when comparing the order
2428+ of strings. The algorithms the server supports are advertised
2429+ in the capabilities object returned with the Session object
2430+ (see Section 2).
2431+2432+ If omitted, the default algorithm is server dependent, but:
2433+2434+ 1. It MUST be unicode-aware.
2435+2436+ 2. It MAY be selected based on an Accept-Language header in
2437+ the request (as defined in [RFC7231], Section 5.3.5) or
2438+ out-of-band information about the user's language/locale.
2439+2440+ 3. It SHOULD be case insensitive where such a concept makes
2441+ sense for a language/locale. Where the user's language is
2442+ unknown, it is RECOMMENDED to follow the advice in
2443+ Section 5.2.3 of [RFC8264].
2444+2445+ The "i;unicode-casemap" collation [RFC5051] and the Unicode
2446+ Collation Algorithm (<http://www.unicode.org/reports/tr10/>)
2447+ are two examples that fulfil these criterion and provide
2448+ reasonable behaviour for a large number of languages.
2449+2450+ When the property being compared is not a string, the
2451+ "collation" property is ignored, and the following comparison
2452+ rules apply based on the type. In ascending order:
2453+2454+ + "Boolean": false comes before true.
2455+2456+ + "Number": A lower number comes before a higher number.
2457+2458+ + "Date"/"UTCDate": The earlier date comes first.
2459+2460+ The Comparator object may also have additional properties as
2461+ required for specific sort operations defined in a type's /query
2462+ method.
2463+2464+2465+2466+Jenkins & Newman Standards Track [Page 44]
2467+2468+RFC 8620 JMAP July 2019
2469+2470+2471+ o position: "Int" (default: 0)
2472+2473+ The zero-based index of the first id in the full list of results
2474+ to return.
2475+2476+ If a negative value is given, it is an offset from the end of the
2477+ list. Specifically, the negative value MUST be added to the total
2478+ number of results given the filter, and if still negative, it's
2479+ clamped to "0". This is now the zero-based index of the first id
2480+ to return.
2481+2482+ If the index is greater than or equal to the total number of
2483+ objects in the results list, then the "ids" array in the response
2484+ will be empty, but this is not an error.
2485+2486+ o anchor: "Id|null"
2487+2488+ A Foo id. If supplied, the "position" argument is ignored. The
2489+ index of this id in the results will be used in combination with
2490+ the "anchorOffset" argument to determine the index of the first
2491+ result to return (see below for more details).
2492+2493+ o anchorOffset: "Int" (default: 0)
2494+2495+ The index of the first result to return relative to the index of
2496+ the anchor, if an anchor is given. This MAY be negative. For
2497+ example, "-1" means the Foo immediately preceding the anchor is
2498+ the first result in the list returned (see below for more
2499+ details).
2500+2501+ o limit: "UnsignedInt|null"
2502+2503+ The maximum number of results to return. If null, no limit
2504+ presumed. The server MAY choose to enforce a maximum "limit"
2505+ argument. In this case, if a greater value is given (or if it is
2506+ null), the limit is clamped to the maximum; the new limit is
2507+ returned with the response so the client is aware. If a negative
2508+ value is given, the call MUST be rejected with an
2509+ "invalidArguments" error.
2510+2511+ o calculateTotal: "Boolean" (default: false)
2512+2513+ Does the client wish to know the total number of results in the
2514+ query? This may be slow and expensive for servers to calculate,
2515+ particularly with complex filters, so clients should take care to
2516+ only request the total when needed.
2517+2518+2519+2520+2521+2522+Jenkins & Newman Standards Track [Page 45]
2523+2524+RFC 8620 JMAP July 2019
2525+2526+2527+ If an "anchor" argument is given, the anchor is looked for in the
2528+ results after filtering and sorting. If found, the "anchorOffset" is
2529+ then added to its index. If the resulting index is now negative, it
2530+ is clamped to 0. This index is now used exactly as though it were
2531+ supplied as the "position" argument. If the anchor is not found, the
2532+ call is rejected with an "anchorNotFound" error.
2533+2534+ If an "anchor" is specified, any position argument supplied by the
2535+ client MUST be ignored. If no "anchor" is supplied, any
2536+ "anchorOffset" argument MUST be ignored.
2537+2538+ A client can use "anchor" instead of "position" to find the index of
2539+ an id within a large set of results.
2540+2541+ The response has the following arguments:
2542+2543+ o accountId: "Id"
2544+2545+ The id of the account used for the call.
2546+2547+ o queryState: "String"
2548+2549+ A string encoding the current state of the query on the server.
2550+ This string MUST change if the results of the query (i.e., the
2551+ matching ids and their sort order) have changed. The queryState
2552+ string MAY change if something has changed on the server, which
2553+ means the results may have changed but the server doesn't know for
2554+ sure.
2555+2556+ The queryState string only represents the ordered list of ids that
2557+ match the particular query (including its sort/filter). There is
2558+ no requirement for it to change if a property on an object
2559+ matching the query changes but the query results are unaffected
2560+ (indeed, it is more efficient if the queryState string does not
2561+ change in this case). The queryState string only has meaning when
2562+ compared to future responses to a query with the same type/sort/
2563+ filter or when used with /queryChanges to fetch changes.
2564+2565+ Should a client receive back a response with a different
2566+ queryState string to a previous call, it MUST either throw away
2567+ the currently cached query and fetch it again (note, this does not
2568+ require fetching the records again, just the list of ids) or call
2569+ "Foo/queryChanges" to get the difference.
2570+2571+2572+2573+2574+2575+2576+2577+2578+Jenkins & Newman Standards Track [Page 46]
2579+2580+RFC 8620 JMAP July 2019
2581+2582+2583+ o canCalculateChanges: "Boolean"
2584+2585+ This is true if the server supports calling "Foo/queryChanges"
2586+ with these "filter"/"sort" parameters. Note, this does not
2587+ guarantee that the "Foo/queryChanges" call will succeed, as it may
2588+ only be possible for a limited time afterwards due to server
2589+ internal implementation details.
2590+2591+ o position: "UnsignedInt"
2592+2593+ The zero-based index of the first result in the "ids" array within
2594+ the complete list of query results.
2595+2596+ o ids: "Id[]"
2597+2598+ The list of ids for each Foo in the query results, starting at the
2599+ index given by the "position" argument of this response and
2600+ continuing until it hits the end of the results or reaches the
2601+ "limit" number of ids. If "position" is >= "total", this MUST be
2602+ the empty list.
2603+2604+ o total: "UnsignedInt" (only if requested)
2605+2606+ The total number of Foos in the results (given the "filter").
2607+ This argument MUST be omitted if the "calculateTotal" request
2608+ argument is not true.
2609+2610+ o limit: "UnsignedInt" (if set by the server)
2611+2612+ The limit enforced by the server on the maximum number of results
2613+ to return. This is only returned if the server set a limit or
2614+ used a different limit than that given in the request.
2615+2616+ The following additional errors may be returned instead of the "Foo/
2617+ query" response:
2618+2619+ "anchorNotFound": An anchor argument was supplied, but it cannot be
2620+ found in the results of the query.
2621+2622+ "unsupportedSort": The "sort" is syntactically valid, but it includes
2623+ a property the server does not support sorting on or a collation
2624+ method it does not recognise.
2625+2626+ "unsupportedFilter": The "filter" is syntactically valid, but the
2627+ server cannot process it. If the filter was the result of a user's
2628+ search input, the client SHOULD suggest that the user simplify their
2629+ search.
2630+2631+2632+2633+2634+Jenkins & Newman Standards Track [Page 47]
2635+2636+RFC 8620 JMAP July 2019
2637+2638+2639+5.6. /queryChanges
2640+2641+ The "Foo/queryChanges" method allows a client to efficiently update
2642+ the state of a cached query to match the new state on the server. It
2643+ takes the following arguments:
2644+2645+ o accountId: "Id"
2646+2647+ The id of the account to use.
2648+2649+ o filter: "FilterOperator|FilterCondition|null"
2650+2651+ The filter argument that was used with "Foo/query".
2652+2653+ o sort: "Comparator[]|null"
2654+2655+ The sort argument that was used with "Foo/query".
2656+2657+ o sinceQueryState: "String"
2658+2659+ The current state of the query in the client. This is the string
2660+ that was returned as the "queryState" argument in the "Foo/query"
2661+ response with the same sort/filter. The server will return the
2662+ changes made to the query since this state.
2663+2664+ o maxChanges: "UnsignedInt|null"
2665+2666+ The maximum number of changes to return in the response. See
2667+ error descriptions below for more details.
2668+2669+ o upToId: "Id|null"
2670+2671+ The last (highest-index) id the client currently has cached from
2672+ the query results. When there are a large number of results, in a
2673+ common case, the client may have only downloaded and cached a
2674+ small subset from the beginning of the results. If the sort and
2675+ filter are both only on immutable properties, this allows the
2676+ server to omit changes after this point in the results, which can
2677+ significantly increase efficiency. If they are not immutable,
2678+ this argument is ignored.
2679+2680+ o calculateTotal: "Boolean" (default: false)
2681+2682+ Does the client wish to know the total number of results now in
2683+ the query? This may be slow and expensive for servers to
2684+ calculate, particularly with complex filters, so clients should
2685+ take care to only request the total when needed.
2686+2687+2688+2689+2690+Jenkins & Newman Standards Track [Page 48]
2691+2692+RFC 8620 JMAP July 2019
2693+2694+2695+ The response has the following arguments:
2696+2697+ o accountId: "Id"
2698+2699+ The id of the account used for the call.
2700+2701+ o oldQueryState: "String"
2702+2703+ This is the "sinceQueryState" argument echoed back; that is, the
2704+ state from which the server is returning changes.
2705+2706+ o newQueryState: "String"
2707+2708+ This is the state the query will be in after applying the set of
2709+ changes to the old state.
2710+2711+ o total: "UnsignedInt" (only if requested)
2712+2713+ The total number of Foos in the results (given the "filter").
2714+ This argument MUST be omitted if the "calculateTotal" request
2715+ argument is not true.
2716+2717+ o removed: "Id[]"
2718+2719+ The "id" for every Foo that was in the query results in the old
2720+ state and that is not in the results in the new state.
2721+2722+ If the server cannot calculate this exactly, the server MAY return
2723+ the ids of extra Foos in addition that may have been in the old
2724+ results but are not in the new results.
2725+2726+ If the sort and filter are both only on immutable properties and
2727+ an "upToId" is supplied and exists in the results, any ids that
2728+ were removed but have a higher index than "upToId" SHOULD be
2729+ omitted.
2730+2731+ If the "filter" or "sort" includes a mutable property, the server
2732+ MUST include all Foos in the current results for which this
2733+ property may have changed. The position of these may have moved
2734+ in the results, so they must be reinserted by the client to ensure
2735+ its query cache is correct.
2736+2737+2738+2739+2740+2741+2742+2743+2744+2745+2746+Jenkins & Newman Standards Track [Page 49]
2747+2748+RFC 8620 JMAP July 2019
2749+2750+2751+ o added: "AddedItem[]"
2752+2753+ The id and index in the query results (in the new state) for every
2754+ Foo that has been added to the results since the old state AND
2755+ every Foo in the current results that was included in the
2756+ "removed" array (due to a filter or sort based upon a mutable
2757+ property).
2758+2759+ If the sort and filter are both only on immutable properties and
2760+ an "upToId" is supplied and exists in the results, any ids that
2761+ were added but have a higher index than "upToId" SHOULD be
2762+ omitted.
2763+2764+ The array MUST be sorted in order of index, with the lowest index
2765+ first.
2766+2767+ An *AddedItem* object has the following properties:
2768+2769+ * id: "Id"
2770+2771+ * index: "UnsignedInt"
2772+2773+ The result of this is that if the client has a cached sparse array of
2774+ Foo ids corresponding to the results in the old state, then:
2775+2776+ fooIds = [ "id1", "id2", null, null, "id3", "id4", null, null, null ]
2777+2778+ If it *splices out* all ids in the removed array that it has in its
2779+ cached results, then:
2780+2781+ removed = [ "id2", "id31", ... ];
2782+ fooIds => [ "id1", null, null, "id3", "id4", null, null, null ]
2783+2784+ and *splices in* (one by one in order, starting with the lowest
2785+ index) all of the ids in the added array:
2786+2787+ added = [{ id: "id5", index: 0, ... }];
2788+ fooIds => [ "id5", "id1", null, null, "id3", "id4", null, null, null ]
2789+2790+ and *truncates* or *extends* to the new total length, then the
2791+ results will now be in the new state.
2792+2793+ Note: splicing in adds the item at the given index, incrementing the
2794+ index of all items previously at that or a higher index. Splicing
2795+ out is the inverse, removing the item and decrementing the index of
2796+ every item after it in the array.
2797+2798+2799+2800+2801+2802+Jenkins & Newman Standards Track [Page 50]
2803+2804+RFC 8620 JMAP July 2019
2805+2806+2807+ The following additional errors may be returned instead of the "Foo/
2808+ queryChanges" response:
2809+2810+ "tooManyChanges": There are more changes than the client's
2811+ "maxChanges" argument. Each item in the removed or added array is
2812+ considered to be one change. The client may retry with higher max
2813+ changes or invalidate its cache of the query results.
2814+2815+ "cannotCalculateChanges": The server cannot calculate the changes
2816+ from the queryState string given by the client, usually due to the
2817+ client's state being too old. The client MUST invalidate its cache
2818+ of the query results.
2819+2820+5.7. Examples
2821+2822+ Suppose we have a type *Todo* with the following properties:
2823+2824+ o id: "Id" (immutable; server-set)
2825+2826+ The id of the object.
2827+2828+ o title: "String"
2829+2830+ A brief summary of what is to be done.
2831+2832+ o keywords: "String[Boolean]" (default: {})
2833+2834+ A set of keywords that apply to the Todo. The set is represented
2835+ as an object, with the keys being the "keywords". The value for
2836+ each key in the object MUST be true. (This format allows you to
2837+ update an individual key using patch syntax rather than having to
2838+ update the whole set of keywords as one, which a "String[]"
2839+ representation would require.)
2840+2841+ o neuralNetworkTimeEstimation: "Number" (server-set)
2842+2843+ The title and keywords are fed into the server's state-of-the-art
2844+ neural network to get an estimation of how long this Todo will
2845+ take, in seconds.
2846+2847+ o subTodoIds: "Id[]|null"
2848+2849+ The ids of a list of other Todos to complete as part of this Todo.
2850+2851+ Suppose also that all the standard methods are defined for this type
2852+ and the FilterCondition object supports a "hasKeyword" property to
2853+ match Todos with the given keyword.
2854+2855+2856+2857+2858+Jenkins & Newman Standards Track [Page 51]
2859+2860+RFC 8620 JMAP July 2019
2861+2862+2863+ A client might want to display the list of Todos with either a
2864+ "music" keyword or a "video" keyword, so it makes the following
2865+ method call:
2866+2867+ [[ "Todo/query", {
2868+ "accountId": "x",
2869+ "filter": {
2870+ "operator": "OR",
2871+ "conditions": [
2872+ { "hasKeyword": "music" },
2873+ { "hasKeyword": "video" }
2874+ ]
2875+ },
2876+ "sort": [{ "property": "title" }],
2877+ "position": 0,
2878+ "limit": 10
2879+ }, "0" ],
2880+ [ "Todo/get", {
2881+ "accountId": "x",
2882+ "#ids": {
2883+ "resultOf": "0",
2884+ "name": "Todo/query",
2885+ "path": "/ids"
2886+ }
2887+ }, "1" ]]
2888+2889+2890+2891+2892+2893+2894+2895+2896+2897+2898+2899+2900+2901+2902+2903+2904+2905+2906+2907+2908+2909+2910+2911+2912+2913+2914+Jenkins & Newman Standards Track [Page 52]
2915+2916+RFC 8620 JMAP July 2019
2917+2918+2919+ This would query the server for the set of Todos with a keyword of
2920+ either "music" or "video", sorted by title, and limited to the first
2921+ 10 results. It fetches the full object for each of these Todos using
2922+ back-references to reference the result of the query. The response
2923+ might look something like:
2924+2925+ [[ "Todo/query", {
2926+ "accountId": "x",
2927+ "queryState": "y13213",
2928+ "canCalculateChanges": true,
2929+ "position": 0,
2930+ "ids": [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ]
2931+ }, "0" ],
2932+ [ "Todo/get", {
2933+ "accountId": "x",
2934+ "state": "10324",
2935+ "list": [{
2936+ "id": "a",
2937+ "title": "Practise Piano",
2938+ "keywords": {
2939+ "music": true,
2940+ "beethoven": true,
2941+ "mozart": true,
2942+ "liszt": true,
2943+ "rachmaninov": true
2944+ },
2945+ "neuralNetworkTimeEstimation": 3600
2946+ }, {
2947+ "id": "b",
2948+ "title": "Watch Daft Punk music video",
2949+ "keywords": {
2950+ "music": true,
2951+ "video": true,
2952+ "trance": true
2953+ },
2954+ "neuralNetworkTimeEstimation": 18000
2955+ },
2956+ ...
2957+ ]
2958+ }, "1" ]]
2959+2960+2961+2962+2963+2964+2965+2966+2967+2968+2969+2970+Jenkins & Newman Standards Track [Page 53]
2971+2972+RFC 8620 JMAP July 2019
2973+2974+2975+ Now, suppose the user adds a keyword "chopin" and removes the keyword
2976+ "mozart" from the "Practise Piano" task. The client may send the
2977+ whole object to the server, as this is a valid PatchObject:
2978+2979+ [[ "Todo/set", {
2980+ "accountId": "x",
2981+ "ifInState": "10324",
2982+ "update": {
2983+ "a": {
2984+ "id": "a",
2985+ "title": "Practise Piano",
2986+ "keywords": {
2987+ "music": true,
2988+ "beethoven": true,
2989+ "chopin": true,
2990+ "liszt": true,
2991+ "rachmaninov": true
2992+ },
2993+ "neuralNetworkTimeEstimation": 360
2994+ }
2995+ }
2996+ }, "0" ]]
2997+2998+ or it may send a minimal patch:
2999+3000+ [[ "Todo/set", {
3001+ "accountId": "x",
3002+ "ifInState": "10324",
3003+ "update": {
3004+ "a": {
3005+ "keywords/chopin": true,
3006+ "keywords/mozart": null
3007+ }
3008+ }
3009+ }, "0" ]]
3010+3011+3012+3013+3014+3015+3016+3017+3018+3019+3020+3021+3022+3023+3024+3025+3026+Jenkins & Newman Standards Track [Page 54]
3027+3028+RFC 8620 JMAP July 2019
3029+3030+3031+ The effect is exactly the same on the server in either case, and
3032+ presuming the server is still in state "10324", it will probably
3033+ return success:
3034+3035+ [[ "Todo/set", {
3036+ "accountId": "x",
3037+ "oldState": "10324",
3038+ "newState": "10329",
3039+ "updated": {
3040+ "a": {
3041+ "neuralNetworkTimeEstimation": 5400
3042+ }
3043+ }
3044+ }, "0" ]]
3045+3046+ The server changed the "neuralNetworkTimeEstimation" property on the
3047+ object as part of this change; as this changed in a way *not*
3048+ explicitly requested by the PatchObject sent to the server, it is
3049+ returned with the "updated" confirmation.
3050+3051+ Let us now add a sub-Todo to our new "Practise Piano" Todo. In this
3052+ example, we can see the use of a reference to a creation id to allow
3053+ us to set a foreign key reference to a record created in the same
3054+ request:
3055+3056+ [[ "Todo/set", {
3057+ "accountId": "x",
3058+ "create": {
3059+ "k15": {
3060+ "title": "Warm up with scales"
3061+ }
3062+ },
3063+ "update": {
3064+ "a": {
3065+ "subTodoIds": [ "#k15" ]
3066+ }
3067+ }
3068+ }, "0" ]]
3069+3070+3071+3072+3073+3074+3075+3076+3077+3078+3079+3080+3081+3082+Jenkins & Newman Standards Track [Page 55]
3083+3084+RFC 8620 JMAP July 2019
3085+3086+3087+ Now, suppose another user deleted the "Listen to Daft Punk" Todo.
3088+ The first user will receive a push notification (see Section 7) with
3089+ the changed state string for the "Todo" type. Since the new string
3090+ does not match its current state, it knows it needs to check for
3091+ updates. It may make a request like:
3092+3093+ [[ "Todo/changes", {
3094+ "accountId": "x",
3095+ "sinceState": "10324",
3096+ "maxChanges": 50
3097+ }, "0" ],
3098+ [ "Todo/queryChanges", {
3099+ "accountId": "x",
3100+ "filter": {
3101+ "operator": "OR",
3102+ "conditions": [
3103+ { "hasKeyword": "music" },
3104+ { "hasKeyword": "video" }
3105+ ]
3106+ },
3107+ "sort": [{ "property": "title" }],
3108+ "sinceQueryState": "y13213",
3109+ "maxChanges": 50
3110+ }, "1" ]]
3111+3112+ and receive in response:
3113+3114+ [[ "Todo/changes", {
3115+ "accountId": "x",
3116+ "oldState": "10324",
3117+ "newState": "871903",
3118+ "hasMoreChanges": false,
3119+ "created": [],
3120+ "updated": [],
3121+ "destroyed": ["b"]
3122+ }, "0" ],
3123+ [ "Todo/queryChanges", {
3124+ "accountId": "x",
3125+ "oldQueryState": "y13213",
3126+ "newQueryState": "y13218",
3127+ "removed": ["b"],
3128+ "added": null
3129+ }, "1" ]]
3130+3131+3132+3133+3134+3135+3136+3137+3138+Jenkins & Newman Standards Track [Page 56]
3139+3140+RFC 8620 JMAP July 2019
3141+3142+3143+ Suppose the user has access to another account "y", for example, a
3144+ team account shared between multiple users. To move an existing Todo
3145+ from account "x", the client would call:
3146+3147+ [[ "Todo/copy", {
3148+ "fromAccountId": "x",
3149+ "accountId": "y",
3150+ "create": {
3151+ "k5122": {
3152+ "id": "a"
3153+ }
3154+ },
3155+ "onSuccessDestroyOriginal": true
3156+ }, "0" ]]
3157+3158+ The server successfully copies the Todo to a new account (where it
3159+ receives a new id) and deletes the original. Due to the implicit
3160+ call to "Todo/set", there are two responses to the single method
3161+ call, both with the same method call id:
3162+3163+ [[ "Todo/copy", {
3164+ "fromAccountId": "x",
3165+ "accountId": "y",
3166+ "created": {
3167+ "k5122": {
3168+ "id": "DAf97"
3169+ }
3170+ },
3171+ "oldState": "c1d64ecb038c",
3172+ "newState": "33844835152b"
3173+ }, "0" ],
3174+ [ "Todo/set", {
3175+ "accountId": "x",
3176+ "oldState": "871903",
3177+ "newState": "871909",
3178+ "destroyed": [ "a" ],
3179+ ...
3180+ }, "0" ]]
3181+3182+3183+3184+3185+3186+3187+3188+3189+3190+3191+3192+3193+3194+Jenkins & Newman Standards Track [Page 57]
3195+3196+RFC 8620 JMAP July 2019
3197+3198+3199+5.8. Proxy Considerations
3200+3201+ JMAP has been designed to allow an API endpoint to easily proxy
3202+ through to one or more JMAP servers. This may be useful for load
3203+ balancing, augmenting capabilities, or presenting a single endpoint
3204+ to accounts hosted on different JMAP servers (splitting the request
3205+ based on each method's "accountId" argument). The proxy need only
3206+ understand the general structure of a JMAP Request object; it does
3207+ not need to know anything specifically about the methods and
3208+ arguments it will pass through to other servers.
3209+3210+ If splitting up the methods in a request to call them on different
3211+ backend servers, the proxy must do two things to ensure back-
3212+ references and creation-id references resolve the same as if the
3213+ entire request were processed on a single server:
3214+3215+ 1. It must pass a "createdIds" property with each subrequest. If
3216+ this is not given by the client, an empty object should be used
3217+ for the first subrequest. The "createdIds" property of each
3218+ subresponse should be passed on in the next subrequest.
3219+3220+ 2. It must resolve back-references to previous method results that
3221+ were processed on a different server. This is a relatively
3222+ simple syntactic substitution, described in Section 3.7.
3223+3224+ When splitting a request based on accountId, proxy implementors do
3225+ need to be aware of "/copy" methods that copy between accounts. If
3226+ the accounts are on different servers, the proxy will have to
3227+ implement this functionality directly.
3228+3229+6. Binary Data
3230+3231+ Binary data is referenced by a *blobId* in JMAP and uploaded/
3232+ downloaded separately to the core API. The blobId solely represents
3233+ the raw bytes of data, not any associated metadata such as a file
3234+ name or content type. Such metadata is stored alongside the blobId
3235+ in the object referencing it. The data represented by a blobId is
3236+ immutable.
3237+3238+ Any blobId that exists within an account may be used when creating/
3239+ updating another object in that account. For example, an Email type
3240+ may have a blobId that represents the object in Internet Message
3241+ Format [RFC5322]. A client could create a new Email object with an
3242+ attachment and use this blobId, in effect attaching the old message
3243+ to the new one. Similarly, it could attach any existing attachment
3244+ of an old message without having to download and upload it again.
3245+3246+3247+3248+3249+3250+Jenkins & Newman Standards Track [Page 58]
3251+3252+RFC 8620 JMAP July 2019
3253+3254+3255+ When the client uses a blobId in a create/update, the server MAY
3256+ assign a new blobId to refer to the same binary data within the new/
3257+ updated object. If it does so, it MUST return any properties that
3258+ contain a changed blobId in the created/updated response, so the
3259+ client gets the new ids.
3260+3261+ A blob that is not referenced by a JMAP object (e.g., as a message
3262+ attachment) MAY be deleted by the server to free up resources.
3263+ Uploads (see below) are initially unreferenced blobs. To ensure
3264+ interoperability:
3265+3266+ o The server SHOULD use a separate quota for unreferenced blobs to
3267+ the account's usual quota. In the case of shared accounts, this
3268+ quota SHOULD be separate per user.
3269+3270+ o This quota SHOULD be at least the maximum total size that a single
3271+ object can reference on this server. For example, if supporting
3272+ JMAP Mail, this should be at least the maximum total attachments
3273+ size for a message.
3274+3275+ o When an upload would take the user over quota, the server MUST
3276+ delete unreferenced blobs in date order, oldest first, until there
3277+ is room for the new blob.
3278+3279+ o Except where quota restrictions force early deletion, an
3280+ unreferenced blob MUST NOT be deleted for at least 1 hour from the
3281+ time of upload; if reuploaded, the same blobId MAY be returned,
3282+ but this SHOULD reset the expiry time.
3283+3284+ o A blob MUST NOT be deleted during the method call that removed the
3285+ last reference, so that a client can issue a create and a destroy
3286+ that both reference the blob within the same method call.
3287+3288+6.1. Uploading Binary Data
3289+3290+ There is a single endpoint that handles all file uploads for an
3291+ account, regardless of what they are to be used for. The Session
3292+ object (see Section 2) has an "uploadUrl" property in URI Template
3293+ (level 1) format [RFC6570], which MUST contain a variable called
3294+ "accountId". The client may use this template in combination with an
3295+ "accountId" to get the URL of the file upload resource.
3296+3297+ To upload a file, the client submits an authenticated POST request to
3298+ the file upload resource.
3299+3300+3301+3302+3303+3304+3305+3306+Jenkins & Newman Standards Track [Page 59]
3307+3308+RFC 8620 JMAP July 2019
3309+3310+3311+ A successful request MUST return a single JSON object with the
3312+ following properties as the response:
3313+3314+ o accountId: "Id"
3315+3316+ The id of the account used for the call.
3317+3318+ o blobId: "Id"
3319+3320+ The id representing the binary data uploaded. The data for this
3321+ id is immutable. The id *only* refers to the binary data, not any
3322+ metadata.
3323+3324+ o type: "String"
3325+3326+ The media type of the file (as specified in [RFC6838],
3327+ Section 4.2) as set in the Content-Type header of the upload HTTP
3328+ request.
3329+3330+ o size: "UnsignedInt"
3331+3332+ The size of the file in octets.
3333+3334+ If identical binary content to an existing blob in the account is
3335+ uploaded, the existing blobId MAY be returned.
3336+3337+ Clients should use the blobId returned in a timely manner. Under
3338+ rare circumstances, the server may have deleted the blob before the
3339+ client uses it; the client should keep a reference to the local file
3340+ so it can upload it again in such a situation.
3341+3342+ When an HTTP error response is returned to the client, the server
3343+ SHOULD return a JSON "problem details" object as the response body,
3344+ as per [RFC7807].
3345+3346+ As access controls are often determined by the object holding the
3347+ reference to a blob, unreferenced blobs MUST only be accessible to
3348+ the uploader, even in shared accounts.
3349+3350+6.2. Downloading Binary Data
3351+3352+ The Session object (see Section 2) has a "downloadUrl" property,
3353+ which is in URI Template (level 1) format [RFC6570]. The URL MUST
3354+ contain variables called "accountId", "blobId", "type", and "name".
3355+3356+3357+3358+3359+3360+3361+3362+Jenkins & Newman Standards Track [Page 60]
3363+3364+RFC 8620 JMAP July 2019
3365+3366+3367+ To download a file, the client makes an authenticated GET request to
3368+ the download URL with the appropriate variables substituted in:
3369+3370+ o "accountId": The id of the account to which the record with the
3371+ blobId belongs.
3372+3373+ o "blobId": The blobId representing the data of the file to
3374+ download.
3375+3376+ o "type": The type for the server to set in the "Content-Type"
3377+ header of the response; the blobId only represents the binary data
3378+ and does not have a content-type innately associated with it.
3379+3380+ o "name": The name for the file; the server MUST return this as the
3381+ filename if it sets a "Content-Disposition" header.
3382+3383+ As the data for a particular blobId is immutable, and thus the
3384+ response in the generated download URL is too, implementors are
3385+ recommended to set long cache times and use the "immutable" Cache-
3386+ Control extension [RFC8246] for successful responses, for example,
3387+ "Cache-Control: private, immutable, max-age=31536000".
3388+3389+ When an HTTP error response is returned to the client, the server
3390+ SHOULD return a JSON "problem details" object as the response body,
3391+ as per [RFC7807].
3392+3393+6.3. Blob/copy
3394+3395+ Binary data may be copied *between* two different accounts using the
3396+ "Blob/copy" method rather than having to download and then reupload
3397+ on the client.
3398+3399+ The "Blob/copy" method takes the following arguments:
3400+3401+ o fromAccountId: "Id"
3402+3403+ The id of the account to copy blobs from.
3404+3405+ o accountId: "Id"
3406+3407+ The id of the account to copy blobs to.
3408+3409+ o blobIds: "Id[]"
3410+3411+ A list of ids of blobs to copy to the other account.
3412+3413+3414+3415+3416+3417+3418+Jenkins & Newman Standards Track [Page 61]
3419+3420+RFC 8620 JMAP July 2019
3421+3422+3423+ The response has the following arguments:
3424+3425+ o fromAccountId: "Id"
3426+3427+ The id of the account blobs were copied from.
3428+3429+ o accountId: "Id"
3430+3431+ The id of the account blobs were copied to.
3432+3433+ o copied: "Id[Id]|null"
3434+3435+ A map of the blobId in the fromAccount to the id for the blob in
3436+ the account it was copied to, or null if none were successfully
3437+ copied.
3438+3439+ o notCopied: "Id[SetError]|null"
3440+3441+ A map of blobId to a SetError object for each blob that failed to
3442+ be copied, or null if none.
3443+3444+ The SetError may be any of the standard set errors that may be
3445+ returned for a create, as defined in Section 5.3. In addition, the
3446+ "notFound" SetError error may be returned if the blobId to be copied
3447+ cannot be found.
3448+3449+ The following additional method-level error may be returned instead
3450+ of the "Blob/copy" response:
3451+3452+ "fromAccountNotFound": The "fromAccountId" included with the request
3453+ does not correspond to a valid account.
3454+3455+7. Push
3456+3457+ Push notifications allow clients to efficiently update (almost)
3458+ instantly to stay in sync with data changes on the server. The
3459+ general model for push is simple and sends minimal data over the push
3460+ channel: just enough for the client to know whether it needs to
3461+ resync. The format allows multiple changes to be coalesced into a
3462+ single push update and the frequency of pushes to be rate limited by
3463+ the server. It doesn't matter if some push events are dropped before
3464+ they reach the client; the next time it gets/sets any records of a
3465+ changed type, it will discover the data has changed and still sync
3466+ all changes.
3467+3468+3469+3470+3471+3472+3473+3474+Jenkins & Newman Standards Track [Page 62]
3475+3476+RFC 8620 JMAP July 2019
3477+3478+3479+ There are two different mechanisms by which a client can receive push
3480+ notifications, to allow for the different environments in which a
3481+ client may exist. An event source resource (see Section 7.3) allows
3482+ clients that can hold transport connections open to receive push
3483+ notifications directly from the JMAP server. This is simple and
3484+ avoids third parties, but it is often not feasible on constrained
3485+ platforms such as mobile devices. Alternatively, clients can make
3486+ use of any push service supported by their environment. A URL for
3487+ the push service is registered with the JMAP server (see
3488+ Section 7.2); the server then POSTs each notification to that URL.
3489+ The push service is then responsible for routing these to the client.
3490+3491+7.1. The StateChange Object
3492+3493+ When something changes on the server, the server pushes a StateChange
3494+ object to the client. A *StateChange* object has the following
3495+ properties:
3496+3497+ o @type: "String"
3498+3499+ This MUST be the string "StateChange".
3500+3501+ o changed: "Id[TypeState]"
3502+3503+ A map of an "account id" to an object encoding the state of data
3504+ types that have changed for that account since the last
3505+ StateChange object was pushed, for each of the accounts to which
3506+ the user has access and for which something has changed.
3507+3508+ A *TypeState* object is a map. The keys are the type name "Foo"
3509+ (e.g., "Mailbox" or "Email"), and the value is the "state"
3510+ property that would currently be returned by a call to "Foo/get".
3511+3512+ The client can compare the new state strings with its current
3513+ values to see whether it has the current data for these types. If
3514+ not, the changes can then be efficiently fetched in a single
3515+ standard API request (using the /changes type methods).
3516+3517+3518+3519+3520+3521+3522+3523+3524+3525+3526+3527+3528+3529+3530+Jenkins & Newman Standards Track [Page 63]
3531+3532+RFC 8620 JMAP July 2019
3533+3534+3535+7.1.1. Example
3536+3537+ In this example, the server has amalgamated a few changes together
3538+ across two different accounts the user has access to, before pushing
3539+ the following StateChange object to the client:
3540+3541+ {
3542+ "@type": "StateChange",
3543+ "changed": {
3544+ "a3123": {
3545+ "Email": "d35ecb040aab",
3546+ "EmailDelivery": "428d565f2440",
3547+ "CalendarEvent": "87accfac587a"
3548+ },
3549+ "a43461d": {
3550+ "Mailbox": "0af7a512ce70",
3551+ "CalendarEvent": "7a4297cecd76"
3552+ }
3553+ }
3554+ }
3555+3556+ The client can compare the state strings with its current state for
3557+ the Email, CalendarEvent, etc., object types in the appropriate
3558+ accounts to see if it needs to fetch changes.
3559+3560+ If the client is itself making changes, it may receive a StateChange
3561+ object while the /set API call is in flight. It can wait until the
3562+ call completes and then compare if the new state string after the
3563+ /set is the same as was pushed in the StateChange object; if so, and
3564+ the old state of the /set response matches the client's previous
3565+ state, it does not need to waste a request asking for changes it
3566+ already knows.
3567+3568+7.2. PushSubscription
3569+3570+ Clients may create a PushSubscription to register a URL with the JMAP
3571+ server. The JMAP server will then make an HTTP POST request to this
3572+ URL for each push notification it wishes to send to the client.
3573+3574+ As a push subscription causes the JMAP server to make a number of
3575+ requests to a previously unknown endpoint, it can be used as a vector
3576+ for launching a denial-of-service attack. To prevent this, when a
3577+ subscription is created, the JMAP server immediately sends a
3578+ PushVerification object to that URL (see Section 7.2.2). The JMAP
3579+ server MUST NOT make any further requests to the URL until the client
3580+ receives the push and updates the subscription with the correct
3581+ verification code.
3582+3583+3584+3585+3586+Jenkins & Newman Standards Track [Page 64]
3587+3588+RFC 8620 JMAP July 2019
3589+3590+3591+ A *PushSubscription* object has the following properties:
3592+3593+ o id: "Id" (immutable; server-set)
3594+3595+ The id of the push subscription.
3596+3597+ o deviceClientId: "String" (immutable)
3598+3599+ An id that uniquely identifies the client + device it is running
3600+ on. The purpose of this is to allow clients to identify which
3601+ PushSubscription objects they created even if they lose their
3602+ local state, so they can revoke or update them. This string MUST
3603+ be different on different devices and be different from apps from
3604+ other vendors. It SHOULD be easy to regenerate and not depend on
3605+ persisted state. It is RECOMMENDED to use a secure hash of a
3606+ string that contains:
3607+3608+ 1. A unique identifier associated with the device where the JMAP
3609+ client is running, normally supplied by the device's operating
3610+ system.
3611+3612+ 2. A custom vendor/app id, including a domain controlled by the
3613+ vendor of the JMAP client.
3614+3615+ To protect the privacy of the user, the deviceClientId id MUST NOT
3616+ contain an unobfuscated device id.
3617+3618+ o url: "String" (immutable)
3619+3620+ An absolute URL where the JMAP server will POST the data for the
3621+ push message. This MUST begin with "https://".
3622+3623+ o keys: "Object|null" (immutable)
3624+3625+ Client-generated encryption keys. If supplied, the server MUST
3626+ use them as specified in [RFC8291] to encrypt all data sent to the
3627+ push subscription. The object MUST have the following properties:
3628+3629+ * p256dh: "String"
3630+3631+ The P-256 Elliptic Curve Diffie-Hellman (ECDH) public key as
3632+ described in [RFC8291], encoded in URL-safe base64
3633+ representation as defined in [RFC4648].
3634+3635+ * auth: "String"
3636+3637+ The authentication secret as described in [RFC8291], encoded in
3638+ URL-safe base64 representation as defined in [RFC4648].
3639+3640+3641+3642+Jenkins & Newman Standards Track [Page 65]
3643+3644+RFC 8620 JMAP July 2019
3645+3646+3647+ o verificationCode: "String|null"
3648+3649+ This MUST be null (or omitted) when the subscription is created.
3650+ The JMAP server then generates a verification code and sends it in
3651+ a push message, and the client updates the PushSubscription object
3652+ with the code; see Section 7.2.2 for details.
3653+3654+ o expires: "UTCDate|null"
3655+3656+ The time this push subscription expires. If specified, the JMAP
3657+ server MUST NOT make further requests to this resource after this
3658+ time. It MAY automatically destroy the push subscription at or
3659+ after this time.
3660+3661+ The server MAY choose to set an expiry if none is given by the
3662+ client or modify the expiry time given by the client to a shorter
3663+ duration.
3664+3665+ o types: "String[]|null"
3666+3667+ A list of types the client is interested in (using the same names
3668+ as the keys in the TypeState object defined in the previous
3669+ section). A StateChange notification will only be sent if the
3670+ data for one of these types changes. Other types are omitted from
3671+ the TypeState object. If null, changes will be pushed for all
3672+ types.
3673+3674+ The POST request MUST have a content type of "application/json" and
3675+ contain the UTF-8 JSON-encoded object as the body. The request MUST
3676+ have a "TTL" header and MAY have "Urgency" and/or "Topic" headers, as
3677+ specified in Section 5 of [RFC8030]. The JMAP server is expected to
3678+ understand and handle HTTP status responses in a reasonable manner.
3679+ A "429" (Too Many Requests) response MUST cause the JMAP server to
3680+ reduce the frequency of pushes; the JMAP push structure allows
3681+ multiple changes to be coalesced into a single minimal StateChange
3682+ object. See the security considerations in Section 8.6 for a
3683+ discussion of the risks in connecting to unknown servers.
3684+3685+ The JMAP server acts as an application server as defined in
3686+ [RFC8030]. A client MAY use the rest of [RFC8030] in combination
3687+ with its own push service to form a complete end-to-end solution, or
3688+ it MAY rely on alternative mechanisms to ensure the delivery of the
3689+ pushed data after it leaves the JMAP server.
3690+3691+ The push subscription is tied to the credentials used to authenticate
3692+ the API request that created it. Should these credentials expire or
3693+ be revoked, the push subscription MUST be destroyed by the JMAP
3694+3695+3696+3697+3698+Jenkins & Newman Standards Track [Page 66]
3699+3700+RFC 8620 JMAP July 2019
3701+3702+3703+ server. Only subscriptions created by these credentials are returned
3704+ when the client fetches existing subscriptions.
3705+3706+ When these credentials have their own expiry (i.e., it is a session
3707+ with a timeout), the server SHOULD NOT set or bound the expiry time
3708+ for the push subscription given by the client but MUST expire it when
3709+ the session expires.
3710+3711+ When these credentials are not time bounded (e.g., Basic
3712+ authentication [RFC7617]), the server SHOULD set an expiry time for
3713+ the push subscription if none is given and limit the expiry time if
3714+ set too far in the future. This maximum expiry time MUST be at least
3715+ 48 hours in the future and SHOULD be at least 7 days in the future.
3716+ An app running on a mobile device may only be able to refresh the
3717+ push subscription lifetime when it is in the foreground, so this
3718+ gives a reasonable time frame to allow this to happen.
3719+3720+ In the case of separate access and refresh credentials, as in Oauth
3721+ 2.0 [RFC6749], the server SHOULD tie the push subscription to the
3722+ validity of the refresh token rather than the access token and behave
3723+ according to whether this is time-limited or not.
3724+3725+ When a push subscription is destroyed, the server MUST securely erase
3726+ the URL and encryption keys from memory and storage as soon as
3727+ possible.
3728+3729+7.2.1. PushSubscription/get
3730+3731+ Standard /get method as described in Section 5.1, except it does
3732+ *not* take or return an "accountId" argument, as push subscriptions
3733+ are not tied to specific accounts. It also does *not* return a
3734+ "state" argument. The "ids" argument may be null to fetch all at
3735+ once.
3736+3737+ The server MUST only return push subscriptions that were created
3738+ using the same authentication credentials as for this
3739+ "PushSubscription/get" request.
3740+3741+ As the "url" and "keys" properties may contain data that is private
3742+ to a particular device, the values for these properties MUST NOT be
3743+ returned. If the "properties" argument is null or omitted, the
3744+ server MUST default to all properties excluding these two. If one of
3745+ them is explicitly requested, the method call MUST be rejected with a
3746+ "forbidden" error.
3747+3748+3749+3750+3751+3752+3753+3754+Jenkins & Newman Standards Track [Page 67]
3755+3756+RFC 8620 JMAP July 2019
3757+3758+3759+7.2.2. PushSubscription/set
3760+3761+ Standard /set method as described in Section 5.3, except it does
3762+ *not* take or return an "accountId" argument, as push subscriptions
3763+ are not tied to specific accounts. It also does *not* take an
3764+ "ifInState" argument or return "oldState" or "newState" arguments.
3765+3766+ The "url" and "keys" properties are immutable; if the client wishes
3767+ to change these, it must destroy the current push subscription and
3768+ create a new one.
3769+3770+ When a PushSubscription is created, the server MUST immediately push
3771+ a *PushVerification* object to the URL. It has the following
3772+ properties:
3773+3774+ o @type: "String"
3775+3776+ This MUST be the string "PushVerification".
3777+3778+ o pushSubscriptionId: "String"
3779+3780+ The id of the push subscription that was created.
3781+3782+ o verificationCode: "String"
3783+3784+ The verification code to add to the push subscription. This MUST
3785+ contain sufficient entropy to avoid the client being able to guess
3786+ the code via brute force.
3787+3788+ The client MUST update the push subscription with the correct
3789+ verification code before the server makes any further requests to the
3790+ subscription's URL. Attempts to update the subscription with an
3791+ invalid verification code MUST be rejected by the server with an
3792+ "invalidProperties" SetError.
3793+3794+ The client may update the "expires" property to extend (or, less
3795+ commonly, shorten) the lifetime of a push subscription. The server
3796+ MAY modify the proposed new expiry time to enforce server-defined
3797+ limits. Extending the lifetime does not require the subscription to
3798+ be verified again.
3799+3800+ Clients SHOULD NOT update or destroy a push subscription that they
3801+ did not create (i.e., has a "deviceClientId" that they do not
3802+ recognise).
3803+3804+3805+3806+3807+3808+3809+3810+Jenkins & Newman Standards Track [Page 68]
3811+3812+RFC 8620 JMAP July 2019
3813+3814+3815+7.2.3. Example
3816+3817+ At "2018-07-06T02:14:29Z", a client with deviceClientId "a889-ffea-
3818+ 910" fetches the set of push subscriptions currently on the server,
3819+ making an API request with:
3820+3821+ [[ "PushSubscription/get", {
3822+ "ids": null
3823+ }, "0" ]]
3824+3825+ Which returns:
3826+3827+ [[ "PushSubscription/get", {
3828+ "list": [{
3829+ "id": "e50b2c1d-9553-41a3-b0a7-a7d26b599ee1",
3830+ "deviceClientId": "b37ff8001ca0",
3831+ "verificationCode": "b210ef734fe5f439c1ca386421359f7b",
3832+ "expires": "2018-07-31T00:13:21Z",
3833+ "types": [ "Todo" ]
3834+ }, {
3835+ "id": "f2d0aab5-e976-4e8b-ad4b-b380a5b987e4",
3836+ "deviceClientId": "X8980fc",
3837+ "verificationCode": "f3d4618a9ae15c8b7f5582533786d531",
3838+ "expires": "2018-07-12T05:55:00Z",
3839+ "types": [ "Mailbox", "Email", "EmailDelivery" ]
3840+ }],
3841+ "notFound": []
3842+ }, "0" ]]
3843+3844+ Since neither of the returned push subscription objects have the
3845+ client's deviceClientId, it knows it does not have a current push
3846+ subscription active on the server. So it creates one, sending this
3847+ request:
3848+3849+[[ "PushSubscription/set", {
3850+ "create": {
3851+ "4f29": {
3852+ "deviceClientId": "a889-ffea-910",
3853+ "url": "https://example.com/push/?device=X8980fc&client=12c6d086",
3854+ "types": null
3855+ }
3856+ }
3857+}, "0" ]]
3858+3859+3860+3861+3862+3863+3864+3865+3866+Jenkins & Newman Standards Track [Page 69]
3867+3868+RFC 8620 JMAP July 2019
3869+3870+3871+ The server creates the push subscription but limits the expiry time
3872+ to 7 days in the future, returning this response:
3873+3874+ [[ "PushSubscription/set", {
3875+ "created": {
3876+ "4f29": {
3877+ "id": "P43dcfa4-1dd4-41ef-9156-2c89b3b19c60",
3878+ "keys": null,
3879+ "expires": "2018-07-13T02:14:29Z"
3880+ }
3881+ }
3882+ }, "0" ]]
3883+3884+ The server also immediately makes a POST request to
3885+ "https://example.com/push/?device=X8980fc&client=12c6d086" with the
3886+ data:
3887+3888+ {
3889+ "@type": "PushVerification",
3890+ "pushSubscriptionId": "P43dcfa4-1dd4-41ef-9156-2c89b3b19c60",
3891+ "verificationCode": "da1f097b11ca17f06424e30bf02bfa67"
3892+ }
3893+3894+ The client receives this and updates the subscription with the
3895+ verification code (note there is a potential race condition here; the
3896+ client MUST be able to handle receiving the push while the request
3897+ creating the subscription is still in progress):
3898+3899+ [[ "PushSubscription/set", {
3900+ "update": {
3901+ "P43dcfa4-1dd4-41ef-9156-2c89b3b19c60": {
3902+ "verificationCode": "da1f097b11ca17f06424e30bf02bfa67"
3903+ }
3904+ }
3905+ }, "0" ]]
3906+3907+ The server confirms the update was successful and will now make
3908+ requests to the registered URL when the state changes.
3909+3910+3911+3912+3913+3914+3915+3916+3917+3918+3919+3920+3921+3922+Jenkins & Newman Standards Track [Page 70]
3923+3924+RFC 8620 JMAP July 2019
3925+3926+3927+ Two days later, the client updates the subscription to extend its
3928+ lifetime, sending this request:
3929+3930+ [[ "PushSubscription/set", {
3931+ "update": {
3932+ "P43dcfa4-1dd4-41ef-9156-2c89b3b19c60": {
3933+ "expires": "2018-08-13T00:00:00Z"
3934+ }
3935+ }
3936+ }, "0" ]]
3937+3938+ The server extends the expiry time, but only again to its maximum
3939+ limit of 7 days in the future, returning this response:
3940+3941+ [[ "PushSubscription/set", {
3942+ "updated": {
3943+ "P43dcfa4-1dd4-41ef-9156-2c89b3b19c60": {
3944+ "expires": "2018-07-15T02:22:50Z"
3945+ }
3946+ }
3947+ }, "0" ]]
3948+3949+7.3. Event Source
3950+3951+ Clients that can hold transport connections open can connect directly
3952+ to the JMAP server to receive push notifications via a "text/event-
3953+ stream" resource, as described in [EventSource]. This is a long
3954+ running HTTP request, where the server can push data to the client by
3955+ appending data without ending the response.
3956+3957+ When a change occurs in the data on the server, it pushes an event
3958+ called "state" to any connected clients, with the StateChange object
3959+ as the data.
3960+3961+ The server SHOULD also send a new event id that encodes the entire
3962+ server state visible to the user immediately after sending a "state"
3963+ event. When a new connection is made to the event-source endpoint, a
3964+ client following the server-sent events specification will send a
3965+ Last-Event-ID HTTP header field with the last id it saw, which the
3966+ server can use to work out whether the client has missed some
3967+ changes. If so, it SHOULD send these changes immediately on
3968+ connection.
3969+3970+ The Session object (see Section 2) has an "eventSourceUrl" property,
3971+ which is in URI Template (level 1) format [RFC6570]. The URL MUST
3972+ contain variables called "types", "closeafter", and "ping".
3973+3974+3975+3976+3977+3978+Jenkins & Newman Standards Track [Page 71]
3979+3980+RFC 8620 JMAP July 2019
3981+3982+3983+ To connect to the resource, the client makes an authenticated GET
3984+ request to the event-source URL with the appropriate variables
3985+ substituted in:
3986+3987+ o "types": This MUST be either:
3988+3989+ * A comma-separated list of type names, e.g.,
3990+ "Email,CalendarEvent". The server MUST only push changes for
3991+ the types in this list.
3992+3993+ * The single character: "*". Changes to all types are pushed.
3994+3995+ o "closeafter": This MUST be one of the following values:
3996+3997+ * "state": The server MUST end the HTTP response after pushing a
3998+ state event. This can be used by clients in environments where
3999+ buffering proxies prevent the pushed data from arriving
4000+ immediately, or indeed at all, when operating in the usual
4001+ mode.
4002+4003+ * "no": The connection is persisted by the server as a standard
4004+ event-source resource.
4005+4006+ o "ping": A positive integer value representing a length of time in
4007+ seconds, e.g., "300". If non-zero, the server MUST send an event
4008+ called "ping" whenever this time elapses since the previous event
4009+ was sent. This MUST NOT set a new event id. If the value is "0",
4010+ the server MUST NOT send ping events.
4011+4012+ The server MAY modify a requested ping interval to be subject to a
4013+ minimum and/or maximum value. For interoperability, servers MUST
4014+ NOT have a minimum allowed value higher than 30 or a maximum
4015+ allowed value less than 300.
4016+4017+ The data for the ping event MUST be a JSON object containing an
4018+ "interval" property, the value (type "UnsignedInt") being the
4019+ interval in seconds the server is using to send pings (this may be
4020+ different to the requested value if the server clamped it to be
4021+ within a min/max value).
4022+4023+ Clients can monitor for the ping event to help determine when the
4024+ closeafter mode may be required.
4025+4026+ A client MAY hold open multiple connections to the event-source
4027+ resource, although it SHOULD try to use a single connection for
4028+ efficiency.
4029+4030+4031+4032+4033+4034+Jenkins & Newman Standards Track [Page 72]
4035+4036+RFC 8620 JMAP July 2019
4037+4038+4039+8. Security Considerations
4040+4041+8.1. Transport Confidentiality
4042+4043+ To ensure the confidentiality and integrity of data sent and received
4044+ via JMAP, all requests MUST use TLS 1.2 [RFC5246] [RFC8446] or later,
4045+ following the recommendations in [RFC7525]. Servers SHOULD support
4046+ TLS 1.3 [RFC8446] or later.
4047+4048+ Clients MUST validate TLS certificate chains to protect against
4049+ man-in-the-middle attacks [RFC5280].
4050+4051+8.2. Authentication Scheme
4052+4053+ A number of HTTP authentication schemes have been standardised (see
4054+ <https://www.iana.org/assignments/http-authschemes/>). Servers
4055+ should take care to assess the security characteristics of different
4056+ schemes in relation to their needs when deciding what to implement.
4057+4058+ Use of the Basic authentication scheme is NOT RECOMMENDED. Services
4059+ that choose to use it are strongly recommended to require generation
4060+ of a unique "app password" via some external mechanism for each
4061+ client they wish to connect. This allows connections from different
4062+ devices to be differentiated by the server and access to be
4063+ individually revoked.
4064+4065+8.3. Service Autodiscovery
4066+4067+ Unless secured by something like DNSSEC, autodiscovery of server
4068+ details using SRV DNS records is vulnerable to a DNS poisoning
4069+ attack, which can lead to the client talking to an attacker's server
4070+ instead of the real JMAP server. The attacker may then intercept
4071+ requests to execute man-in-the-middle attacks and, depending on the
4072+ authentication scheme, steal credentials to generate its own
4073+ requests.
4074+4075+ Clients that do not support SRV lookups are likely to try just using
4076+ the "/.well-known/jmap" path directly against the domain of the
4077+ username over HTTPS. Servers SHOULD ensure this path resolves or
4078+ redirects to the correct JMAP Session resource to allow this to work.
4079+ If this is not feasible, servers MUST ensure this path cannot be
4080+ controlled by an attacker, as again it may be used to steal
4081+ credentials.
4082+4083+4084+4085+4086+4087+4088+4089+4090+Jenkins & Newman Standards Track [Page 73]
4091+4092+RFC 8620 JMAP July 2019
4093+4094+4095+8.4. JSON Parsing
4096+4097+ The Security Considerations of [RFC8259] apply to the use of JSON as
4098+ the data interchange format.
4099+4100+ As for any serialization format, parsers need to thoroughly check the
4101+ syntax of the supplied data. JSON uses opening and closing tags for
4102+ several types and structures, and it is possible that the end of the
4103+ supplied data will be reached when scanning for a matching closing
4104+ tag; this is an error condition, and implementations need to stop
4105+ scanning at the end of the supplied data.
4106+4107+ JSON also uses a string encoding with some escape sequences to encode
4108+ special characters within a string. Care is needed when processing
4109+ these escape sequences to ensure that they are fully formed before
4110+ the special processing is triggered, with special care taken when the
4111+ escape sequences appear adjacent to other (non-escaped) special
4112+ characters or adjacent to the end of data (as in the previous
4113+ paragraph).
4114+4115+ If parsing JSON into a non-textual structured data format,
4116+ implementations may need to allocate storage to hold JSON string
4117+ elements. Since JSON does not use explicit string lengths, the risk
4118+ of denial of service due to resource exhaustion is small, but
4119+ implementations may still wish to place limits on the size of
4120+ allocations they are willing to make in any given context, to avoid
4121+ untrusted data causing excessive memory allocation.
4122+4123+8.5. Denial of Service
4124+4125+ A small request may result in a very large response and require
4126+ considerable work on the server if resource limits are not enforced.
4127+ JMAP provides mechanisms for advertising and enforcing a wide variety
4128+ of limits for mitigating this threat, including limits on the number
4129+ of objects fetched in a single method call, number of methods in a
4130+ single request, number of concurrent requests, etc.
4131+4132+ JMAP servers MUST implement sensible limits to mitigate against
4133+ resource exhaustion attacks.
4134+4135+8.6. Connection to Unknown Push Server
4136+4137+ When a push subscription is registered, the application server will
4138+ make POST requests to the given URL. There are a number of security
4139+ considerations that MUST be considered when implementing this.
4140+4141+4142+4143+4144+4145+4146+Jenkins & Newman Standards Track [Page 74]
4147+4148+RFC 8620 JMAP July 2019
4149+4150+4151+ The server MUST ensure the URL is externally resolvable to avoid
4152+ server-side request forgery, where the server makes a request to a
4153+ resource on its internal network.
4154+4155+ A malicious client may use the push subscription to attempt to flood
4156+ a third party server with requests, creating a denial-of-service
4157+ attack and masking the attacker's true identity. There is no
4158+ guarantee that the URL given to the JMAP server is actually a valid
4159+ push server. Upon creation of a push subscription, the JMAP server
4160+ sends a PushVerification object to the URL and MUST NOT send any
4161+ further requests until the client verifies it has received the
4162+ initial push. The verification code MUST contain sufficient entropy
4163+ to prevent the client from being able to verify the subscription via
4164+ brute force.
4165+4166+ The verification code does not guarantee the URL is a valid push
4167+ server, only that the client is able to access the data submitted to
4168+ it. While the verification step significantly reduces the set of
4169+ potential targets, there is still a risk that the server is unrelated
4170+ to the client and being targeted for a denial-of-service attack.
4171+4172+ The server MUST limit the number of push subscriptions any one user
4173+ may have to ensure the user cannot cause the server to send a large
4174+ number of push notifications at once, which could again be used as
4175+ part of a denial-of-service attack. The rate of creation MUST also
4176+ be limited to minimise the ability to abuse the verification request
4177+ as an attack vector.
4178+4179+8.7. Push Encryption
4180+4181+ When data changes, a small object is pushed with the new state
4182+ strings for the types that have changed. While the data here is
4183+ minimal, a passive man-in-the-middle attacker may be able to gain
4184+ useful information. To ensure confidentiality and integrity, if the
4185+ push is sent via a third party outside of the control of the client
4186+ and JMAP server, the client MUST specify encryption keys when
4187+ establishing the PushSubscription and ignore any push notification
4188+ received that is not encrypted with those keys.
4189+4190+ The privacy and security considerations of [RFC8030] and [RFC8291]
4191+ also apply to the use of the PushSubscription mechanism.
4192+4193+ As there is no crypto algorithm agility in Web Push Encryption
4194+ [RFC8291], a new specification will be needed to provide this if new
4195+ algorithms are required in the future.
4196+4197+4198+4199+4200+4201+4202+Jenkins & Newman Standards Track [Page 75]
4203+4204+RFC 8620 JMAP July 2019
4205+4206+4207+8.8. Traffic Analysis
4208+4209+ While the data is encrypted, a passive observer with the ability to
4210+ monitor network traffic may be able to glean information from the
4211+ timing of API requests and push notifications. For example, suppose
4212+ an email or calendar invitation is sent from User A (hosted on Server
4213+ X) to User B (hosted on Server Y). If Server X hosts data for many
4214+ users, a passive observer can see that the two servers connected but
4215+ does not know who the data was for. However, if a push notification
4216+ is immediately sent to User B and the attacker can observe this as
4217+ well, they may reasonably conclude that someone on Server X is
4218+ connecting to User B.
4219+4220+9. IANA Considerations
4221+4222+9.1. Assignment of jmap Service Name
4223+4224+ IANA has assigned the 'jmap' service name in the "Service Name and
4225+ Transport Protocol Port Number Registry" [RFC6335].
4226+4227+ Service Name: jmap
4228+4229+ Transport Protocol(s): tcp
4230+4231+ Assignee: IESG
4232+4233+ Contact: IETF Chair
4234+4235+ Description: JSON Meta Application Protocol
4236+4237+ Reference: RFC 8620
4238+4239+ Assignment Notes: This service name was previously assigned under the
4240+ name "JSON Mail Access Protocol". This has been de-assigned and
4241+ re-assigned with the approval of the previous assignee.
4242+4243+9.2. Registration of Well-Known URI Suffix for JMAP
4244+4245+ IANA has registered the following suffix in the "Well-Known URIs"
4246+ registry for JMAP, as described in [RFC8615]:
4247+4248+ URI Suffix: jmap
4249+4250+ Change Controller: IETF
4251+4252+ Specification Document: RFC 8620, Section 2.2.
4253+4254+4255+4256+4257+4258+Jenkins & Newman Standards Track [Page 76]
4259+4260+RFC 8620 JMAP July 2019
4261+4262+4263+9.3. Registration of the jmap URN Sub-namespace
4264+4265+ IANA has registered the following URN sub-namespace in the "IETF URN
4266+ Sub-namespace for Registered Protocol Parameter Identifiers" registry
4267+ within the "Uniform Resource Name (URN) Namespace for IETF Use"
4268+ registry as described in [RFC3553].
4269+4270+ Registered Parameter Identifier: jmap
4271+4272+ Reference: RFC 8620, Section 9.4
4273+4274+ IANA Registry Reference: http://www.iana.org/assignments/jmap
4275+4276+9.4. Creation of "JMAP Capabilities" Registry
4277+4278+ IANA has created the "JMAP Capabilities" registry as described in
4279+ Section 2. JMAP capabilities are advertised in the "capabilities"
4280+ property of the JMAP Session resource. They are used to extend the
4281+ functionality of a JMAP server. A capability is referenced by a URI.
4282+ The JMAP capability URI can be a URN starting with
4283+ "urn:ietf:params:jmap:" plus a unique suffix that is the index value
4284+ in the jmap URN sub-namespace. Registration of a JMAP capability
4285+ with another form of URI has no impact on the jmap URN sub-namespace.
4286+4287+ This registry follows the expert review process unless the "intended
4288+ use" field is "common" or "placeholder", in which case registration
4289+ follows the specification required process.
4290+4291+ A JMAP capability registration can have an intended use of "common",
4292+ "placeholder", "limited", or "obsolete". IANA will list common-use
4293+ registrations prominently and separately from those with other
4294+ intended use values.
4295+4296+ The JMAP capability registration procedure is not a formal standards
4297+ process but rather an administrative procedure intended to allow
4298+ community comment and sanity checking without excessive time delay.
4299+4300+ A "placeholder" registration reserves part of the jmap URN namespace
4301+ for another purpose but is typically not included in the
4302+ "capabilities" property of the JMAP Session resource.
4303+4304+9.4.1. Preliminary Community Review
4305+4306+ Notice of a potential JMAP common-use registration SHOULD be sent to
4307+ the JMAP mailing list <jmap@ietf.org> for review. This mailing list
4308+ is appropriate to solicit community feedback on a proposed JMAP
4309+4310+4311+4312+4313+4314+Jenkins & Newman Standards Track [Page 77]
4315+4316+RFC 8620 JMAP July 2019
4317+4318+4319+ capability. Registrations that are not intended for common use MAY
4320+ be sent to the list for review as well; doing so is entirely
4321+ OPTIONAL, but is encouraged.
4322+4323+ The intent of the public posting to this list is to solicit comments
4324+ and feedback on the choice of the capability name, the unambiguity of
4325+ the specification document, and a review of any interoperability or
4326+ security considerations. The submitter may submit a revised
4327+ registration proposal or abandon the registration completely at any
4328+ time.
4329+4330+9.4.2. Submit Request to IANA
4331+4332+ Registration requests can be sent to <iana@iana.org>.
4333+4334+9.4.3. Designated Expert Review
4335+4336+ For a limited-use registration, the primary concern of the designated
4337+ expert (DE) is preventing name collisions and encouraging the
4338+ submitter to document security and privacy considerations; a
4339+ published specification is not required. For a common-use
4340+ registration, the DE is expected to confirm that suitable
4341+ documentation, as described in Section 4.6 of [RFC8126], is
4342+ available. The DE should also verify that the capability does not
4343+ conflict with work that is active or already published within the
4344+ IETF.
4345+4346+ Before a period of 30 days has passed, the DE will either approve or
4347+ deny the registration request and publish a notice of the decision to
4348+ the JMAP WG mailing list or its successor, as well as inform IANA. A
4349+ denial notice must be justified by an explanation, and, in the cases
4350+ where it is possible, concrete suggestions on how the request can be
4351+ modified so as to become acceptable should be provided.
4352+4353+ If the DE does not respond within 30 days, the registrant may request
4354+ the IESG take action to process the request in a timely manner.
4355+4356+9.4.4. Change Procedures
4357+4358+ Once a JMAP capability has been published by the IANA, the change
4359+ controller may request a change to its definition. The same
4360+ procedure that would be appropriate for the original registration
4361+ request is used to process a change request.
4362+4363+ JMAP capability registrations may not be deleted; capabilities that
4364+ are no longer believed appropriate for use can be declared obsolete
4365+ by a change to their "intended use" field; such capabilities will be
4366+ clearly marked in the lists published by the IANA.
4367+4368+4369+4370+Jenkins & Newman Standards Track [Page 78]
4371+4372+RFC 8620 JMAP July 2019
4373+4374+4375+ Significant changes to a capability's definition should be requested
4376+ only when there are serious omissions or errors in the published
4377+ specification. When review is required, a change request may be
4378+ denied if it renders entities that were valid under the previous
4379+ definition invalid under the new definition.
4380+4381+ The owner of a JMAP capability may pass responsibility to another
4382+ person or agency by informing the IANA; this can be done without
4383+ discussion or review.
4384+4385+ The IESG may reassign responsibility for a JMAP capability. The most
4386+ common case of this will be to enable changes to be made to
4387+ capabilities where the author of the registration has died, moved out
4388+ of contact, or is otherwise unable to make changes that are important
4389+ to the community.
4390+4391+9.4.5. JMAP Capabilities Registry Template
4392+4393+ Capability name: (see capability property in Section 2)
4394+4395+ Specification document:
4396+4397+ Intended use: (one of common, limited, placeholder, or obsolete)
4398+4399+ Change controller: ("IETF" for Standards Track / BCP RFCs)
4400+4401+ Security and privacy considerations:
4402+4403+9.4.6. Initial Registration for JMAP Core
4404+4405+ Capability Name: "urn:ietf:params:jmap:core"
4406+4407+ Specification document: RFC 8620, Section 2
4408+4409+ Intended use: common
4410+4411+ Change Controller: IETF
4412+4413+ Security and privacy considerations: RFC 8620, Section 8.
4414+4415+4416+4417+4418+4419+4420+4421+4422+4423+4424+4425+4426+Jenkins & Newman Standards Track [Page 79]
4427+4428+RFC 8620 JMAP July 2019
4429+4430+4431+9.4.7. Registration for JMAP Error Placeholder in JMAP Capabilities
4432+ Registry
4433+4434+ Capability Name: "urn:ietf:params:jmap:error:"
4435+4436+ Specification document: RFC 8620, Section 9.5
4437+4438+ Intended use: placeholder
4439+4440+ Change Controller: IETF
4441+4442+ Security and privacy considerations: RFC 8620, Section 8.
4443+4444+9.5. Creation of "JMAP Error Codes" Registry
4445+4446+ IANA has created the "JMAP Error Codes" registry. JMAP error codes
4447+ appear in the "type" member of a JSON problem details object (as
4448+ described in Section 3.6.1), the "type" member in a JMAP error object
4449+ (as described in Section 3.6.2), or the "type" member of a JMAP
4450+ method-specific error object (such as SetError in Section 5.3). When
4451+ used in a problem details object, the prefix
4452+ "urn:ietf:params:jmap:error:" is always included; when used in JMAP
4453+ objects, the prefix is always omitted.
4454+4455+ This registry follows the expert review process. Preliminary
4456+ community review for this registry follows the same procedures as the
4457+ "JMAP Capabilities" registry, but it is optional. The change
4458+ procedures for this registry are the same as the change procedures
4459+ for the "JMAP Capabilities" registry.
4460+4461+9.5.1. Expert Review
4462+4463+ The designated expert should review the following aspects of the
4464+ registration:
4465+4466+ 1. Verify the error code does not conflict with existing names.
4467+4468+ 2. Verify the error code follows the syntax limitations (does not
4469+ require URI encoding).
4470+4471+ 3. Encourage the submitter to follow the naming convention of
4472+ previously registered errors.
4473+4474+ 4. Encourage the submitter to describe client behaviours that are
4475+ recommended in response to the error code. These may distinguish
4476+ the error code from other error codes.
4477+4478+4479+4480+4481+4482+Jenkins & Newman Standards Track [Page 80]
4483+4484+RFC 8620 JMAP July 2019
4485+4486+4487+ 5. Encourage the submitter to describe when the server should issue
4488+ the error as opposed to some other error code.
4489+4490+ 6. Encourage the submitter to note any security considerations
4491+ associated with the error, if any (e.g., an error code that might
4492+ disclose existence of data the authenticated user does not have
4493+ permission to know about).
4494+4495+ Steps 3-6 are meant to promote a higher-quality registry. However,
4496+ the expert is encouraged to approve any registration that would not
4497+ actively harm JMAP interoperability to make this a relatively
4498+ lightweight process.
4499+4500+9.5.2. JMAP Error Codes Registry Template
4501+4502+ JMAP Error Code:
4503+4504+ Intended use: (one of "common", "limited", "obsolete")
4505+4506+ Change Controller: ("IETF" for Standards Track / BCP RFCs)
4507+4508+ Reference: (Optional. Only required if defined in an RFC.)
4509+4510+ Description:
4511+4512+9.5.3. Initial Contents for the JMAP Error Codes Registry
4513+4514+ o JMAP Error Code: accountNotFound
4515+ Intended Use: Common
4516+ Change Controller: IETF
4517+ Reference: RFC 8620, Section 3.6.2
4518+ Description: The accountId does not correspond to a valid account.
4519+4520+ o JMAP Error Code: accountNotSupportedByMethod
4521+ Intended Use: Common
4522+ Change Controller: IETF
4523+ Reference: RFC 8620, Section 3.6.2
4524+ Description: The accountId given corresponds to a valid account,
4525+ but the account does not support this method or data type.
4526+4527+ o JMAP Error Code: accountReadOnly
4528+ Intended Use: Common
4529+ Change Controller: IETF
4530+ Reference: RFC 8620, Section 3.6.2
4531+ Description: This method modifies state, but the account is read-
4532+ only (as returned on the corresponding Account object in the JMAP
4533+ Session resource).
4534+4535+4536+4537+4538+Jenkins & Newman Standards Track [Page 81]
4539+4540+RFC 8620 JMAP July 2019
4541+4542+4543+ o JMAP Error Code: anchorNotFound
4544+ Intended Use: Common
4545+ Change Controller: IETF
4546+ Reference: RFC 8620, Section 5.5
4547+ Description: An anchor argument was supplied, but it cannot be
4548+ found in the results of the query.
4549+4550+ o JMAP Error Code: alreadyExists
4551+ Intended Use: Common
4552+ Change Controller: IETF
4553+ Reference: RFC 8620, Section 5.4
4554+ Description: The server forbids duplicates, and the record already
4555+ exists in the target account. An existingId property of type Id
4556+ MUST be included on the SetError object with the id of the
4557+ existing record.
4558+4559+ o JMAP Error Code: cannotCalculateChanges
4560+ Intended Use: Common
4561+ Change Controller: IETF
4562+ Reference: RFC 8620, Sections 5.2 and 5.6
4563+ Description: The server cannot calculate the changes from the
4564+ state string given by the client.
4565+4566+ o JMAP Error Code: forbidden
4567+ Intended Use: Common
4568+ Change Controller: IETF
4569+ Reference: RFC 8620, Sections 3.6.2, 5.3, and 7.2.1
4570+ Description: The action would violate an ACL or other permissions
4571+ policy.
4572+4573+ o JMAP Error Code: fromAccountNotFound
4574+ Intended Use: Common
4575+ Change Controller: IETF
4576+ Reference: RFC 8620, Sections 5.4 and 6.3
4577+ Description: The fromAccountId does not correspond to a valid
4578+ account.
4579+4580+ o JMAP Error Code: fromAccountNotSupportedByMethod
4581+ Intended Use: Common
4582+ Change Controller: IETF
4583+ Reference: RFC 8620, Section 5.4
4584+ Description: The fromAccountId given corresponds to a valid
4585+ account, but the account does not support this data type.
4586+4587+4588+4589+4590+4591+4592+4593+4594+Jenkins & Newman Standards Track [Page 82]
4595+4596+RFC 8620 JMAP July 2019
4597+4598+4599+ o JMAP Error Code: invalidArguments
4600+ Intended Use: Common
4601+ Change Controller: IETF
4602+ Reference: RFC 8620, Section 3.6.2
4603+ Description: One of the arguments is of the wrong type or
4604+ otherwise invalid, or a required argument is missing.
4605+4606+ o JMAP Error Code: invalidPatch
4607+ Intended Use: Common
4608+ Change Controller: IETF
4609+ Reference: RFC 8620, Section 5.3
4610+ Description: The PatchObject given to update the record was not a
4611+ valid patch.
4612+4613+ o JMAP Error Code: invalidProperties
4614+ Intended Use: Common
4615+ Change Controller: IETF
4616+ Reference: RFC 8620, Section 5.3
4617+ Description: The record given is invalid.
4618+4619+ o JMAP Error Code: notFound
4620+ Intended Use: Common
4621+ Change Controller: IETF
4622+ Reference: RFC 8620, Section 5.3
4623+ Description: The id given cannot be found.
4624+4625+ o JMAP Error Code: notJSON
4626+ Intended Use: Common
4627+ Change Controller: IETF
4628+ Reference: RFC 8620, Section 3.6.1
4629+ Description: The content type of the request was not application/
4630+ json, or the request did not parse as I-JSON.
4631+4632+ o JMAP Error Code: notRequest
4633+ Intended Use: Common
4634+ Change Controller: IETF
4635+ Reference: RFC 8620, Section 3.6.1
4636+ Description: The request parsed as JSON but did not match the type
4637+ signature of the Request object.
4638+4639+ o JMAP Error Code: overQuota
4640+ Intended Use: Common
4641+ Change Controller: IETF
4642+ Reference: RFC 8620, Section 5.3
4643+ Description: The create would exceed a server-defined limit on the
4644+ number or total size of objects of this type.
4645+4646+4647+4648+4649+4650+Jenkins & Newman Standards Track [Page 83]
4651+4652+RFC 8620 JMAP July 2019
4653+4654+4655+ o JMAP Error Code: rateLimit
4656+ Intended Use: Common
4657+ Change Controller: IETF
4658+ Reference: RFC 8620, Section 5.3
4659+ Description: Too many objects of this type have been created
4660+ recently, and a server-defined rate limit has been reached. It
4661+ may work if tried again later.
4662+4663+ o JMAP Error Code: requestTooLarge
4664+ Intended Use: Common
4665+ Change Controller: IETF
4666+ Reference: RFC 8620, Sections 5.1 and 5.3
4667+ Description: The total number of actions exceeds the maximum
4668+ number the server is willing to process in a single method call.
4669+4670+ o JMAP Error Code: invalidResultReference
4671+ Intended Use: Common
4672+ Change Controller: IETF
4673+ Reference: RFC 8620, Section 3.6.2
4674+ Description: The method used a result reference for one of its
4675+ arguments, but this failed to resolve.
4676+4677+ o JMAP Error Code: serverFail
4678+ Intended Use: Common
4679+ Change Controller: IETF
4680+ Reference: RFC 8620, Section 3.6.2
4681+ Description: An unexpected or unknown error occurred during the
4682+ processing of the call. The method call made no changes to the
4683+ server's state.
4684+4685+ o JMAP Error Code: serverPartialFail
4686+ Intended Use: Limited
4687+ Change Controller: IETF
4688+ Reference: RFC 8620, Section 3.6.2
4689+ Description: Some, but not all, expected changes described by the
4690+ method occurred. The client MUST resynchronise impacted data to
4691+ determine the server state. Use of this error is strongly
4692+ discouraged.
4693+4694+ o JMAP Error Code: serverUnavailable
4695+ Intended Use: Common
4696+ Change Controller: IETF
4697+ Reference: RFC 8620, Section 3.6.2
4698+ Description: Some internal server resource was temporarily
4699+ unavailable. Attempting the same operation later (perhaps after a
4700+ backoff with a random factor) may succeed.
4701+4702+4703+4704+4705+4706+Jenkins & Newman Standards Track [Page 84]
4707+4708+RFC 8620 JMAP July 2019
4709+4710+4711+ o JMAP Error Code: singleton
4712+ Intended Use: Common
4713+ Change Controller: IETF
4714+ Reference: RFC 8620, Section 5.3
4715+ Description: This is a singleton type, so you cannot create
4716+ another one or destroy the existing one.
4717+4718+ o JMAP Error Code: stateMismatch
4719+ Intended Use: Common
4720+ Change Controller: IETF
4721+ Reference: RFC 8620, Section 5.3
4722+ Description: An ifInState argument was supplied, and it does not
4723+ match the current state.
4724+4725+ o JMAP Error Code: tooLarge
4726+ Intended Use: Common
4727+ Change Controller: IETF
4728+ Reference: RFC 8620, Section 5.3
4729+ Description: The action would result in an object that exceeds a
4730+ server-defined limit for the maximum size of a single object of
4731+ this type.
4732+4733+ o JMAP Error Code: tooManyChanges
4734+ Intended Use: Common
4735+ Change Controller: IETF
4736+ Reference: RFC 8620, Section 5.6
4737+ Description: There are more changes than the client's maxChanges
4738+ argument.
4739+4740+ o JMAP Error Code: unknownCapability
4741+ Intended Use: Common
4742+ Change Controller: IETF
4743+ Reference: RFC 8620, Section 3.6.1
4744+ Description: The client included a capability in the "using"
4745+ property of the request that the server does not support.
4746+4747+ o JMAP Error Code: unknownMethod
4748+ Intended Use: Common
4749+ Change Controller: IETF
4750+ Reference: RFC 8620, Section 3.6.2
4751+ Description: The server does not recognise this method name.
4752+4753+ o JMAP Error Code: unsupportedFilter
4754+ Intended Use: Common
4755+ Change Controller: IETF
4756+ Reference: RFC 8620, Section 5.5
4757+ Description: The filter is syntactically valid, but the server
4758+ cannot process it.
4759+4760+4761+4762+Jenkins & Newman Standards Track [Page 85]
4763+4764+RFC 8620 JMAP July 2019
4765+4766+4767+ o JMAP Error Code: unsupportedSort
4768+ Intended Use: Common
4769+ Change Controller: IETF
4770+ Reference: RFC 8620, Section 5.5
4771+ Description: The sort is syntactically valid but includes a
4772+ property the server does not support sorting on or a collation
4773+ method it does not recognise.
4774+4775+ o JMAP Error Code: willDestroy
4776+ Intended Use: Common
4777+ Change Controller: IETF
4778+ Reference: RFC 8620, Section 5.3
4779+ Description: The client requested an object be both updated and
4780+ destroyed in the same /set request, and the server has decided to
4781+ therefore ignore the update.
4782+4783+10. References
4784+4785+10.1. Normative References
4786+4787+ [EventSource]
4788+ Hickson, I., "Server-Sent Events", World Wide Web
4789+ Consortium Recommendation REC-eventsource-20150203,
4790+ February 2015, <https://www.w3.org/TR/eventsource/>.
4791+4792+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
4793+ Requirement Levels", BCP 14, RFC 2119,
4794+ DOI 10.17487/RFC2119, March 1997,
4795+ <https://www.rfc-editor.org/info/rfc2119>.
4796+4797+ [RFC2782] Gulbrandsen, A., Vixie, P., and L. Esibov, "A DNS RR for
4798+ specifying the location of services (DNS SRV)", RFC 2782,
4799+ DOI 10.17487/RFC2782, February 2000,
4800+ <https://www.rfc-editor.org/info/rfc2782>.
4801+4802+ [RFC2818] Rescorla, E., "HTTP Over TLS", RFC 2818,
4803+ DOI 10.17487/RFC2818, May 2000,
4804+ <https://www.rfc-editor.org/info/rfc2818>.
4805+4806+ [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet:
4807+ Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002,
4808+ <https://www.rfc-editor.org/info/rfc3339>.
4809+4810+ [RFC3553] Mealling, M., Masinter, L., Hardie, T., and G. Klyne, "An
4811+ IETF URN Sub-namespace for Registered Protocol
4812+ Parameters", BCP 73, RFC 3553, DOI 10.17487/RFC3553, June
4813+ 2003, <https://www.rfc-editor.org/info/rfc3553>.
4814+4815+4816+4817+4818+Jenkins & Newman Standards Track [Page 86]
4819+4820+RFC 8620 JMAP July 2019
4821+4822+4823+ [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
4824+ 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November
4825+ 2003, <https://www.rfc-editor.org/info/rfc3629>.
4826+4827+ [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
4828+ Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
4829+ <https://www.rfc-editor.org/info/rfc4648>.
4830+4831+ [RFC4790] Newman, C., Duerst, M., and A. Gulbrandsen, "Internet
4832+ Application Protocol Collation Registry", RFC 4790,
4833+ DOI 10.17487/RFC4790, March 2007,
4834+ <https://www.rfc-editor.org/info/rfc4790>.
4835+4836+ [RFC5051] Crispin, M., "i;unicode-casemap - Simple Unicode Collation
4837+ Algorithm", RFC 5051, DOI 10.17487/RFC5051, October 2007,
4838+ <https://www.rfc-editor.org/info/rfc5051>.
4839+4840+ [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
4841+ (TLS) Protocol Version 1.2", RFC 5246,
4842+ DOI 10.17487/RFC5246, August 2008,
4843+ <https://www.rfc-editor.org/info/rfc5246>.
4844+4845+ [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S.,
4846+ Housley, R., and W. Polk, "Internet X.509 Public Key
4847+ Infrastructure Certificate and Certificate Revocation List
4848+ (CRL) Profile", RFC 5280, DOI 10.17487/RFC5280, May 2008,
4849+ <https://www.rfc-editor.org/info/rfc5280>.
4850+4851+ [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
4852+ DOI 10.17487/RFC5322, October 2008,
4853+ <https://www.rfc-editor.org/info/rfc5322>.
4854+4855+ [RFC6186] Daboo, C., "Use of SRV Records for Locating Email
4856+ Submission/Access Services", RFC 6186,
4857+ DOI 10.17487/RFC6186, March 2011,
4858+ <https://www.rfc-editor.org/info/rfc6186>.
4859+4860+ [RFC6335] Cotton, M., Eggert, L., Touch, J., Westerlund, M., and S.
4861+ Cheshire, "Internet Assigned Numbers Authority (IANA)
4862+ Procedures for the Management of the Service Name and
4863+ Transport Protocol Port Number Registry", BCP 165,
4864+ RFC 6335, DOI 10.17487/RFC6335, August 2011,
4865+ <https://www.rfc-editor.org/info/rfc6335>.
4866+4867+ [RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M.,
4868+ and D. Orchard, "URI Template", RFC 6570,
4869+ DOI 10.17487/RFC6570, March 2012,
4870+ <https://www.rfc-editor.org/info/rfc6570>.
4871+4872+4873+4874+Jenkins & Newman Standards Track [Page 87]
4875+4876+RFC 8620 JMAP July 2019
4877+4878+4879+ [RFC6749] Hardt, D., Ed., "The OAuth 2.0 Authorization Framework",
4880+ RFC 6749, DOI 10.17487/RFC6749, October 2012,
4881+ <https://www.rfc-editor.org/info/rfc6749>.
4882+4883+ [RFC6764] Daboo, C., "Locating Services for Calendaring Extensions
4884+ to WebDAV (CalDAV) and vCard Extensions to WebDAV
4885+ (CardDAV)", RFC 6764, DOI 10.17487/RFC6764, February 2013,
4886+ <https://www.rfc-editor.org/info/rfc6764>.
4887+4888+ [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type
4889+ Specifications and Registration Procedures", BCP 13,
4890+ RFC 6838, DOI 10.17487/RFC6838, January 2013,
4891+ <https://www.rfc-editor.org/info/rfc6838>.
4892+4893+ [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed.,
4894+ "JavaScript Object Notation (JSON) Pointer", RFC 6901,
4895+ DOI 10.17487/RFC6901, April 2013,
4896+ <https://www.rfc-editor.org/info/rfc6901>.
4897+4898+ [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
4899+ Protocol (HTTP/1.1): Message Syntax and Routing",
4900+ RFC 7230, DOI 10.17487/RFC7230, June 2014,
4901+ <https://www.rfc-editor.org/info/rfc7230>.
4902+4903+ [RFC7231] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer
4904+ Protocol (HTTP/1.1): Semantics and Content", RFC 7231,
4905+ DOI 10.17487/RFC7231, June 2014,
4906+ <https://www.rfc-editor.org/info/rfc7231>.
4907+4908+ [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493,
4909+ DOI 10.17487/RFC7493, March 2015,
4910+ <https://www.rfc-editor.org/info/rfc7493>.
4911+4912+ [RFC7525] Sheffer, Y., Holz, R., and P. Saint-Andre,
4913+ "Recommendations for Secure Use of Transport Layer
4914+ Security (TLS) and Datagram Transport Layer Security
4915+ (DTLS)", BCP 195, RFC 7525, DOI 10.17487/RFC7525, May
4916+ 2015, <https://www.rfc-editor.org/info/rfc7525>.
4917+4918+ [RFC7617] Reschke, J., "The 'Basic' HTTP Authentication Scheme",
4919+ RFC 7617, DOI 10.17487/RFC7617, September 2015,
4920+ <https://www.rfc-editor.org/info/rfc7617>.
4921+4922+ [RFC7807] Nottingham, M. and E. Wilde, "Problem Details for HTTP
4923+ APIs", RFC 7807, DOI 10.17487/RFC7807, March 2016,
4924+ <https://www.rfc-editor.org/info/rfc7807>.
4925+4926+4927+4928+4929+4930+Jenkins & Newman Standards Track [Page 88]
4931+4932+RFC 8620 JMAP July 2019
4933+4934+4935+ [RFC8030] Thomson, M., Damaggio, E., and B. Raymor, Ed., "Generic
4936+ Event Delivery Using HTTP Push", RFC 8030,
4937+ DOI 10.17487/RFC8030, December 2016,
4938+ <https://www.rfc-editor.org/info/rfc8030>.
4939+4940+ [RFC8126] Cotton, M., Leiba, B., and T. Narten, "Guidelines for
4941+ Writing an IANA Considerations Section in RFCs", BCP 26,
4942+ RFC 8126, DOI 10.17487/RFC8126, June 2017,
4943+ <https://www.rfc-editor.org/info/rfc8126>.
4944+4945+ [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
4946+ 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
4947+ May 2017, <https://www.rfc-editor.org/info/rfc8174>.
4948+4949+ [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
4950+ Interchange Format", STD 90, RFC 8259,
4951+ DOI 10.17487/RFC8259, December 2017,
4952+ <https://www.rfc-editor.org/info/rfc8259>.
4953+4954+ [RFC8264] Saint-Andre, P. and M. Blanchet, "PRECIS Framework:
4955+ Preparation, Enforcement, and Comparison of
4956+ Internationalized Strings in Application Protocols",
4957+ RFC 8264, DOI 10.17487/RFC8264, October 2017,
4958+ <https://www.rfc-editor.org/info/rfc8264>.
4959+4960+ [RFC8291] Thomson, M., "Message Encryption for Web Push", RFC 8291,
4961+ DOI 10.17487/RFC8291, November 2017,
4962+ <https://www.rfc-editor.org/info/rfc8291>.
4963+4964+ [RFC8446] Rescorla, E., "The Transport Layer Security (TLS) Protocol
4965+ Version 1.3", RFC 8446, DOI 10.17487/RFC8446, August 2018,
4966+ <https://www.rfc-editor.org/info/rfc8446>.
4967+4968+ [RFC8615] Nottingham, M., "Well-Known Uniform Resource Identifiers
4969+ (URIs)", RFC 8615, DOI 10.17487/RFC8615, May 2019,
4970+ <https://www.rfc-editor.org/info/rfc8615>.
4971+4972+10.2. Informative References
4973+4974+ [RFC8246] McManus, P., "HTTP Immutable Responses", RFC 8246,
4975+ DOI 10.17487/RFC8246, September 2017,
4976+ <https://www.rfc-editor.org/info/rfc8246>.
4977+4978+4979+4980+4981+4982+4983+4984+4985+4986+Jenkins & Newman Standards Track [Page 89]
4987+4988+RFC 8620 JMAP July 2019
4989+4990+4991+Authors' Addresses
4992+4993+ Neil Jenkins
4994+ Fastmail
4995+ PO Box 234, Collins St. West
4996+ Melbourne, VIC 8007
4997+ Australia
4998+4999+ Email: neilj@fastmailteam.com
5000+ URI: https://www.fastmail.com
5001+5002+5003+ Chris Newman
5004+ Oracle
5005+ 440 E. Huntington Dr., Suite 400
5006+ Arcadia, CA 91006
5007+ United States of America
5008+5009+ Email: chris.newman@oracle.com
5010+5011+5012+5013+5014+5015+5016+5017+5018+5019+5020+5021+5022+5023+5024+5025+5026+5027+5028+5029+5030+5031+5032+5033+5034+5035+5036+5037+5038+5039+5040+5041+5042+Jenkins & Newman Standards Track [Page 90]
5043+