From 4bfd864f10b68b71482b35c818559068ef8d5797 Mon Sep 17 00:00:00 2001 From: Thomas Voss Date: Wed, 27 Nov 2024 20:54:24 +0100 Subject: doc: Add RFC documents --- doc/rfc/rfc8621.txt | 6051 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 6051 insertions(+) create mode 100644 doc/rfc/rfc8621.txt (limited to 'doc/rfc/rfc8621.txt') diff --git a/doc/rfc/rfc8621.txt b/doc/rfc/rfc8621.txt new file mode 100644 index 0000000..9add50e --- /dev/null +++ b/doc/rfc/rfc8621.txt @@ -0,0 +1,6051 @@ + + + + + + +Internet Engineering Task Force (IETF) N. Jenkins +Request for Comments: 8621 Fastmail +Updates: 5788 C. Newman +Category: Standards Track Oracle +ISSN: 2070-1721 August 2019 + + + The JSON Meta Application Protocol (JMAP) for Mail + +Abstract + + This document specifies a data model for synchronising email data + with a server using the JSON Meta Application Protocol (JMAP). + Clients can use this to efficiently search, access, organise, and + send messages, and to get push notifications for fast + resynchronisation when new messages are delivered or a change is made + in another client. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 7841. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + https://www.rfc-editor.org/info/rfc8621. + +Copyright Notice + + Copyright (c) 2019 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (https://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + +Jenkins & Newman Standards Track [Page 1] + +RFC 8621 JMAP Mail August 2019 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 4 + 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.3. Additions to the Capabilities Object . . . . . . . . . . 5 + 1.3.1. urn:ietf:params:jmap:mail . . . . . . . . . . . . . . 5 + 1.3.2. urn:ietf:params:jmap:submission . . . . . . . . . . . 7 + 1.3.3. urn:ietf:params:jmap:vacationresponse . . . . . . . . 8 + 1.4. Data Type Support in Different Accounts . . . . . . . . . 8 + 1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 8 + 1.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 9 + 1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 14 + 2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 14 + 2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 14 + 2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 15 + 2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 16 + 2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 17 + 3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 + 3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 22 + 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 22 + 3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 22 + 4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 + 4.1. Properties of the Email Object . . . . . . . . . . . . . 23 + 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 24 + 4.1.2. Header Fields Parsed Forms . . . . . . . . . . . . . 26 + 4.1.3. Header Fields Properties . . . . . . . . . . . . . . 32 + 4.1.4. Body Parts . . . . . . . . . . . . . . . . . . . . . 35 + 4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 42 + 4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 44 + 4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 45 + 4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 45 + 4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 46 + 4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 49 + 4.4.3. Thread Collapsing . . . . . . . . . . . . . . . . . . 50 + 4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 51 + 4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 51 + 4.7. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 53 + 4.8. Email/import . . . . . . . . . . . . . . . . . . . . . . 54 + 4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 56 + 4.10. Examples . . . . . . . . . . . . . . . . . . . . . . . . 58 + 5. Search Snippets . . . . . . . . . . . . . . . . . . . . . . . 68 + 5.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 69 + 5.2. Example . . . . . . . . . . . . . . . . . . . . . . . . . 71 + + + + + +Jenkins & Newman Standards Track [Page 2] + +RFC 8621 JMAP Mail August 2019 + + + 6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 72 + 6.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 73 + 6.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 73 + 6.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 73 + 6.4. Example . . . . . . . . . . . . . . . . . . . . . . . . . 73 + 7. Email Submission . . . . . . . . . . . . . . . . . . . . . . 74 + 7.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 80 + 7.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 80 + 7.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 80 + 7.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 81 + 7.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 81 + 7.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 84 + 8. Vacation Response . . . . . . . . . . . . . . . . . . . . . . 86 + 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 87 + 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 88 + 9. Security Considerations . . . . . . . . . . . . . . . . . . . 88 + 9.1. EmailBodyPart Value . . . . . . . . . . . . . . . . . . . 88 + 9.2. HTML Email Display . . . . . . . . . . . . . . . . . . . 88 + 9.3. Multiple Part Display . . . . . . . . . . . . . . . . . . 91 + 9.4. Email Submission . . . . . . . . . . . . . . . . . . . . 91 + 9.5. Partial Account Access . . . . . . . . . . . . . . . . . 92 + 9.6. Permission to Send from an Address . . . . . . . . . . . 92 + 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 93 + 10.1. JMAP Capability Registration for "mail" . . . . . . . . 93 + 10.2. JMAP Capability Registration for "submission" . . . . . 93 + 10.3. JMAP Capability Registration for "vacationresponse" . . 94 + 10.4. IMAP and JMAP Keywords Registry . . . . . . . . . . . . 94 + 10.4.1. Registration of JMAP Keyword "$draft" . . . . . . . 95 + 10.4.2. Registration of JMAP Keyword "$seen" . . . . . . . . 96 + 10.4.3. Registration of JMAP Keyword "$flagged" . . . . . . 97 + 10.4.4. Registration of JMAP Keyword "$answered" . . . . . . 98 + 10.4.5. Registration of "$recent" Keyword . . . . . . . . . 99 + 10.5. IMAP Mailbox Name Attributes Registry . . . . . . . . . 99 + 10.5.1. Registration of "inbox" Role . . . . . . . . . . . . 99 + 10.6. JMAP Error Codes Registry . . . . . . . . . . . . . . . 100 + 10.6.1. mailboxHasChild . . . . . . . . . . . . . . . . . . 100 + 10.6.2. mailboxHasEmail . . . . . . . . . . . . . . . . . . 100 + 10.6.3. blobNotFound . . . . . . . . . . . . . . . . . . . . 100 + 10.6.4. tooManyKeywords . . . . . . . . . . . . . . . . . . 101 + 10.6.5. tooManyMailboxes . . . . . . . . . . . . . . . . . . 101 + 10.6.6. invalidEmail . . . . . . . . . . . . . . . . . . . . 101 + 10.6.7. tooManyRecipients . . . . . . . . . . . . . . . . . 102 + 10.6.8. noRecipients . . . . . . . . . . . . . . . . . . . . 102 + 10.6.9. invalidRecipients . . . . . . . . . . . . . . . . . 102 + 10.6.10. forbiddenMailFrom . . . . . . . . . . . . . . . . . 103 + 10.6.11. forbiddenFrom . . . . . . . . . . . . . . . . . . . 103 + 10.6.12. forbiddenToSend . . . . . . . . . . . . . . . . . . 103 + + + + +Jenkins & Newman Standards Track [Page 3] + +RFC 8621 JMAP Mail August 2019 + + + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 104 + 11.1. Normative References . . . . . . . . . . . . . . . . . . 104 + 11.2. Informative References . . . . . . . . . . . . . . . . . 107 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 108 + +1. Introduction + + The JSON Meta Application Protocol (JMAP) [RFC8620] is a generic + protocol for synchronising data, such as mail, calendars, or contacts + between a client and a server. It is optimised for mobile and web + environments and aims to provide a consistent interface to different + data types. + + This specification defines a data model for accessing a mail store + over JMAP, allowing you to query, read, organise, and submit mail for + sending. + + The data model is designed to allow a server to provide consistent + access to the same data via IMAP [RFC3501] as well as JMAP. As in + IMAP, a message must belong to a mailbox; however, in JMAP, its id + does not change if you move it between mailboxes, and the server may + allow it to belong to multiple mailboxes simultaneously (often + exposed in a user agent as labels rather than folders). + + As in IMAP, messages may also be assigned zero or more keywords: + short arbitrary strings. These are primarily intended to store + metadata to inform client display, such as unread status or whether a + message has been replied to. An IANA registry allows common + semantics to be shared between clients and extended easily in the + future. + + A message and its replies are linked on the server by a common Thread + id. Clients may fetch the list of messages with a particular Thread + id to more easily present a threaded or conversational interface. + + Permissions for message access happen on a per-mailbox basis. + Servers may give the user restricted permissions for certain + mailboxes, for example, if another user's inbox has been shared as + read-only with them. + +1.1. Notational Conventions + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as described in + BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all + capitals, as shown here. + + + + +Jenkins & Newman Standards Track [Page 4] + +RFC 8621 JMAP Mail August 2019 + + + Type signatures, examples, and property descriptions in this document + follow the conventions established in Section 1.1 of [RFC8620]. Data + types defined in the core specification are also used in this + document. + + Servers MUST support all properties specified for the new data types + defined in this document. + +1.2. Terminology + + This document uses the same terminology as in the core JMAP + specification. + + The terms Mailbox, Thread, Email, SearchSnippet, EmailSubmission and + VacationResponse (with that specific capitalisation) are used to + refer to the data types defined in this document and instances of + those data types. + + The term message refers to a document in Internet Message Format, as + described in [RFC5322]. The Email data type represents messages in + the mail store and associated metadata. + +1.3. Additions to the Capabilities Object + + The capabilities object is returned as part of the JMAP Session + object; see [RFC8620], Section 2. + + This document defines three additional capability URIs. + +1.3.1. urn:ietf:params:jmap:mail + + This represents support for the Mailbox, Thread, Email, and + SearchSnippet data types and associated API methods. The value of + this property in the JMAP session "capabilities" property is an empty + object. + + The value of this property in an account's "accountCapabilities" + property is an object that MUST contain the following information on + server capabilities and permissions for that account: + + o maxMailboxesPerEmail: "UnsignedInt|null" + + The maximum number of Mailboxes (see Section 2) that can be can + assigned to a single Email object (see Section 4). This MUST be + an integer >= 1, or null for no limit (or rather, the limit is + always the number of Mailboxes in the account). + + + + + +Jenkins & Newman Standards Track [Page 5] + +RFC 8621 JMAP Mail August 2019 + + + o maxMailboxDepth: "UnsignedInt|null" + + The maximum depth of the Mailbox hierarchy (i.e., one more than + the maximum number of ancestors a Mailbox may have), or null for + no limit. + + o maxSizeMailboxName: "UnsignedInt" + + The maximum length, in (UTF-8) octets, allowed for the name of a + Mailbox. This MUST be at least 100, although it is recommended + servers allow more. + + o maxSizeAttachmentsPerEmail: "UnsignedInt" + + The maximum total size of attachments, in octets, allowed for a + single Email object. A server MAY still reject the import or + creation of an Email with a lower attachment size total (for + example, if the body includes several megabytes of text, causing + the size of the encoded MIME structure to be over some server- + defined limit). + + Note that this limit is for the sum of unencoded attachment sizes. + Users are generally not knowledgeable about encoding overhead, + etc., nor should they need to be, so marketing and help materials + normally tell them the "max size attachments". This is the + unencoded size they see on their hard drive, so this capability + matches that and allows the client to consistently enforce what + the user understands as the limit. + + The server may separately have a limit for the total size of the + message [RFC5322], created by combining the attachments (often + base64 encoded) with the message headers and bodies. For example, + suppose the server advertises "maxSizeAttachmentsPerEmail: + 50000000" (50 MB). The enforced server limit may be for a message + size of 70000000 octets. Even with base64 encoding and a 2 MB + HTML body, 50 MB attachments would fit under this limit. + + o emailQuerySortOptions: "String[]" + + A list of all the values the server supports for the "property" + field of the Comparator object in an "Email/query" sort (see + Section 4.4.2). This MAY include properties the client does not + recognise (for example, custom properties specified in a vendor + extension). Clients MUST ignore any unknown properties in the + list. + + + + + + +Jenkins & Newman Standards Track [Page 6] + +RFC 8621 JMAP Mail August 2019 + + + o mayCreateTopLevelMailbox: "Boolean" + + If true, the user may create a Mailbox (see Section 2) in this + account with a null parentId. (Permission for creating a child of + an existing Mailbox is given by the "myRights" property on that + Mailbox.) + +1.3.2. urn:ietf:params:jmap:submission + + This represents support for the Identity and EmailSubmission data + types and associated API methods. The value of this property in the + JMAP session "capabilities" property is an empty object. + + The value of this property in an account's "accountCapabilities" + property is an object that MUST contain the following information on + server capabilities and permissions for that account: + + o maxDelayedSend: "UnsignedInt" + + The number in seconds of the maximum delay the server supports in + sending (see the EmailSubmission object description). This is 0 + if the server does not support delayed send. + + o submissionExtensions: "String[String[]]" + + The set of SMTP submission extensions supported by the server, + which the client may use when creating an EmailSubmission object + (see Section 7). Each key in the object is the "ehlo-name", and + the value is a list of "ehlo-args". + + A JMAP implementation that talks to a submission server [RFC6409] + SHOULD have a configuration setting that allows an administrator + to modify the set of submission EHLO capabilities it may expose on + this property. This allows a JMAP server to easily add access to + a new submission extension without code changes. By default, the + JMAP server should hide EHLO capabilities that have to do with the + transport mechanism and thus are only relevant to the JMAP server + (for example, PIPELINING, CHUNKING, or STARTTLS). + + Examples of Submission extensions to include: + + * FUTURERELEASE [RFC4865] + + * SIZE [RFC1870] + + * DSN [RFC3461] + + * DELIVERYBY [RFC2852] + + + +Jenkins & Newman Standards Track [Page 7] + +RFC 8621 JMAP Mail August 2019 + + + * MT-PRIORITY [RFC6710] + + A JMAP server MAY advertise an extension and implement the + semantics of that extension locally on the JMAP server even if a + submission server used by JMAP doesn't implement it. + + The full IANA registry of submission extensions can be found at + . + +1.3.3. urn:ietf:params:jmap:vacationresponse + + This represents support for the VacationResponse data type and + associated API methods. The value of this property is an empty + object in both the JMAP session "capabilities" property and an + account's "accountCapabilities" property. + +1.4. Data Type Support in Different Accounts + + The server MUST include the appropriate capability strings as keys in + the "accountCapabilities" property of any account with which the user + may use the data types represented by that URI. Supported data types + may differ between accounts the user has access to. For example, in + the user's personal account, they may have access to all three sets + of data, but in a shared account, they may only have data for + "urn:ietf:params:jmap:mail". This means they can access + Mailbox/Thread/Email data in the shared account but are not allowed + to send as that account (and so do not have access to Identity/ + EmailSubmission objects) or view/set its VacationResponse. + +1.5. Push + + Servers MUST support the JMAP push mechanisms, as specified in + [RFC8620], Section 7, to receive notifications when the state changes + for any of the types defined in this specification. + + In addition, servers that implement the "urn:ietf:params:jmap:mail" + capability MUST support pushing state changes for a type called + "EmailDelivery". There are no methods to act on this type; it only + exists as part of the push mechanism. The state string for this MUST + change whenever a new Email is added to the store, but it SHOULD NOT + change upon any other change to the Email objects, for example, if + one is marked as read or deleted. + + Clients in battery-constrained environments may wish to delay + fetching changes initiated by the user but fetch new Emails + immediately so they can notify the user. To do this, they can + register for pushes for the EmailDelivery type rather than the Email + type (as defined in Section 4). + + + +Jenkins & Newman Standards Track [Page 8] + +RFC 8621 JMAP Mail August 2019 + + +1.5.1. Example + + The client has registered for push notifications (see [RFC8620]) just + for the EmailDelivery type. The user marks an Email as read on + another device, causing the state string for the Email type to + change; however, as nothing new was added to the store, the + EmailDelivery state does not change and nothing is pushed to the + client. A new message arrives in the user's inbox, again causing the + Email state to change. This time, the EmailDelivery state also + changes, and a StateChange object is pushed to the client with the + new state string. The client may then resync to fetch the new Email + immediately. + +1.6. Ids + + If a JMAP Mail server also provides an IMAP interface to the data and + supports IMAP Extension for Object Identifiers [RFC8474], the ids + SHOULD be the same for Mailbox, Thread, and Email objects in JMAP. + +2. Mailboxes + + A Mailbox represents a named set of Email objects. This is the + primary mechanism for organising messages within an account. It is + analogous to a folder or a label in other systems. A Mailbox may + perform a certain role in the system; see below for more details. + + For compatibility with IMAP, an Email MUST belong to one or more + Mailboxes. The Email id does not change if the Email changes + Mailboxes. + + A *Mailbox* object has the following properties: + + o id: "Id" (immutable; server-set) + + The id of the Mailbox. + + o name: "String" + + User-visible name for the Mailbox, e.g., "Inbox". This MUST be a + Net-Unicode string [RFC5198] of at least 1 character in length, + subject to the maximum size given in the capability object. There + MUST NOT be two sibling Mailboxes with both the same parent and + the same name. Servers MAY reject names that violate server + policy (e.g., names containing a slash (/) or control characters). + + + + + + + +Jenkins & Newman Standards Track [Page 9] + +RFC 8621 JMAP Mail August 2019 + + + o parentId: "Id|null" (default: null) + + The Mailbox id for the parent of this Mailbox, or null if this + Mailbox is at the top level. Mailboxes form acyclic graphs + (forests) directed by the child-to-parent relationship. There + MUST NOT be a loop. + + o role: "String|null" (default: null) + + Identifies Mailboxes that have a particular common purpose (e.g., + the "inbox"), regardless of the "name" property (which may be + localised). + + This value is shared with IMAP (exposed in IMAP via the SPECIAL- + USE extension [RFC6154]). However, unlike in IMAP, a Mailbox MUST + only have a single role, and there MUST NOT be two Mailboxes in + the same account with the same role. Servers providing IMAP + access to the same data are encouraged to enforce these extra + restrictions in IMAP as well. Otherwise, modifying the IMAP + attributes to ensure compliance when exposing the data over JMAP + is implementation dependent. + + The value MUST be one of the Mailbox attribute names listed in the + IANA "IMAP Mailbox Name Attributes" registry at + , + as established in [RFC8457], converted to lowercase. New roles + may be established here in the future. + + An account is not required to have Mailboxes with any particular + roles. + + o sortOrder: "UnsignedInt" (default: 0) + + Defines the sort order of Mailboxes when presented in the client's + UI, so it is consistent between devices. The number MUST be an + integer in the range 0 <= sortOrder < 2^31. + + A Mailbox with a lower order should be displayed before a Mailbox + with a higher order (that has the same parent) in any Mailbox + listing in the client's UI. Mailboxes with equal order SHOULD be + sorted in alphabetical order by name. The sorting should take + into account locale-specific character order convention. + + o totalEmails: "UnsignedInt" (server-set) + + The number of Emails in this Mailbox. + + + + + +Jenkins & Newman Standards Track [Page 10] + +RFC 8621 JMAP Mail August 2019 + + + o unreadEmails: "UnsignedInt" (server-set) + + The number of Emails in this Mailbox that have neither the "$seen" + keyword nor the "$draft" keyword. + + o totalThreads: "UnsignedInt" (server-set) + + The number of Threads where at least one Email in the Thread is in + this Mailbox. + + o unreadThreads: "UnsignedInt" (server-set) + + An indication of the number of "unread" Threads in the Mailbox. + + For compatibility with existing implementations, the way "unread + Threads" is determined is not mandated in this document. The + simplest solution to implement is simply the number of Threads + where at least one Email in the Thread is both in this Mailbox and + has neither the "$seen" nor "$draft" keywords. + + However, a quality implementation will return the number of unread + items the user would see if they opened that Mailbox. A Thread is + shown as unread if it contains any unread Emails that will be + displayed when the Thread is opened. Therefore, "unreadThreads" + should be the number of Threads where at least one Email in the + Thread has neither the "$seen" nor the "$draft" keyword AND at + least one Email in the Thread is in this Mailbox. Note that the + unread Email does not need to be the one in this Mailbox. In + addition, the trash Mailbox (that is, a Mailbox whose "role" is + "trash") requires special treatment: + + 1. Emails that are *only* in the trash (and no other Mailbox) are + ignored when calculating the "unreadThreads" count of other + Mailboxes. + + 2. Emails that are *not* in the trash are ignored when + calculating the "unreadThreads" count for the trash Mailbox. + + The result of this is that Emails in the trash are treated as + though they are in a separate Thread for the purposes of unread + counts. It is expected that clients will hide Emails in the trash + when viewing a Thread in another Mailbox, and vice versa. This + allows you to delete a single Email to the trash out of a Thread. + + For example, suppose you have an account where the entire contents + is a single Thread with 2 Emails: an unread Email in the trash and + a read Email in the inbox. The "unreadThreads" count would be 1 + for the trash and 0 for the inbox. + + + +Jenkins & Newman Standards Track [Page 11] + +RFC 8621 JMAP Mail August 2019 + + + o myRights: "MailboxRights" (server-set) + + The set of rights (Access Control Lists (ACLs)) the user has in + relation to this Mailbox. These are backwards compatible with + IMAP ACLs, as defined in [RFC4314]. A *MailboxRights* object has + the following properties: + + * mayReadItems: "Boolean" + + If true, the user may use this Mailbox as part of a filter in + an "Email/query" call, and the Mailbox may be included in the + "mailboxIds" property of Email objects. Email objects may be + fetched if they are in *at least one* Mailbox with this + permission. If a sub-Mailbox is shared but not the parent + Mailbox, this may be false. Corresponds to IMAP ACLs "lr" (if + mapping from IMAP, both are required for this to be true). + + * mayAddItems: "Boolean" + + The user may add mail to this Mailbox (by either creating a new + Email or moving an existing one). Corresponds to IMAP ACL "i". + + * mayRemoveItems: "Boolean" + + The user may remove mail from this Mailbox (by either changing + the Mailboxes of an Email or destroying the Email). + Corresponds to IMAP ACLs "te" (if mapping from IMAP, both are + required for this to be true). + + * maySetSeen: "Boolean" + + The user may add or remove the "$seen" keyword to/from an + Email. If an Email belongs to multiple Mailboxes, the user may + only modify "$seen" if they have this permission for *all* of + the Mailboxes. Corresponds to IMAP ACL "s". + + * maySetKeywords: "Boolean" + + The user may add or remove any keyword other than "$seen" to/ + from an Email. If an Email belongs to multiple Mailboxes, the + user may only modify keywords if they have this permission for + *all* of the Mailboxes. Corresponds to IMAP ACL "w". + + * mayCreateChild: "Boolean" + + The user may create a Mailbox with this Mailbox as its parent. + Corresponds to IMAP ACL "k". + + + + +Jenkins & Newman Standards Track [Page 12] + +RFC 8621 JMAP Mail August 2019 + + + * mayRename: "Boolean" + + The user may rename the Mailbox or make it a child of another + Mailbox. Corresponds to IMAP ACL "x" (although this covers + both rename and delete permissions). + + * mayDelete: "Boolean" + + The user may delete the Mailbox itself. Corresponds to IMAP + ACL "x" (although this covers both rename and delete + permissions). + + * maySubmit: "Boolean" + + Messages may be submitted directly to this Mailbox. + Corresponds to IMAP ACL "p". + + o isSubscribed: "Boolean" + + Has the user indicated they wish to see this Mailbox in their + client? This SHOULD default to false for Mailboxes in shared + accounts the user has access to and true for any new Mailboxes + created by the user themself. This MUST be stored separately per + user where multiple users have access to a shared Mailbox. + + A user may have permission to access a large number of shared + accounts, or a shared account with a very large set of Mailboxes, + but only be interested in the contents of a few of these. Clients + may choose to only display Mailboxes where the "isSubscribed" + property is set to true, and offer a separate UI to allow the user + to see and subscribe/unsubscribe from the full set of Mailboxes. + However, clients MAY choose to ignore this property, either + entirely for ease of implementation or just for an account where + "isPersonal" is true (indicating it is the user's own rather than + a shared account). + + This property corresponds to IMAP [RFC3501] mailbox subscriptions. + + For IMAP compatibility, an Email in both the trash and another + Mailbox SHOULD be treated by the client as existing in both places + (i.e., when emptying the trash, the client should just remove it from + the trash Mailbox and leave it in the other Mailbox). + + The following JMAP methods are supported. + + + + + + + +Jenkins & Newman Standards Track [Page 13] + +RFC 8621 JMAP Mail August 2019 + + +2.1. Mailbox/get + + This is a standard "/get" method as described in [RFC8620], + Section 5.1. The "ids" argument may be "null" to fetch all at once. + +2.2. Mailbox/changes + + This is a standard "/changes" method as described in [RFC8620], + Section 5.2 but with one extra argument to the response: + + o updatedProperties: "String[]|null" + + If only the "totalEmails", "unreadEmails", "totalThreads", and/or + "unreadThreads" Mailbox properties have changed since the old + state, this will be the list of properties that may have changed. + If the server is unable to tell if only counts have changed, it + MUST just be null. + + Since counts frequently change but other properties are generally + only changed rarely, the server can help the client optimise data + transfer by keeping track of changes to Email/Thread counts separate + from other state changes. The "updatedProperties" array may be used + directly via a back-reference in a subsequent "Mailbox/get" call in + the same request, so only these properties are returned if nothing + else has changed. + +2.3. Mailbox/query + + This is a standard "/query" method as described in [RFC8620], + Section 5.5 but with the following additional request argument: + + o sortAsTree: "Boolean" (default: false) + + If true, when sorting the query results and comparing Mailboxes A + and B: + + * If A is an ancestor of B, it always comes first regardless of + the sort comparators. Similarly, if A is descendant of B, then + B always comes first. + + * Otherwise, if A and B do not share a "parentId", find the + nearest ancestors of each that do have the same "parentId" and + compare the sort properties on those Mailboxes instead. + + The result of this is that the Mailboxes are sorted as a tree + according to the parentId properties, with each set of children + with a common parent sorted according to the standard sort + comparators. + + + +Jenkins & Newman Standards Track [Page 14] + +RFC 8621 JMAP Mail August 2019 + + + o filterAsTree: "Boolean" (default: false) + + If true, a Mailbox is only included in the query if all its + ancestors are also included in the query according to the filter. + + A *FilterCondition* object has the following properties, any of which + may be omitted: + + o parentId: "Id|null" + + The Mailbox "parentId" property must match the given value + exactly. + + o name: "String" + + The Mailbox "name" property contains the given string. + + o role: "String|null" + + The Mailbox "role" property must match the given value exactly. + + o hasAnyRole: "Boolean" + + If true, a Mailbox matches if it has any non-null value for its + "role" property. + + o isSubscribed: "Boolean" + + The "isSubscribed" property of the Mailbox must be identical to + the value given to match the condition. + + A Mailbox object matches the FilterCondition if and only if all of + the given conditions match. If zero properties are specified, it is + automatically true for all objects. + + The following Mailbox properties MUST be supported for sorting: + + o "sortOrder" + + o "name" + +2.4. Mailbox/queryChanges + + This is a standard "/queryChanges" method as described in [RFC8620], + Section 5.6. + + + + + + +Jenkins & Newman Standards Track [Page 15] + +RFC 8621 JMAP Mail August 2019 + + +2.5. Mailbox/set + + This is a standard "/set" method as described in [RFC8620], + Section 5.3 but with the following additional request argument: + + o onDestroyRemoveEmails: "Boolean" (default: false) + + If false, any attempt to destroy a Mailbox that still has Emails + in it will be rejected with a "mailboxHasEmail" SetError. If + true, any Emails that were in the Mailbox will be removed from it, + and if in no other Mailboxes, they will be destroyed when the + Mailbox is destroyed. + + The following extra SetError types are defined: + + For "destroy": + + o "mailboxHasChild": The Mailbox still has at least one child + Mailbox. The client MUST remove these before it can delete the + parent Mailbox. + + o "mailboxHasEmail": The Mailbox has at least one Email assigned to + it, and the "onDestroyRemoveEmails" argument was false. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 16] + +RFC 8621 JMAP Mail August 2019 + + +2.6. Example + + Fetching all Mailboxes in an account: + + [[ "Mailbox/get", { + "accountId": "u33084183", + "ids": null + }, "0" ]] + + And the response: + + [[ "Mailbox/get", { + "accountId": "u33084183", + "state": "78540", + "list": [{ + "id": "MB23cfa8094c0f41e6", + "name": "Inbox", + "parentId": null, + "role": "inbox", + "sortOrder": 10, + "totalEmails": 16307, + "unreadEmails": 13905, + "totalThreads": 5833, + "unreadThreads": 5128, + "myRights": { + "mayAddItems": true, + "mayRename": false, + "maySubmit": true, + "mayDelete": false, + "maySetKeywords": true, + "mayRemoveItems": true, + "mayCreateChild": true, + "maySetSeen": true, + "mayReadItems": true + }, + "isSubscribed": true + }, { + "id": "MB674cc24095db49ce", + "name": "Important mail", + ... + }, ... ], + "notFound": [] + }, "0" ]] + + + + + + + + +Jenkins & Newman Standards Track [Page 17] + +RFC 8621 JMAP Mail August 2019 + + + Now suppose an Email is marked read, and we get a push update that + the Mailbox state has changed. You might fetch the updates like + this: + + [[ "Mailbox/changes", { + "accountId": "u33084183", + "sinceState": "78540" + }, "0" ], + [ "Mailbox/get", { + "accountId": "u33084183", + "#ids": { + "resultOf": "0", + "name": "Mailbox/changes", + "path": "/created" + } + }, "1" ], + [ "Mailbox/get", { + "accountId": "u33084183", + "#ids": { + "resultOf": "0", + "name": "Mailbox/changes", + "path": "/updated" + }, + "#properties": { + "resultOf": "0", + "name": "Mailbox/changes", + "path": "/updatedProperties" + } + }, "2" ]] + + + + + + + + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 18] + +RFC 8621 JMAP Mail August 2019 + + + This fetches the list of ids for created/updated/destroyed Mailboxes, + then using back-references, it fetches the data for just the created/ + updated Mailboxes in the same request. The response may look + something like this: + + [[ "Mailbox/changes", { + "accountId": "u33084183", + "oldState": "78541", + "newState": "78542", + "hasMoreChanges": false, + "updatedProperties": [ + "totalEmails", "unreadEmails", + "totalThreads", "unreadThreads" + ], + "created": [], + "updated": ["MB23cfa8094c0f41e6"], + "destroyed": [] + }, "0" ], + [ "Mailbox/get", { + "accountId": "u33084183", + "state": "78542", + "list": [], + "notFound": [] + }, "1" ], + [ "Mailbox/get", { + "accountId": "u33084183", + "state": "78542", + "list": [{ + "id": "MB23cfa8094c0f41e6", + "totalEmails": 16307, + "unreadEmails": 13903, + "totalThreads": 5833, + "unreadThreads": 5127 + }], + "notFound": [] + }, "2" ]] + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 19] + +RFC 8621 JMAP Mail August 2019 + + + Here's an example where we try to rename one Mailbox and destroy + another: + + [[ "Mailbox/set", { + "accountId": "u33084183", + "ifInState": "78542", + "update": { + "MB674cc24095db49ce": { + "name": "Maybe important mail" + } + }, + "destroy": [ "MB23cfa8094c0f41e6" ] + }, "0" ]] + + Suppose the rename succeeds, but we don't have permission to destroy + the Mailbox we tried to destroy; we might get back: + + [[ "Mailbox/set", { + "accountId": "u33084183", + "oldState": "78542", + "newState": "78549", + "updated": { + "MB674cc24095db49ce": null + }, + "notDestroyed": { + "MB23cfa8094c0f41e6": { + "type": "forbidden" + } + } + }, "0" ]] + +3. Threads + + Replies are grouped together with the original message to form a + Thread. In JMAP, a Thread is simply a flat list of Emails, ordered + by date. Every Email MUST belong to a Thread, even if it is the only + Email in the Thread. + + The exact algorithm for determining whether two Emails belong to the + same Thread is not mandated in this spec to allow for compatibility + with different existing systems. For new implementations, it is + suggested that two messages belong in the same Thread if both of the + following conditions apply: + + 1. An identical message id [RFC5322] appears in both messages in any + of the Message-Id, In-Reply-To, and References header fields. + + + + + +Jenkins & Newman Standards Track [Page 20] + +RFC 8621 JMAP Mail August 2019 + + + 2. After stripping automatically added prefixes such as "Fwd:", + "Re:", "[List-Tag]", etc., and ignoring white space, the subjects + are the same. This avoids the situation where a person replies + to an old message as a convenient way of finding the right + recipient to send to but changes the subject and starts a new + conversation. + + If messages are delivered out of order for some reason, a user may + have two Emails in the same Thread but without headers that associate + them with each other. The arrival of a third Email may provide the + missing references to join them all together into a single Thread. + Since the "threadId" of an Email is immutable, if the server wishes + to merge the Threads, it MUST handle this by deleting and reinserting + (with a new Email id) the Emails that change "threadId". + + A *Thread* object has the following properties: + + o id: "Id" (immutable; server-set) + + + The id of the Thread. + + o emailIds: "Id[]" (server-set) + + The ids of the Emails in the Thread, sorted by the "receivedAt" + date of the Email, oldest first. If two Emails have an identical + date, the sort is server dependent but MUST be stable (sorting by + id is recommended). + + The following JMAP methods are supported. + + + + + + + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 21] + +RFC 8621 JMAP Mail August 2019 + + +3.1. Thread/get + + This is a standard "/get" method as described in [RFC8620], + Section 5.1. + +3.1.1. Example + + Request: + + [[ "Thread/get", { + "accountId": "acme", + "ids": ["f123u4", "f41u44"] + }, "#1" ]] + + with response: + + [[ "Thread/get", { + "accountId": "acme", + "state": "f6a7e214", + "list": [ + { + "id": "f123u4", + "emailIds": [ "eaa623", "f782cbb"] + }, + { + "id": "f41u44", + "emailIds": [ "82cf7bb" ] + } + ], + "notFound": [] + }, "#1" ]] + +3.2. Thread/changes + + This is a standard "/changes" method as described in [RFC8620], + Section 5.2. + +4. Emails + + An *Email* object is a representation of a message [RFC5322], which + allows clients to avoid the complexities of MIME parsing, transfer + encoding, and character encoding. + + + + + + + + + +Jenkins & Newman Standards Track [Page 22] + +RFC 8621 JMAP Mail August 2019 + + +4.1. Properties of the Email Object + + Broadly, a message consists of two parts: a list of header fields and + then a body. The Email data type provides a way to access the full + structure or to use simplified properties and avoid some complexity + if this is sufficient for the client application. + + While raw headers can be fetched and set, the vast majority of + clients should use an appropriate parsed form for each of the header + fields it wants to process, as this allows it to avoid the + complexities of various encodings that are required in a valid + message per RFC 5322. + + The body of a message is normally a MIME-encoded set of documents in + a tree structure. This may be arbitrarily nested, but the majority + of email clients present a flat model of a message body (normally + plaintext or HTML) with a set of attachments. Flattening the MIME + structure to form this model can be difficult and causes + inconsistency between clients. Therefore, in addition to the + "bodyStructure" property, which gives the full tree, the Email object + contains 3 alternate properties with flat lists of body parts: + + o "textBody"/"htmlBody": These provide a list of parts that should + be rendered sequentially as the "body" of the message. This is a + list rather than a single part as messages may have headers and/or + footers appended/prepended as separate parts when they are + transmitted, and some clients send text and images intended to be + displayed inline in the body (or even videos and sound clips) as + multiple parts rather than a single HTML part with referenced + images. + + Because MIME allows for multiple representations of the same data + (using "multipart/alternative"), there is a "textBody" property + (which prefers a plaintext representation) and an "htmlBody" + property (which prefers an HTML representation) to accommodate the + two most common client requirements. The same part may appear in + both lists where there is no alternative between the two. + + o "attachments": This provides a list of parts that should be + presented as "attachments" to the message. Some images may be + solely there for embedding within an HTML body part; clients may + wish to not present these as attachments in the user interface if + they are displaying the HTML with the embedded images directly. + Some parts may also be in htmlBody/textBody; again, clients may + wish to not present these as attachments in the user interface if + rendered as part of the body. + + + + + +Jenkins & Newman Standards Track [Page 23] + +RFC 8621 JMAP Mail August 2019 + + + The "bodyValues" property allows for clients to fetch the value of + text parts directly without having to do a second request for the + blob and to have the server handle decoding the charset into unicode. + This data is in a separate property rather than on the EmailBodyPart + object to avoid duplication of large amounts of data, as the same + part may be included twice if the client fetches more than one of + bodyStructure, textBody, and htmlBody. + + In the following subsections, the common notational convention for + wildcards has been adopted for content types, so "foo/*" means any + content type that starts with "foo/". + + Due to the number of properties involved, the set of Email properties + is specified over the following four subsections. This is purely for + readability; all properties are top-level peers. + +4.1.1. Metadata + + These properties represent metadata about the message in the mail + store and are not derived from parsing the message itself. + + o id: "Id" (immutable; server-set) + + The id of the Email object. Note that this is the JMAP object id, + NOT the Message-ID header field value of the message [RFC5322]. + + o blobId: "Id" (immutable; server-set) + + The id representing the raw octets of the message [RFC5322] for + this Email. This may be used to download the raw original message + or to attach it directly to another Email, etc. + + o threadId: "Id" (immutable; server-set) + + The id of the Thread to which this Email belongs. + + o mailboxIds: "Id[Boolean]" + + The set of Mailbox ids this Email belongs to. An Email in the + mail store MUST belong to one or more Mailboxes at all times + (until it is destroyed). The set is represented as an object, + with each key being a Mailbox id. The value for each key in the + object MUST be true. + + + + + + + + +Jenkins & Newman Standards Track [Page 24] + +RFC 8621 JMAP Mail August 2019 + + + o keywords: "String[Boolean]" (default: {}) + + A set of keywords that apply to the Email. The set is represented + as an object, with the keys being the keywords. The value for + each key in the object MUST be true. + + Keywords are shared with IMAP. The six system keywords from IMAP + get special treatment. The following four keywords have their + first character changed from "\" in IMAP to "$" in JMAP and have + particular semantic meaning: + + * "$draft": The Email is a draft the user is composing. + + * "$seen": The Email has been read. + + * "$flagged": The Email has been flagged for urgent/special + attention. + + * "$answered": The Email has been replied to. + + The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP + "\Deleted" keyword is also not present: IMAP uses a delete+expunge + model, which JMAP does not. Any message with the "\Deleted" + keyword MUST NOT be visible via JMAP (and so are not counted in + the "totalEmails", "unreadEmails", "totalThreads", and + "unreadThreads" Mailbox properties). + + Users may add arbitrary keywords to an Email. For compatibility + with IMAP, a keyword is a case-insensitive string of 1-255 + characters in the ASCII subset %x21-%x7e (excludes control chars + and space), and it MUST NOT include any of these characters: + + ( ) { ] % * " \ + + Because JSON is case sensitive, servers MUST return keywords in + lowercase. + + The IANA "IMAP and JMAP Keywords" registry at + as + established in [RFC5788] assigns semantic meaning to some other + keywords in common use. New keywords may be established here in + the future. In particular, note: + + * "$forwarded": The Email has been forwarded. + + * "$phishing": The Email is highly likely to be phishing. + Clients SHOULD warn users to take care when viewing this Email + and disable links and attachments. + + + +Jenkins & Newman Standards Track [Page 25] + +RFC 8621 JMAP Mail August 2019 + + + * "$junk": The Email is definitely spam. Clients SHOULD set this + flag when users report spam to help train automated spam- + detection systems. + + * "$notjunk": The Email is definitely not spam. Clients SHOULD + set this flag when users indicate an Email is legitimate, to + help train automated spam-detection systems. + + o size: "UnsignedInt" (immutable; server-set) + + The size, in octets, of the raw data for the message [RFC5322] (as + referenced by the "blobId", i.e., the number of octets in the file + the user would download). + + o receivedAt: "UTCDate" (immutable; default: time of creation on + server) + + The date the Email was received by the message store. This is the + "internal date" in IMAP [RFC3501]. + +4.1.2. Header Fields Parsed Forms + + Header field properties are derived from the message header fields + [RFC5322] [RFC6532]. All header fields may be fetched in a raw form. + Some header fields may also be fetched in a parsed form. The + structured form that may be fetched depends on the header. The forms + are defined in the subsections that follow. + +4.1.2.1. Raw + + Type: "String" + + The raw octets of the header field value from the first octet + following the header field name terminating colon, up to but + excluding the header field terminating CRLF. Any standards-compliant + message MUST be either ASCII (RFC 5322) or UTF-8 (RFC 6532); however, + other encodings exist in the wild. A server SHOULD replace any octet + or octet run with the high bit set that violates UTF-8 syntax with + the unicode replacement character (U+FFFD). Any NUL octet MUST be + dropped. + + This form will typically have a leading space, as most generated + messages insert a space after the colon that terminates the header + field name. + + + + + + + +Jenkins & Newman Standards Track [Page 26] + +RFC 8621 JMAP Mail August 2019 + + +4.1.2.2. Text + + Type: "String" + + The header field value with: + + 1. White space unfolded (as defined in [RFC5322], Section 2.2.3). + + 2. The terminating CRLF at the end of the value removed. + + 3. Any SP characters at the beginning of the value removed. + + 4. Any syntactically correct encoded sections [RFC2047] with a known + character set decoded. Any NUL octets or control characters + encoded per [RFC2047] are dropped from the decoded value. Any + text that looks like syntax per [RFC2047] but violates placement + or white space rules per [RFC2047] MUST NOT be decoded. + + 5. The resulting unicode converted to Normalization Form C (NFC) + form. + + If any decodings fail, the parser SHOULD insert a unicode replacement + character (U+FFFD) and attempt to continue as much as possible. + + To prevent obviously nonsense behaviour, which can lead to + interoperability issues, this form may only be fetched or set for the + following header fields: + + o Subject + + o Comments + + o Keywords + + o List-Id + + o Any header field not defined in [RFC5322] or [RFC2369] + +4.1.2.3. Addresses + + Type: "EmailAddress[]" + + The header field is parsed as an "address-list" value, as specified + in [RFC5322], Section 3.4, into the "EmailAddress[]" type. There is + an EmailAddress item for each "mailbox" parsed from the "address- + list". Group and comment information is discarded. + + + + + +Jenkins & Newman Standards Track [Page 27] + +RFC 8621 JMAP Mail August 2019 + + + An *EmailAddress* object has the following properties: + + o name: "String|null" + + The "display-name" of the "mailbox" [RFC5322]. If this is a + "quoted-string": + + 1. The surrounding DQUOTE characters are removed. + + 2. Any "quoted-pair" is decoded. + + 3. White space is unfolded, and then any leading and trailing + white space is removed. + + If there is no "display-name" but there is a "comment" immediately + following the "addr-spec", the value of this SHOULD be used + instead. Otherwise, this property is null. + + o email: "String" + + The "addr-spec" of the "mailbox" [RFC5322]. + + Any syntactically correct encoded sections [RFC2047] with a known + encoding MUST be decoded, following the same rules as for the Text + form (see Section 4.1.2.2). + + Parsing SHOULD be best effort in the face of invalid structure to + accommodate invalid messages and semi-complete drafts. EmailAddress + objects MAY have an "email" property that does not conform to the + "addr-spec" form (for example, may not contain an @ symbol). + + For example, the following "address-list" string: + + " James Smythe" , Friends: + jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= + ; + + would be parsed as: + + [ + { "name": "James Smythe", "email": "james@example.com" }, + { "name": null, "email": "jane@example.com" }, + { "name": "John Smith", "email": "john@example.com" } + ] + + + + + + + +Jenkins & Newman Standards Track [Page 28] + +RFC 8621 JMAP Mail August 2019 + + + To prevent obviously nonsense behaviour, which can lead to + interoperability issues, this form may only be fetched or set for the + following header fields: + + o From + + o Sender + + o Reply-To + + o To + + o Cc + + o Bcc + + o Resent-From + + o Resent-Sender + + o Resent-Reply-To + + o Resent-To + + o Resent-Cc + + o Resent-Bcc + + o Any header field not defined in [RFC5322] or [RFC2369] + +4.1.2.4. GroupedAddresses + + Type: "EmailAddressGroup[]" + + This is similar to the Addresses form but preserves group + information. The header field is parsed as an "address-list" value, + as specified in [RFC5322], Section 3.4, into the "GroupedAddresses[]" + type. Consecutive "mailbox" values that are not part of a group are + still collected under an EmailAddressGroup object to provide a + uniform type. + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 29] + +RFC 8621 JMAP Mail August 2019 + + + An *EmailAddressGroup* object has the following properties: + + o name: "String|null" + + The "display-name" of the "group" [RFC5322], or null if the + addresses are not part of a group. If this is a "quoted-string", + it is processed the same as the "name" in the EmailAddress type. + + o addresses: "EmailAddress[]" + + The "mailbox" values that belong to this group, represented as + EmailAddress objects. + + Any syntactically correct encoded sections [RFC2047] with a known + encoding MUST be decoded, following the same rules as for the Text + form (see Section 4.1.2.2). + + Parsing SHOULD be best effort in the face of invalid structure to + accommodate invalid messages and semi-complete drafts. + + For example, the following "address-list" string: + + " James Smythe" , Friends: + jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= + ; + + would be parsed as: + + [ + { "name": null, "addresses": [ + { "name": "James Smythe", "email": "james@example.com" } + ]}, + { "name": "Friends", "addresses": [ + { "name": null, "email": "jane@example.com" }, + { "name": "John Smith", "email": "john@example.com" } + ]} + ] + + To prevent obviously nonsense behaviour, which can lead to + interoperability issues, this form may only be fetched or set for the + same header fields as the Addresses form (see Section 4.1.2.3). + + + + + + + + + + +Jenkins & Newman Standards Track [Page 30] + +RFC 8621 JMAP Mail August 2019 + + +4.1.2.5. MessageIds + + Type: "String[]|null" + + The header field is parsed as a list of "msg-id" values, as specified + in [RFC5322], Section 3.6.4, into the "String[]" type. Comments and/ + or folding white space (CFWS) and surrounding angle brackets ("<>") + are removed. If parsing fails, the value is null. + + To prevent obviously nonsense behaviour, which can lead to + interoperability issues, this form may only be fetched or set for the + following header fields: + + o Message-ID + + o In-Reply-To + + o References + + o Resent-Message-ID + + o Any header field not defined in [RFC5322] or [RFC2369] + +4.1.2.6. Date + + Type: "Date|null" + + The header field is parsed as a "date-time" value, as specified in + [RFC5322], Section 3.3, into the "Date" type. If parsing fails, the + value is null. + + To prevent obviously nonsense behaviour, which can lead to + interoperability issues, this form may only be fetched or set for the + following header fields: + + o Date + + o Resent-Date + + o Any header field not defined in [RFC5322] or [RFC2369] + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 31] + +RFC 8621 JMAP Mail August 2019 + + +4.1.2.7. URLs + + Type: "String[]|null" + + The header field is parsed as a list of URLs, as described in + [RFC2369], into the "String[]" type. Values do not include the + surrounding angle brackets or any comments in the header field with + the URLs. If parsing fails, the value is null. + + To prevent obviously nonsense behaviour, which can lead to + interoperability issues, this form may only be fetched or set for the + following header fields: + + o List-Help + + o List-Unsubscribe + + o List-Subscribe + + o List-Post + + o List-Owner + + o List-Archive + + o Any header field not defined in [RFC5322] or [RFC2369] + +4.1.3. Header Fields Properties + + The following low-level Email property is specified for complete + access to the header data of the message: + + o headers: "EmailHeader[]" (immutable) + + This is a list of all header fields [RFC5322], in the same order + they appear in the message. An *EmailHeader* object has the + following properties: + + * name: "String" + + The header "field name" as defined in [RFC5322], with the same + capitalization that it has in the message. + + * value: "String" + + The header "field value" as defined in [RFC5322], in Raw form. + + + + + +Jenkins & Newman Standards Track [Page 32] + +RFC 8621 JMAP Mail August 2019 + + + In addition, the client may request/send properties representing + individual header fields of the form: + + header:{header-field-name} + + Where "{header-field-name}" means any series of one or more printable + ASCII characters (i.e., characters that have values between 33 and + 126, inclusive), except for colon (:). The property may also have + the following suffixes: + + o :as{header-form} + + This means the value is in a parsed form, where "{header-form}" is + one of the parsed-form names specified above. If not given, the + value is in Raw form. + + o :all + + This means the value is an array, with the items corresponding to + each instance of the header field, in the order they appear in the + message. If this suffix is not used, the result is the value of + the *last* instance of the header field (i.e., identical to the + last item in the array if :all is used), or null if none. + + If both suffixes are used, they MUST be specified in the order above. + Header field names are matched case insensitively. The value is + typed according to the requested form or to an array of that type if + :all is used. If no header fields exist in the message with the + requested name, the value is null if fetching a single instance or an + empty array if requesting :all. + + As a simple example, if the client requests a property called + "header:subject", this means find the *last* header field in the + message named "subject" (matched case insensitively) and return the + value in Raw form, or null if no header field of this name is found. + + For a more complex example, consider the client requesting a property + called "header:Resent-To:asAddresses:all". This means: + + 1. Find *all* header fields named Resent-To (matched case + insensitively). + + 2. For each instance, parse the header field value in the Addresses + form. + + 3. The result is of type "EmailAddress[][]" -- each item in the + array corresponds to the parsed value (which is itself an array) + of the Resent-To header field instance. + + + +Jenkins & Newman Standards Track [Page 33] + +RFC 8621 JMAP Mail August 2019 + + + The following convenience properties are also specified for the Email + object: + + o messageId: "String[]|null" (immutable) + + The value is identical to the value of "header:Message- + ID:asMessageIds". For messages conforming to RFC 5322, this will + be an array with a single entry. + + o inReplyTo: "String[]|null" (immutable) + + The value is identical to the value of "header:In-Reply- + To:asMessageIds". + + o references: "String[]|null" (immutable) + + The value is identical to the value of + "header:References:asMessageIds". + + o sender: "EmailAddress[]|null" (immutable) + + The value is identical to the value of + "header:Sender:asAddresses". + + o from: "EmailAddress[]|null" (immutable) + + The value is identical to the value of "header:From:asAddresses". + + o to: "EmailAddress[]|null" (immutable) + + The value is identical to the value of "header:To:asAddresses". + + o cc: "EmailAddress[]|null" (immutable) + + The value is identical to the value of "header:Cc:asAddresses". + + o bcc: "EmailAddress[]|null" (immutable) + + The value is identical to the value of "header:Bcc:asAddresses". + + o replyTo: "EmailAddress[]|null" (immutable) + + The value is identical to the value of "header:Reply- + To:asAddresses". + + o subject: "String|null" (immutable) + + The value is identical to the value of "header:Subject:asText". + + + +Jenkins & Newman Standards Track [Page 34] + +RFC 8621 JMAP Mail August 2019 + + + o sentAt: "Date|null" (immutable; default on creation: current + server time) + + The value is identical to the value of "header:Date:asDate". + +4.1.4. Body Parts + + These properties are derived from the message body [RFC5322] and its + MIME entities [RFC2045]. + + An *EmailBodyPart* object has the following properties: + + o partId: "String|null" + + Identifies this part uniquely within the Email. This is scoped to + the "emailId" and has no meaning outside of the JMAP Email object + representation. This is null if, and only if, the part is of type + "multipart/*". + + o blobId: "Id|null" + + The id representing the raw octets of the contents of the part, + after decoding any known Content-Transfer-Encoding (as defined in + [RFC2045]), or null if, and only if, the part is of type + "multipart/*". Note that two parts may be transfer-encoded + differently but have the same blob id if their decoded octets are + identical and the server is using a secure hash of the data for + the blob id. If the transfer encoding is unknown, it is treated + as though it had no transfer encoding. + + o size: "UnsignedInt" + + The size, in octets, of the raw data after content transfer + decoding (as referenced by the "blobId", i.e., the number of + octets in the file the user would download). + + o headers: "EmailHeader[]" + + This is a list of all header fields in the part, in the order they + appear in the message. The values are in Raw form. + + o name: "String|null" + + This is the decoded "filename" parameter of the Content- + Disposition header field per [RFC2231], or (for compatibility with + existing systems) if not present, then it's the decoded "name" + parameter of the Content-Type header field per [RFC2047]. + + + + +Jenkins & Newman Standards Track [Page 35] + +RFC 8621 JMAP Mail August 2019 + + + o type: "String" + + The value of the Content-Type header field of the part, if + present; otherwise, the implicit type as per the MIME standard + ("text/plain" or "message/rfc822" if inside a "multipart/digest"). + CFWS is removed and any parameters are stripped. + + o charset: "String|null" + + The value of the charset parameter of the Content-Type header + field, if present, or null if the header field is present but not + of type "text/*". If there is no Content-Type header field, or it + exists and is of type "text/*" but has no charset parameter, this + is the implicit charset as per the MIME standard: "us-ascii". + + o disposition: "String|null" + + The value of the Content-Disposition header field of the part, if + present; otherwise, it's null. CFWS is removed and any parameters + are stripped. + + o cid: "String|null" + + The value of the Content-Id header field of the part, if present; + otherwise, it's null. CFWS and surrounding angle brackets ("<>") + are removed. This may be used to reference the content from + within a "text/html" body part [HTML] using the "cid:" protocol, + as defined in [RFC2392]. + + o language: "String[]|null" + + The list of language tags, as defined in [RFC3282], in the + Content-Language header field of the part, if present. + + o location: "String|null" + + The URI, as defined in [RFC2557], in the Content-Location header + field of the part, if present. + + o subParts: "EmailBodyPart[]|null" + + If the type is "multipart/*", this contains the body parts of each + child. + + In addition, the client may request/send EmailBodyPart properties + representing individual header fields, following the same syntax and + semantics as for the Email object, e.g., "header:Content-Type". + + + + +Jenkins & Newman Standards Track [Page 36] + +RFC 8621 JMAP Mail August 2019 + + + The following Email properties are specified for access to the body + data of the message: + + o bodyStructure: "EmailBodyPart" (immutable) + + This is the full MIME structure of the message body, without + recursing into "message/rfc822" or "message/global" parts. Note + that EmailBodyParts may have subParts if they are of type + "multipart/*". + + o bodyValues: "String[EmailBodyValue]" (immutable) + + This is a map of "partId" to an EmailBodyValue object for none, + some, or all "text/*" parts. Which parts are included and whether + the value is truncated is determined by various arguments to + "Email/get" and "Email/parse". An *EmailBodyValue* object has the + following properties: + + * value: "String" + + The value of the body part after decoding Content-Transfer- + Encoding and the Content-Type charset, if both known to the + server, and with any CRLF replaced with a single LF. The + server MAY use heuristics to determine the charset to use for + decoding if the charset is unknown, no charset is given, or it + believes the charset given is incorrect. Decoding is best + effort; the server SHOULD insert the unicode replacement + character (U+FFFD) and continue when a malformed section is + encountered. + + Note that due to the charset decoding and line ending + normalisation, the length of this string will probably not be + exactly the same as the "size" property on the corresponding + EmailBodyPart. + + * isEncodingProblem: "Boolean" (default: false) + + This is true if malformed sections were found while decoding + the charset, the charset was unknown, or the content-transfer- + encoding was unknown. + + * isTruncated: "Boolean" (default: false) + + This is true if the "value" has been truncated. + + See the Security Considerations section for issues related to + truncation and heuristic determination of the content-type and + charset. + + + +Jenkins & Newman Standards Track [Page 37] + +RFC 8621 JMAP Mail August 2019 + + + o textBody: "EmailBodyPart[]" (immutable) + + A list of "text/plain", "text/html", "image/*", "audio/*", and/or + "video/*" parts to display (sequentially) as the message body, + with a preference for "text/plain" when alternative versions are + available. + + o htmlBody: "EmailBodyPart[]" (immutable) + + A list of "text/plain", "text/html", "image/*", "audio/*", and/or + "video/*" parts to display (sequentially) as the message body, + with a preference for "text/html" when alternative versions are + available. + + o attachments: "EmailBodyPart[]" (immutable) + + A list, traversing depth-first, of all parts in "bodyStructure" + that satisfy either of the following conditions: + + * not of type "multipart/*" and not included in "textBody" or + "htmlBody" + + * of type "image/*", "audio/*", or "video/*" and not in both + "textBody" and "htmlBody" + + None of these parts include subParts, including "message/*" types. + Attached messages may be fetched using the "Email/parse" method + and the "blobId". + + Note that a "text/html" body part [HTML] may reference image parts + in attachments by using "cid:" links to reference the Content-Id, + as defined in [RFC2392], or by referencing the Content-Location. + + o hasAttachment: "Boolean" (immutable; server-set) + + This is true if there are one or more parts in the message that a + client UI should offer as downloadable. A server SHOULD set + hasAttachment to true if the "attachments" list contains at least + one item that does not have "Content-Disposition: inline". The + server MAY ignore parts in this list that are processed + automatically in some way or are referenced as embedded images in + one of the "text/html" parts of the message. + + The server MAY set hasAttachment based on implementation-defined + or site-configurable heuristics. + + + + + + +Jenkins & Newman Standards Track [Page 38] + +RFC 8621 JMAP Mail August 2019 + + + o preview: "String" (immutable; server-set) + + A plaintext fragment of the message body. This is intended to be + shown as a preview line when listing messages in the mail store + and may be truncated when shown. The server may choose which part + of the message to include in the preview; skipping quoted sections + and salutations and collapsing white space can result in a more + useful preview. + + This MUST NOT be more than 256 characters in length. + + As this is derived from the message content by the server, and the + algorithm for doing so could change over time, fetching this for + an Email a second time MAY return a different result. However, + the previous value is not considered incorrect, and the change + SHOULD NOT cause the Email object to be considered as changed by + the server. + + The exact algorithm for decomposing bodyStructure into textBody, + htmlBody, and attachments part lists is not mandated, as this is a + quality-of-service implementation issue and likely to require + workarounds for malformed content discovered over time. However, the + following algorithm (expressed here in JavaScript) is suggested as a + starting point, based on real-world experience: + + function isInlineMediaType ( type ) { + return type.startsWith( 'image/' ) || + type.startsWith( 'audio/' ) || + type.startsWith( 'video/' ); + } + + function parseStructure ( parts, multipartType, inAlternative, + htmlBody, textBody, attachments ) { + + // For multipartType == alternative + let textLength = textBody ? textBody.length : -1; + let htmlLength = htmlBody ? htmlBody.length : -1; + + for ( let i = 0; i < parts.length; i += 1 ) { + let part = parts[i]; + let isMultipart = part.type.startsWith( 'multipart/' ); + // Is this a body part rather than an attachment + let isInline = part.disposition != "attachment" && + // Must be one of the allowed body types + ( part.type == "text/plain" || + part.type == "text/html" || + isInlineMediaType( part.type ) ) && + + + + +Jenkins & Newman Standards Track [Page 39] + +RFC 8621 JMAP Mail August 2019 + + + // If multipart/related, only the first part can be inline + // If a text part with a filename, and not the first item + // in the multipart, assume it is an attachment + ( i === 0 || + ( multipartType != "related" && + ( isInlineMediaType( part.type ) || !part.name ) ) ); + + if ( isMultipart ) { + let subMultiType = part.type.split( '/' )[1]; + parseStructure( part.subParts, subMultiType, + inAlternative || ( subMultiType == 'alternative' ), + htmlBody, textBody, attachments ); + } else if ( isInline ) { + if ( multipartType == 'alternative' ) { + switch ( part.type ) { + case 'text/plain': + textBody.push( part ); + break; + case 'text/html': + htmlBody.push( part ); + break; + default: + attachments.push( part ); + break; + } + continue; + } else if ( inAlternative ) { + if ( part.type == 'text/plain' ) { + htmlBody = null; + } + if ( part.type == 'text/html' ) { + textBody = null; + } + } + if ( textBody ) { + textBody.push( part ); + } + if ( htmlBody ) { + htmlBody.push( part ); + } + if ( ( !textBody || !htmlBody ) && + isInlineMediaType( part.type ) ) { + attachments.push( part ); + } + } else { + attachments.push( part ); + } + } + + + +Jenkins & Newman Standards Track [Page 40] + +RFC 8621 JMAP Mail August 2019 + + + if ( multipartType == 'alternative' && textBody && htmlBody ) { + // Found HTML part only + if ( textLength == textBody.length && + htmlLength != htmlBody.length ) { + for ( let i = htmlLength; i < htmlBody.length; i += 1 ) { + textBody.push( htmlBody[i] ); + } + } + // Found plaintext part only + if ( htmlLength == htmlBody.length && + textLength != textBody.length ) { + for ( let i = textLength; i < textBody.length; i += 1 ) { + htmlBody.push( textBody[i] ); + } + } + } + } + + // Usage: + let htmlBody = []; + let textBody = []; + let attachments = []; + + parseStructure( [ bodyStructure ], 'mixed', false, + htmlBody, textBody, attachments ); + + For instance, consider a message with both text and HTML versions + that has gone through a list software manager that attaches a header + and footer. It might have a MIME structure something like: + + multipart/mixed + text/plain, content-disposition=inline - A + multipart/mixed + multipart/alternative + multipart/mixed + text/plain, content-disposition=inline - B + image/jpeg, content-disposition=inline - C + text/plain, content-disposition=inline - D + multipart/related + text/html - E + image/jpeg - F + image/jpeg, content-disposition=attachment - G + application/x-excel - H + message/rfc822 - J + text/plain, content-disposition=inline - K + + + + + + +Jenkins & Newman Standards Track [Page 41] + +RFC 8621 JMAP Mail August 2019 + + + In this case, the above algorithm would decompose this to: + + textBody => [ A, B, C, D, K ] + htmlBody => [ A, E, K ] + attachments => [ C, F, G, H, J ] + +4.2. Email/get + + This is a standard "/get" method as described in [RFC8620], + Section 5.1 with the following additional request arguments: + + o bodyProperties: "String[]" + + A list of properties to fetch for each EmailBodyPart returned. If + omitted, this defaults to: + + [ "partId", "blobId", "size", "name", "type", "charset", + "disposition", "cid", "language", "location" ] + + o fetchTextBodyValues: "Boolean" (default: false) + + If true, the "bodyValues" property includes any "text/*" part in + the "textBody" property. + + o fetchHTMLBodyValues: "Boolean" (default: false) + + If true, the "bodyValues" property includes any "text/*" part in + the "htmlBody" property. + + o fetchAllBodyValues: "Boolean" (default: false) + + If true, the "bodyValues" property includes any "text/*" part in + the "bodyStructure" property. + + o maxBodyValueBytes: "UnsignedInt" (default: 0) + + If greater than zero, the "value" property of any EmailBodyValue + object returned in "bodyValues" MUST be truncated if necessary so + it does not exceed this number of octets in size. If 0 (the + default), no truncation occurs. + + The server MUST ensure the truncation results in valid UTF-8 and + does not occur mid-codepoint. If the part is of type "text/html", + the server SHOULD NOT truncate inside an HTML tag, e.g., in the + middle of "". There is no + requirement for the truncated form to be a balanced tree or valid + HTML (indeed, the original source may well be neither of these + things). + + + +Jenkins & Newman Standards Track [Page 42] + +RFC 8621 JMAP Mail August 2019 + + + If the standard "properties" argument is omitted or null, the + following default MUST be used instead of "all" properties: + + [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size", + "receivedAt", "messageId", "inReplyTo", "references", "sender", "from", + "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", + "preview", "bodyValues", "textBody", "htmlBody", "attachments" ] + + The following properties are expected to be fast to fetch in a + quality implementation: + + o id + + o blobId + + o threadId + + o mailboxIds + + o keywords + + o size + + o receivedAt + + o messageId + + o inReplyTo + + o sender + + o from + + o to + + o cc + + o bcc + + o replyTo + + o subject + + o sentAt + + o hasAttachment + + o preview + + + +Jenkins & Newman Standards Track [Page 43] + +RFC 8621 JMAP Mail August 2019 + + + Clients SHOULD take care when fetching any other properties, as there + may be significantly longer latency in fetching and returning the + data. + + As specified above, parsed forms of headers may only be used on + appropriate header fields. Attempting to fetch a form that is + forbidden (e.g., "header:From:asDate") MUST result in the method call + being rejected with an "invalidArguments" error. + + Where a specific header field is requested as a property, the + capitalization of the property name in the response MUST be identical + to that used in the request. + +4.2.1. Example + + Request: + + [[ "Email/get", { + "ids": [ "f123u456", "f123u457" ], + "properties": [ "threadId", "mailboxIds", "from", "subject", + "receivedAt", "header:List-POST:asURLs", + "htmlBody", "bodyValues" ], + "bodyProperties": [ "partId", "blobId", "size", "type" ], + "fetchHTMLBodyValues": true, + "maxBodyValueBytes": 256 + }, "#1" ]] + + and response: + + [[ "Email/get", { + "accountId": "abc", + "state": "41234123231", + "list": [ + { + "id": "f123u457", + "threadId": "ef1314a", + "mailboxIds": { "f123": true }, + "from": [{ "name": "Joe Bloggs", "email": "joe@example.com" }], + "subject": "Dinner on Thursday?", + "receivedAt": "2013-10-13T14:12:00Z", + "header:List-POST:asURLs": [ + "mailto:partytime@lists.example.com" + ], + "htmlBody": [{ + "partId": "1", + "blobId": "B841623871", + "size": 283331, + "type": "text/html" + + + +Jenkins & Newman Standards Track [Page 44] + +RFC 8621 JMAP Mail August 2019 + + + }, { + "partId": "2", + "blobId": "B319437193", + "size": 10343, + "type": "text/plain" + }], + "bodyValues": { + "1": { + "isEncodingProblem": false, + "isTruncated": true, + "value": "

Hello ..." + }, + "2": { + "isEncodingProblem": false, + "isTruncated": false, + "value": "-- Sent by your friendly mailing list ..." + } + } + } + ], + "notFound": [ "f123u456" ] + }, "#1" ]] + +4.3. Email/changes + + This is a standard "/changes" method as described in [RFC8620], + Section 5.2. If generating intermediate states for a large set of + changes, it is recommended that newer changes be returned first, as + these are generally of more interest to users. + +4.4. Email/query + + This is a standard "/query" method as described in [RFC8620], + Section 5.5 but with the following additional request arguments: + + o collapseThreads: "Boolean" (default: false) + + If true, Emails in the same Thread as a previous Email in the list + (given the filter and sort order) will be removed from the list. + This means only one Email at most will be included in the list for + any given Thread. + + In quality implementations, the query "total" property is expected to + be fast to calculate when the filter consists solely of a single + "inMailbox" property, as it is the same as the totalEmails or + totalThreads properties (depending on whether collapseThreads is + true) of the associated Mailbox object. + + + + +Jenkins & Newman Standards Track [Page 45] + +RFC 8621 JMAP Mail August 2019 + + +4.4.1. Filtering + + A *FilterCondition* object has the following properties, any of which + may be omitted: + + o inMailbox: "Id" + + A Mailbox id. An Email must be in this Mailbox to match the + condition. + + o inMailboxOtherThan: "Id[]" + + A list of Mailbox ids. An Email must be in at least one Mailbox + not in this list to match the condition. This is to allow + messages solely in trash/spam to be easily excluded from a search. + + o before: "UTCDate" + + The "receivedAt" date-time of the Email must be before this date- + time to match the condition. + + o after: "UTCDate" + + The "receivedAt" date-time of the Email must be the same or after + this date-time to match the condition. + + o minSize: "UnsignedInt" + + The "size" property of the Email must be equal to or greater than + this number to match the condition. + + o maxSize: "UnsignedInt" + + The "size" property of the Email must be less than this number to + match the condition. + + o allInThreadHaveKeyword: "String" + + All Emails (including this one) in the same Thread as this Email + must have the given keyword to match the condition. + + o someInThreadHaveKeyword: "String" + + At least one Email (possibly this one) in the same Thread as this + Email must have the given keyword to match the condition. + + + + + + +Jenkins & Newman Standards Track [Page 46] + +RFC 8621 JMAP Mail August 2019 + + + o noneInThreadHaveKeyword: "String" + + All Emails (including this one) in the same Thread as this Email + must *not* have the given keyword to match the condition. + + o hasKeyword: "String" + + This Email must have the given keyword to match the condition. + + o notKeyword: "String" + + This Email must not have the given keyword to match the condition. + + o hasAttachment: "Boolean" + + The "hasAttachment" property of the Email must be identical to the + value given to match the condition. + + o text: "String" + + Looks for the text in Emails. The server MUST look up text in the + From, To, Cc, Bcc, and Subject header fields of the message and + SHOULD look inside any "text/*" or other body parts that may be + converted to text by the server. The server MAY extend the search + to any additional textual property. + + o from: "String" + + Looks for the text in the From header field of the message. + + o to: "String" + + Looks for the text in the To header field of the message. + + o cc: "String" + + Looks for the text in the Cc header field of the message. + + o bcc: "String" + + Looks for the text in the Bcc header field of the message. + + o subject: "String" + + Looks for the text in the Subject header field of the message. + + + + + + +Jenkins & Newman Standards Track [Page 47] + +RFC 8621 JMAP Mail August 2019 + + + o body: "String" + + Looks for the text in one of the body parts of the message. The + server MAY exclude MIME body parts with content media types other + than "text/*" and "message/*" from consideration in search + matching. Care should be taken to match based on the text content + actually presented to an end user by viewers for that media type + or otherwise identified as appropriate for search indexing. + Matching document metadata uninteresting to an end user (e.g., + markup tag and attribute names) is undesirable. + + o header: "String[]" + + The array MUST contain either one or two elements. The first + element is the name of the header field to match against. The + second (optional) element is the text to look for in the header + field value. If not supplied, the message matches simply if it + has a header field of the given name. + + If zero properties are specified on the FilterCondition, the + condition MUST always evaluate to true. If multiple properties are + specified, ALL must apply for the condition to be true (it is + equivalent to splitting the object into one-property conditions and + making them all the child of an AND filter operator). + + The exact semantics for matching "String" fields is *deliberately not + defined* to allow for flexibility in indexing implementation, subject + to the following: + + o Any syntactically correct encoded sections [RFC2047] of header + fields with a known encoding SHOULD be decoded before attempting + to match text. + + o When searching inside a "text/html" body part, any text considered + markup rather than content SHOULD be ignored, including HTML tags + and most attributes, anything inside the "" tag, Cascading + Style Sheets (CSS), and JavaScript. Attribute content intended + for presentation to the user such as "alt" and "title" SHOULD be + considered in the search. + + o Text SHOULD be matched in a case-insensitive manner. + + o Text contained in either (but matched) single (') or double (") + quotes SHOULD be treated as a *phrase search*; that is, a match is + required for that exact word or sequence of words, excluding the + surrounding quotation marks. + + + + + +Jenkins & Newman Standards Track [Page 48] + +RFC 8621 JMAP Mail August 2019 + + + Within a phrase, to match one of the following characters you MUST + escape it by prefixing it with a backslash (\): + + ' " \ + + o Outside of a phrase, white space SHOULD be treated as dividing + separate tokens that may be searched for separately but MUST all + be present for the Email to match the filter. + + o Tokens (not part of a phrase) MAY be matched on a whole-word basis + using stemming (for example, a text search for "bus" would match + "buses" but not "business"). + +4.4.2. Sorting + + The following value for the "property" field on the Comparator object + MUST be supported for sorting: + + o "receivedAt" - The "receivedAt" date as returned in the Email + object. + + The following values for the "property" field on the Comparator + object SHOULD be supported for sorting. When specifying a + "hasKeyword", "allInThreadHaveKeyword", or "someInThreadHaveKeyword" + sort, the Comparator object MUST also have a "keyword" property. + + o "size" - The "size" as returned in the Email object. + + o "from" - This is taken to be either the "name" property or if + null/empty, the "email" property of the *first* EmailAddress + object in the Email's "from" property. If still none, consider + the value to be the empty string. + + o "to" - This is taken to be either the "name" property or if null/ + empty, the "email" property of the *first* EmailAddress object in + the Email's "to" property. If still none, consider the value to + be the empty string. + + o "subject" - This is taken to be the base subject of the message, + as defined in Section 2.1 of [RFC5256]. + + o "sentAt" - The "sentAt" property on the Email object. + + o "hasKeyword" - This value MUST be considered true if the Email has + the keyword given as an additional "keyword" property on the + Comparator object, or false otherwise. + + + + + +Jenkins & Newman Standards Track [Page 49] + +RFC 8621 JMAP Mail August 2019 + + + o "allInThreadHaveKeyword" - This value MUST be considered true for + the Email if *all* of the Emails in the same Thread have the + keyword given as an additional "keyword" property on the + Comparator object. + + o "someInThreadHaveKeyword" - This value MUST be considered true for + the Email if *any* of the Emails in the same Thread have the + keyword given as an additional "keyword" property on the + Comparator object. + + The server MAY support sorting based on other properties as well. A + client can discover which properties are supported by inspecting the + account's "capabilities" object (see Section 1.3). + + Example sort: + + [{ + "property": "someInThreadHaveKeyword", + "keyword": "$flagged", + "isAscending": false + }, { + "property": "subject", + "collation": "i;ascii-casemap" + }, { + "property": "receivedAt", + "isAscending": false + }] + + This would sort Emails in flagged Threads first (the Thread is + considered flagged if any Email within it is flagged), in subject + order second, and then from newest first for messages with the same + subject. If two Emails have identical values for all three + properties, then the order is server dependent but must be stable. + +4.4.3. Thread Collapsing + + When "collapseThreads" is true, then after filtering and sorting the + Email list, the list is further winnowed by removing any Emails for a + Thread id that has already been seen (when passing through the list + sequentially). A Thread will therefore only appear *once* in the + result, at the position of the first Email in the list that belongs + to the Thread (given the current sort/filter). + + + + + + + + + +Jenkins & Newman Standards Track [Page 50] + +RFC 8621 JMAP Mail August 2019 + + +4.5. Email/queryChanges + + This is a standard "/queryChanges" method as described in [RFC8620], + Section 5.6 with the following additional request argument: + + o collapseThreads: "Boolean" (default: false) + + The "collapseThreads" argument that was used with "Email/query". + +4.6. Email/set + + This is a standard "/set" method as described in [RFC8620], + Section 5.3. The "Email/set" method encompasses: + + o Creating a draft + + o Changing the keywords of an Email (e.g., unread/flagged status) + + o Adding/removing an Email to/from Mailboxes (moving a message) + + o Deleting Emails + + The format of the "keywords"/"mailboxIds" properties means that when + updating an Email, you can either replace the entire set of keywords/ + Mailboxes (by setting the full value of the property) or add/remove + individual ones using the JMAP patch syntax (see [RFC8620], + Section 5.3 for the specification and Section 5.7 for an example). + + Due to the format of the Email object, when creating an Email, there + are a number of ways to specify the same information. To ensure that + the message [RFC5322] to create is unambiguous, the following + constraints apply to Email objects submitted for creation: + + o The "headers" property MUST NOT be given on either the top-level + Email or an EmailBodyPart -- the client must set each header field + as an individual property. + + o There MUST NOT be two properties that represent the same header + field (e.g., "header:from" and "from") within the Email or + particular EmailBodyPart. + + o Header fields MUST NOT be specified in parsed forms that are + forbidden for that particular field. + + o Header fields beginning with "Content-" MUST NOT be specified on + the Email object, only on EmailBodyPart objects. + + + + + +Jenkins & Newman Standards Track [Page 51] + +RFC 8621 JMAP Mail August 2019 + + + o If a "bodyStructure" property is given, there MUST NOT be + "textBody", "htmlBody", or "attachments" properties. + + o If given, the "bodyStructure" EmailBodyPart MUST NOT contain a + property representing a header field that is already defined on + the top-level Email object. + + o If given, textBody MUST contain exactly one body part and it MUST + be of type "text/plain". + + o If given, htmlBody MUST contain exactly one body part and it MUST + be of type "text/html". + + o Within an EmailBodyPart: + + * The client may specify a partId OR a blobId, but not both. If + a partId is given, this partId MUST be present in the + "bodyValues" property. + + * The "charset" property MUST be omitted if a partId is given + (the part's content is included in bodyValues, and the server + may choose any appropriate encoding). + + * The "size" property MUST be omitted if a partId is given. If a + blobId is given, it may be included but is ignored by the + server (the size is actually calculated from the blob content + itself). + + * A Content-Transfer-Encoding header field MUST NOT be given. + + o Within an EmailBodyValue object, isEncodingProblem and isTruncated + MUST be either false or omitted. + + Creation attempts that violate any of this SHOULD be rejected with an + "invalidProperties" error; however, a server MAY choose to modify the + Email (e.g., choose between conflicting headers, use a different + content-encoding, etc.) to comply with its requirements instead. + + The server MAY also choose to set additional headers. If not + included, the server MUST generate and set a Message-ID header field + in conformance with [RFC5322], Section 3.6.4 and a Date header field + in conformance with Section 3.6.1. + + The final message generated may be invalid per RFC 5322. For + example, if it is a half-finished draft, the To header field may have + a value that does not conform to the required syntax for this header. + The message will be checked for strict conformance when submitted for + sending (see the EmailSubmission object description). + + + +Jenkins & Newman Standards Track [Page 52] + +RFC 8621 JMAP Mail August 2019 + + + Destroying an Email removes it from all Mailboxes to which it + belonged. To just delete an Email to trash, simply change the + "mailboxIds" property, so it is now in the Mailbox with a "role" + property equal to "trash", and remove all other Mailbox ids. + + When emptying the trash, clients SHOULD NOT destroy Emails that are + also in a Mailbox other than trash. For those Emails, they SHOULD + just remove the trash Mailbox from the Email. + + For successfully created Email objects, the "created" response + contains the "id", "blobId", "threadId", and "size" properties of the + object. + + The following extra SetError types are defined: + + For "create": + + o "blobNotFound": At least one blob id given for an EmailBodyPart + doesn't exist. An extra "notFound" property of type "Id[]" MUST + be included in the SetError object containing every "blobId" + referenced by an EmailBodyPart that could not be found on the + server. + + For "create" and "update": + + o "tooManyKeywords": The change to the Email's keywords would exceed + a server-defined maximum. + + o "tooManyMailboxes": The change to the set of Mailboxes that this + Email is in would exceed a server-defined maximum. + +4.7. Email/copy + + This is a standard "/copy" method as described in [RFC8620], + Section 5.4, except only the "mailboxIds", "keywords", and + "receivedAt" properties may be set during the copy. This method + cannot modify the message represented by the Email. + + The server MAY forbid two Email objects with identical message + content [RFC5322], or even just with the same Message-ID [RFC5322], + to coexist within an account; if the target account already has the + Email, the copy will be rejected with a standard "alreadyExists" + error. + + For successfully copied Email objects, the "created" response + contains the "id", "blobId", "threadId", and "size" properties of the + new object. + + + + +Jenkins & Newman Standards Track [Page 53] + +RFC 8621 JMAP Mail August 2019 + + +4.8. Email/import + + The "Email/import" method adds messages [RFC5322] to the set of + Emails in an account. The server MUST support messages with Email + Address Internationalization (EAI) headers [RFC6532]. The messages + must first be uploaded as blobs using the standard upload mechanism. + The method takes the following arguments: + + o accountId: "Id" + + The id of the account to use. + + o ifInState: "String|null" + + This is a state string as returned by the "Email/get" method. If + supplied, the string must match the current state of the account + referenced by the accountId; otherwise, the method will be aborted + and a "stateMismatch" error returned. If null, any changes will + be applied to the current state. + + o emails: "Id[EmailImport]" + + A map of creation id (client specified) to EmailImport objects. + + An *EmailImport* object has the following properties: + + o blobId: "Id" + + The id of the blob containing the raw message [RFC5322]. + + o mailboxIds: "Id[Boolean]" + + The ids of the Mailboxes to assign this Email to. At least one + Mailbox MUST be given. + + o keywords: "String[Boolean]" (default: {}) + + The keywords to apply to the Email. + + o receivedAt: "UTCDate" (default: time of most recent Received + header, or time of import on server if none) + + The "receivedAt" date to set on the Email. + + Each Email to import is considered an atomic unit that may succeed or + fail individually. Importing successfully creates a new Email object + from the data referenced by the blobId and applies the given + Mailboxes, keywords, and receivedAt date. + + + +Jenkins & Newman Standards Track [Page 54] + +RFC 8621 JMAP Mail August 2019 + + + The server MAY forbid two Email objects with the same exact content + [RFC5322], or even just with the same Message-ID [RFC5322], to + coexist within an account. In this case, it MUST reject attempts to + import an Email considered to be a duplicate with an "alreadyExists" + SetError. An "existingId" property of type "Id" MUST be included on + the SetError object with the id of the existing Email. If duplicates + are allowed, the newly created Email object MUST have a separate id + and independent mutable properties to the existing object. + + If the "blobId", "mailboxIds", or "keywords" properties are invalid + (e.g., missing, wrong type, id not found), the server MUST reject the + import with an "invalidProperties" SetError. + + If the Email cannot be imported because it would take the account + over quota, the import should be rejected with an "overQuota" + SetError. + + If the blob referenced is not a valid message [RFC5322], the server + MAY modify the message to fix errors (such as removing NUL octets or + fixing invalid headers). If it does this, the "blobId" on the + response MUST represent the new representation and therefore be + different to the "blobId" on the EmailImport object. Alternatively, + the server MAY reject the import with an "invalidEmail" SetError. + + The response has the following arguments: + + o accountId: "Id" + + The id of the account used for this call. + + o oldState: "String|null" + + The state string that would have been returned by "Email/get" on + this account before making the requested changes, or null if the + server doesn't know what the previous state string was. + + o newState: "String" + + The state string that will now be returned by "Email/get" on this + account. + + o created: "Id[Email]|null" + + A map of the creation id to an object containing the "id", + "blobId", "threadId", and "size" properties for each successfully + imported Email, or null if none. + + + + + +Jenkins & Newman Standards Track [Page 55] + +RFC 8621 JMAP Mail August 2019 + + + o notCreated: "Id[SetError]|null" + + A map of the creation id to a SetError object for each Email that + failed to be created, or null if all successful. The possible + errors are defined above. + + The following additional errors may be returned instead of the + "Email/import" response: + + "stateMismatch": An "ifInState" argument was supplied, and it does + not match the current state. + +4.9. Email/parse + + This method allows you to parse blobs as messages [RFC5322] to get + Email objects. The server MUST support messages with EAI headers + [RFC6532]. This can be used to parse and display attached messages + without having to import them as top-level Email objects in the mail + store in their own right. + + The following metadata properties on the Email objects will be null + if requested: + + o id + + o mailboxIds + + o keywords + + o receivedAt + + The "threadId" property of the Email MAY be present if the server can + calculate which Thread the Email would be assigned to were it to be + imported. Otherwise, this too is null if fetched. + + The "Email/parse" method takes the following arguments: + + o accountId: "Id" + + The id of the account to use. + + o blobIds: "Id[]" + + The ids of the blobs to parse. + + + + + + + +Jenkins & Newman Standards Track [Page 56] + +RFC 8621 JMAP Mail August 2019 + + + o properties: "String[]" + + If supplied, only the properties listed in the array are returned + for each Email object. If omitted, defaults to: + + [ "messageId", "inReplyTo", "references", "sender", "from", "to", + "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", + "preview", "bodyValues", "textBody", "htmlBody", "attachments" ] + + o bodyProperties: "String[]" + + A list of properties to fetch for each EmailBodyPart returned. If + omitted, defaults to the same value as the "Email/get" + "bodyProperties" default argument. + + o fetchTextBodyValues: "Boolean" (default: false) + + If true, the "bodyValues" property includes any "text/*" part in + the "textBody" property. + + o fetchHTMLBodyValues: "Boolean" (default: false) + + If true, the "bodyValues" property includes any "text/*" part in + the "htmlBody" property. + + o fetchAllBodyValues: "Boolean" (default: false) + + If true, the "bodyValues" property includes any "text/*" part in + the "bodyStructure" property. + + o maxBodyValueBytes: "UnsignedInt" (default: 0) + + If greater than zero, the "value" property of any EmailBodyValue + object returned in "bodyValues" MUST be truncated if necessary so + it does not exceed this number of octets in size. If 0 (the + default), no truncation occurs. + + The server MUST ensure the truncation results in valid UTF-8 and + does not occur mid-codepoint. If the part is of type "text/html", + the server SHOULD NOT truncate inside an HTML tag, e.g., in the + middle of "". There is no + requirement for the truncated form to be a balanced tree or valid + HTML (indeed, the original source may well be neither of these + things). + + + + + + + +Jenkins & Newman Standards Track [Page 57] + +RFC 8621 JMAP Mail August 2019 + + + The response has the following arguments: + + o accountId: "Id" + + The id of the account used for the call. + + o parsed: "Id[Email]|null" + + A map of blob id to parsed Email representation for each + successfully parsed blob, or null if none. + + o notParsable: "Id[]|null" + + A list of ids given that corresponded to blobs that could not be + parsed as Emails, or null if none. + + o notFound: "Id[]|null" + + A list of blob ids given that could not be found, or null if none. + + As specified above, parsed forms of headers may only be used on + appropriate header fields. Attempting to fetch a form that is + forbidden (e.g., "header:From:asDate") MUST result in the method call + being rejected with an "invalidArguments" error. + + Where a specific header field is requested as a property, the + capitalization of the property name in the response MUST be identical + to that used in the request. + +4.10. Examples + + A client logs in for the first time. It first fetches the set of + Mailboxes. Now it will display the inbox to the user, which we will + presume has Mailbox id "fb666a55". The inbox may be (very!) large, + but the user's screen is only so big, so the client can just load the + Threads it needs to fill the screen and then load in more only when + the user scrolls. The client sends this request: + + [[ "Email/query",{ + "accountId": "ue150411c", + "filter": { + "inMailbox": "fb666a55" + }, + "sort": [{ + "isAscending": false, + "property": "receivedAt" + }], + "collapseThreads": true, + + + +Jenkins & Newman Standards Track [Page 58] + +RFC 8621 JMAP Mail August 2019 + + + "position": 0, + "limit": 30, + "calculateTotal": true + }, "0" ], + [ "Email/get", { + "accountId": "ue150411c", + "#ids": { + "resultOf": "0", + "name": "Email/query", + "path": "/ids" + }, + "properties": [ + "threadId" + ] + }, "1" ], + [ "Thread/get", { + "accountId": "ue150411c", + "#ids": { + "resultOf": "1", + "name": "Email/get", + "path": "/list/*/threadId" + } + }, "2" ], + [ "Email/get", { + "accountId": "ue150411c", + "#ids": { + "resultOf": "2", + "name": "Thread/get", + "path": "/list/*/emailIds" + }, + "properties": [ + "threadId", + "mailboxIds", + "keywords", + "hasAttachment", + "from", + "subject", + "receivedAt", + "size", + "preview" + ] + }, "3" ]] + + + + + + + + + +Jenkins & Newman Standards Track [Page 59] + +RFC 8621 JMAP Mail August 2019 + + + Let's break down the 4 method calls to see what they're doing: + + "0": This asks the server for the ids of the first 30 Email objects + in the inbox, sorted newest first, ignoring Emails from the same + Thread as a newer Email in the Mailbox (i.e., it is the first 30 + unique Threads). + + "1": Now we use a back-reference to fetch the Thread ids for each of + these Email ids. + + "2": Another back-reference fetches the Thread object for each of + these Thread ids. + + "3": Finally, we fetch the information we need to display the Mailbox + listing (but no more!) for every Email in each of these 30 Threads. + The client may aggregate this data for display, for example, by + showing the Thread as "flagged" if any of the Emails in it has the + "$flagged" keyword. + + The response from the server may look something like this: + + [[ "Email/query", { + "accountId": "ue150411c", + "queryState": "09aa9a075588-780599:0", + "canCalculateChanges": true, + "position": 0, + "total": 115, + "ids": [ "Ma783e5cdf5f2deffbc97930a", + "M9bd17497e2a99cb345fc1d0a", ... ] + }, "0" ], + [ "Email/get", { + "accountId": "ue150411c", + "state": "780599", + "list": [{ + "id": "Ma783e5cdf5f2deffbc97930a", + "threadId": "T36703c2cfe9bd5ed" + }, { + "id": "M9bd17497e2a99cb345fc1d0a", + "threadId": "T0a22ad76e9c097a1" + }, ... ], + "notFound": [] + }, "1" ], + [ "Thread/get", { + "accountId": "ue150411c", + "state": "22a8728b", + "list": [{ + "id": "T36703c2cfe9bd5ed", + "emailIds": [ "Ma783e5cdf5f2deffbc97930a" ] + + + +Jenkins & Newman Standards Track [Page 60] + +RFC 8621 JMAP Mail August 2019 + + + }, { + "id": "T0a22ad76e9c097a1", + "emailIds": [ "M3b568670a63e5d100f518fa5", + "M9bd17497e2a99cb345fc1d0a" ] + }, ... ], + "notFound": [] + }, "2" ], + [ "Email/get", { + "accountId": "ue150411c", + "state": "780599", + "list": [{ + "id": "Ma783e5cdf5f2deffbc97930a", + "threadId": "T36703c2cfe9bd5ed", + "mailboxIds": { + "fb666a55": true + }, + "keywords": { + "$seen": true, + "$flagged": true + }, + "hasAttachment": true, + "from": [{ + "email": "jdoe@example.com", + "name": "Jane Doe" + }], + "subject": "The Big Reveal", + "receivedAt": "2018-06-27T00:20:35Z", + "size": 175047, + "preview": "As you may be aware, we are required to prepare a + presentation where we wow a panel of 5 random members of the + public, on or before 30 June each year. We have drafted..." + }, + ... + ], + "notFound": [] + }, "3" ]] + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 61] + +RFC 8621 JMAP Mail August 2019 + + + Now, on another device, the user marks the first Email as unread, + sending this API request: + + [[ "Email/set", { + "accountId": "ue150411c", + "update": { + "Ma783e5cdf5f2deffbc97930a": { + "keywords/$seen": null + } + } + }, "0" ]] + + The server applies this and sends the success response: + + [[ "Email/set", { + "accountId": "ue150411c", + "oldState": "780605", + "newState": "780606", + "updated": { + "Ma783e5cdf5f2deffbc97930a": null + }, + ... + }, "0" ]] + + The user also deletes a few Emails, and then a new message arrives. + + + + + + + + + + + + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 62] + +RFC 8621 JMAP Mail August 2019 + + + Back on our original machine, we receive a push update that the state + string for Email is now "780800". As this does not match the + client's current state, it issues a request for the changes: + + [[ "Email/changes", { + "accountId": "ue150411c", + "sinceState": "780605", + "maxChanges": 50 + }, "3" ], + [ "Email/queryChanges", { + "accountId": "ue150411c", + "filter": { + "inMailbox": "fb666a55" + }, + "sort": [{ + "property": "receivedAt", + "isAscending": false + }], + "collapseThreads": true, + "sinceQueryState": "09aa9a075588-780599:0", + "upToId": "Mc2781d5e856a908d8a35a564", + "maxChanges": 25, + "calculateTotal": true + }, "11" ]] + + The response: + + [[ "Email/changes", { + "accountId": "ue150411c", + "oldState": "780605", + "newState": "780800", + "hasMoreChanges": false, + "created": [ "Me8de6c9f6de198239b982ea2" ], + "updated": [ "Ma783e5cdf5f2deffbc97930a" ], + "destroyed": [ "M9bd17497e2a99cb345fc1d0a", ... ] + }, "3" ], + [ "Email/queryChanges", { + "accountId": "ue150411c", + "oldQueryState": "09aa9a075588-780599:0", + "newQueryState": "e35e9facf117-780615:0", + "added": [{ + "id": "Me8de6c9f6de198239b982ea2", + "index": 0 + }], + "removed": [ "M9bd17497e2a99cb345fc1d0a" ], + "total": 115 + }, "11" ]] + + + + +Jenkins & Newman Standards Track [Page 63] + +RFC 8621 JMAP Mail August 2019 + + + The client can update its local cache of the query results by + removing "M9bd17497e2a99cb345fc1d0a" and then splicing in + "Me8de6c9f6de198239b982ea2" at position 0. As it does not have the + data for this new Email, it will then fetch it (it also could have + done this in the same request using back-references). + + It knows something has changed about "Ma783e5cdf5f2deffbc97930a", so + it will refetch the Mailbox ids and keywords (the only mutable + properties) for this Email too. + + The user starts composing a new Email. The email is plaintext and + the client knows the email in English so adds this metadata to the + body part. The user saves a draft while the composition is still in + progress. The client sends: + + [[ "Email/set", { + "accountId": "ue150411c", + "create": { + "k192": { + "mailboxIds": { + "2ea1ca41b38e": true + }, + "keywords": { + "$seen": true, + "$draft": true + }, + "from": [{ + "name": "Joe Bloggs", + "email": "joe@example.com" + }], + "subject": "World domination", + "receivedAt": "2018-07-10T01:03:11Z", + "sentAt": "2018-07-10T11:03:11+10:00", + "bodyStructure": { + "type": "text/plain", + "partId": "bd48", + "header:Content-Language": "en" + }, + "bodyValues": { + "bd48": { + "value": "I have the most brilliant plan. Let me tell + you all about it. What we do is, we", + "isTruncated": false + } + } + } + } + }, "0" ]] + + + +Jenkins & Newman Standards Track [Page 64] + +RFC 8621 JMAP Mail August 2019 + + + The server creates the message and sends the success response: + + [[ "Email/set", { + "accountId": "ue150411c", + "oldState": "780823", + "newState": "780839", + "created": { + "k192": { + "id": "Mf40b5f831efa7233b9eb1c7f", + "blobId": "Gf40b5f831efa7233b9eb1c7f8f97d84eeeee64f7", + "threadId": "Td957e72e89f516dc", + "size": 359 + } + }, + ... + }, "0" ]] + + The message created on the server looks something like this: + + Message-Id: + User-Agent: Cyrus-JMAP/3.1.6-736-gdfb8e44 + Mime-Version: 1.0 + Date: Tue, 10 Jul 2018 11:03:11 +1000 + From: "Joe Bloggs" + Subject: World domination + Content-Language: en + Content-Type: text/plain + + I have the most brilliant plan. Let me tell you all about it. What we + do is, we + + The user adds a recipient and converts the message to HTML so they + can add formatting, then saves an updated draft: + + [[ "Email/set", { + "accountId": "ue150411c", + "create": { + "k1546": { + "mailboxIds": { + "2ea1ca41b38e": true + }, + "keywords": { + "$seen": true, + "$draft": true + }, + "from": [{ + "name": "Joe Bloggs", + "email": "joe@example.com" + + + +Jenkins & Newman Standards Track [Page 65] + +RFC 8621 JMAP Mail August 2019 + + + }], + "to": [{ + "name": "John", + "email": "john@example.com" + }], + "subject": "World domination", + "receivedAt": "2018-07-10T01:05:08Z", + "sentAt": "2018-07-10T11:05:08+10:00", + "bodyStructure": { + "type": "multipart/alternative", + "subParts": [{ + "partId": "a49d", + "type": "text/html", + "header:Content-Language": "en" + }, { + "partId": "bd48", + "type": "text/plain", + "header:Content-Language": "en" + }] + }, + "bodyValues": { + "bd48": { + "value": "I have the most brilliant plan. Let me tell + you all about it. What we do is, we", + "isTruncated": false + }, + "a49d": { + "value": " + +

+ ", + "isTruncated": false + } + } + } + }, + "destroy": [ "Mf40b5f831efa7233b9eb1c7f" ] + }, "0" ]] + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 66] + +RFC 8621 JMAP Mail August 2019 + + + The server creates the new draft, deletes the old one, and sends the + success response: + + [[ "Email/set", { + "accountId": "ue150411c", + "oldState": "780839", + "newState": "780842", + "created": { + "k1546": { + "id": "Md45b47b4877521042cec0938", + "blobId": "Ge8de6c9f6de198239b982ea214e0f3a704e4af74", + "threadId": "Td957e72e89f516dc", + "size": 11721 + } + }, + "destroyed": [ "Mf40b5f831efa7233b9eb1c7f" ], + ... + }, "0" ]] + + The client moves this draft to a different account. The only way to + do this is via the "Email/copy" method. It MUST set a new + "mailboxIds" property, since the current value will not be valid + Mailbox ids in the destination account: + + [[ "Email/copy", { + "fromAccountId": "ue150411c", + "accountId": "u6c6c41ac", + "create": { + "k45": { + "id": "Md45b47b4877521042cec0938", + "mailboxIds": { + "75a4c956": true + } + } + }, + "onSuccessDestroyOriginal": true + }, "0" ]] + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 67] + +RFC 8621 JMAP Mail August 2019 + + + The server successfully copies the Email and deletes the original. + Due to the implicit call to "Email/set", there are two responses to + the single method call, both with the same method call id: + + [[ "Email/copy", { + "fromAccountId": "ue150411c", + "accountId": "u6c6c41ac", + "oldState": "7ee7e9263a6d", + "newState": "5a0d2447ed26", + "created": { + "k45": { + "id": "M138f9954a5cd2423daeafa55", + "blobId": "G6b9fb047cba722c48c611e79233d057c6b0b74e8", + "threadId": "T2f242ea424a4079a", + "size": 11721 + } + }, + "notCreated": null + }, "0" ], + [ "Email/set", { + "accountId": "ue150411c", + "oldState": "780842", + "newState": "780871", + "destroyed": [ "Md45b47b4877521042cec0938" ], + ... + }, "0" ]] + +5. Search Snippets + + When doing a search on a "String" property, the client may wish to + show the relevant section of the body that matches the search as a + preview and to highlight any matching terms in both this and the + subject of the Email. Search snippets represent this data. + + A *SearchSnippet* object has the following properties: + + o emailId: "Id" + + The Email id the snippet applies to. + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 68] + +RFC 8621 JMAP Mail August 2019 + + + o subject: "String|null" + + If text from the filter matches the subject, this is the subject + of the Email with the following transformations: + + 1. Any instance of the following three characters MUST be + replaced by an appropriate HTML entity: & (ampersand), < + (less-than sign), and > (greater-than sign) [HTML]. Other + characters MAY also be replaced with an HTML entity form. + + 2. The matching words/phrases from the filter are wrapped in HTML + "" tags. + + If the subject does not match text from the filter, this property + is null. + + o preview: "String|null" + + If text from the filter matches the plaintext or HTML body, this + is the relevant section of the body (converted to plaintext if + originally HTML), with the same transformations as the "subject" + property. It MUST NOT be bigger than 255 octets in size. If the + body does not contain a match for the text from the filter, this + property is null. + + What is a relevant section of the body for preview is server defined. + If the server is unable to determine search snippets, it MUST return + null for both the "subject" and "preview" properties. + + Note that unlike most data types, a SearchSnippet DOES NOT have a + property called "id". + + The following JMAP method is supported. + +5.1. SearchSnippet/get + + To fetch search snippets, make a call to "SearchSnippet/get". It + takes the following arguments: + + o accountId: "Id" + + The id of the account to use. + + o filter: "FilterOperator|FilterCondition|null" + + The same filter as passed to "Email/query"; see the description of + this method in Section 4.4 for details. + + + + +Jenkins & Newman Standards Track [Page 69] + +RFC 8621 JMAP Mail August 2019 + + + o emailIds: "Id[]" + + The ids of the Emails to fetch snippets for. + + The response has the following arguments: + + o accountId: "Id" + + The id of the account used for the call. + + o list: "SearchSnippet[]" + + An array of SearchSnippet objects for the requested Email ids. + This may not be in the same order as the ids that were in the + request. + + o notFound: "Id[]|null" + + An array of Email ids requested that could not be found, or null + if all ids were found. + + As the search snippets are derived from the message content and the + algorithm for doing so could change over time, fetching the same + snippets a second time MAY return a different result. However, the + previous value is not considered incorrect, so there is no state + string or update mechanism needed. + + The following additional errors may be returned instead of the + "SearchSnippet/get" response: + + "requestTooLarge": The number of "emailIds" requested by the client + exceeds the maximum number the server is willing to process in a + single method call. + + "unsupportedFilter": The server is unable to process the given + "filter" for any reason. + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 70] + +RFC 8621 JMAP Mail August 2019 + + +5.2. Example + + Here, we did an "Email/query" to search for any Email in the account + containing the word "foo"; now, we are fetching the search snippets + for some of the ids that were returned in the results: + + [[ "SearchSnippet/get", { + "accountId": "ue150411c", + "filter": { + "text": "foo" + }, + "emailIds": [ + "M44200ec123de277c0c1ce69c", + "M7bcbcb0b58d7729686e83d99", + "M28d12783a0969584b6deaac0", + ... + ] + }, "0" ]] + + Example response: + + [[ "SearchSnippet/get", { + "accountId": "ue150411c", + "list": [{ + "emailId": "M44200ec123de277c0c1ce69c", + "subject": null, + "preview": null + }, { + "emailId": "M7bcbcb0b58d7729686e83d99", + "subject": "The Foosball competition", + "preview": "...year the foosball competition will + be held in the Stadium de ..." + }, { + "emailId": "M28d12783a0969584b6deaac0", + "subject": null, + "preview": "...the Foo/bar method results often + returns <1 widget rather than the complete..." + }, + ... + ], + "notFound": null + }, "0" ]] + + + + + + + + + +Jenkins & Newman Standards Track [Page 71] + +RFC 8621 JMAP Mail August 2019 + + +6. Identities + + An *Identity* object stores information about an email address or + domain the user may send from. It has the following properties: + + o id: "Id" (immutable; server-set) + + The id of the Identity. + + o name: "String" (default: "") + + The "From" name the client SHOULD use when creating a new Email + from this Identity. + + o email: "String" (immutable) + + The "From" email address the client MUST use when creating a new + Email from this Identity. If the "mailbox" part of the address + (the section before the "@") is the single character "*" (e.g., + "*@example.com"), the client may use any valid address ending in + that domain (e.g., "foo@example.com"). + + o replyTo: "EmailAddress[]|null" (default: null) + + The Reply-To value the client SHOULD set when creating a new Email + from this Identity. + + o bcc: "EmailAddress[]|null" (default: null) + + The Bcc value the client SHOULD set when creating a new Email from + this Identity. + + o textSignature: "String" (default: "") + + A signature the client SHOULD insert into new plaintext messages + that will be sent from this Identity. Clients MAY ignore this + and/or combine this with a client-specific signature preference. + + o htmlSignature: "String" (default: "") + + A signature the client SHOULD insert into new HTML messages that + will be sent from this Identity. This text MUST be an HTML + snippet to be inserted into the "" section of the + HTML. Clients MAY ignore this and/or combine this with a client- + specific signature preference. + + + + + + +Jenkins & Newman Standards Track [Page 72] + +RFC 8621 JMAP Mail August 2019 + + + o mayDelete: "Boolean" (server-set) + + Is the user allowed to delete this Identity? Servers may wish to + set this to false for the user's username or other default + address. Attempts to destroy an Identity with "mayDelete: false" + will be rejected with a standard "forbidden" SetError. + + See the "Addresses" header form description in the Email object + (Section 4.1.2.3) for the definition of EmailAddress. + + Multiple identities with the same email address MAY exist, to allow + for different settings the user wants to pick between (for example, + with different names/signatures). + + The following JMAP methods are supported. + +6.1. Identity/get + + This is a standard "/get" method as described in [RFC8620], + Section 5.1. The "ids" argument may be null to fetch all at once. + +6.2. Identity/changes + + This is a standard "/changes" method as described in [RFC8620], + Section 5.2. + +6.3. Identity/set + + This is a standard "/set" method as described in [RFC8620], + Section 5.3. The following extra SetError types are defined: + + For "create": + + o "forbiddenFrom": The user is not allowed to send from the address + given as the "email" property of the Identity. + +6.4. Example + + Request: + + [ "Identity/get", { + "accountId": "acme" + }, "0" ] + + + + + + + + +Jenkins & Newman Standards Track [Page 73] + +RFC 8621 JMAP Mail August 2019 + + + with response: + + [ "Identity/get", { + "accountId": "acme", + "state": "99401312ae-11-333", + "list": [ + { + "id": "XD-3301-222-11_22AAz", + "name": "Joe Bloggs", + "email": "joe@example.com", + "replyTo": null, + "bcc": [{ + "name": null, + "email": "joe+archive@example.com" + }], + "textSignature": "-- \nJoe Bloggs\nMaster of Email", + "htmlSignature": "
Joe Bloggs
+
Master of Email
", + "mayDelete": false + }, + { + "id": "XD-9911312-11_22AAz", + "name": "Joe B", + "email": "*@example.com", + "replyTo": null, + "bcc": null, + "textSignature": "", + "htmlSignature": "", + "mayDelete": true + } + ], + "notFound": [] + }, "0" ] + +7. Email Submission + + An *EmailSubmission* object represents the submission of an Email for + delivery to one or more recipients. It has the following properties: + + o id: "Id" (immutable; server-set) + + The id of the EmailSubmission. + + o identityId: "Id" (immutable) + + The id of the Identity to associate with this submission. + + + + + +Jenkins & Newman Standards Track [Page 74] + +RFC 8621 JMAP Mail August 2019 + + + o emailId: "Id" (immutable) + + The id of the Email to send. The Email being sent does not have + to be a draft, for example, when "redirecting" an existing Email + to a different address. + + o threadId: "Id" (immutable; server-set) + + The Thread id of the Email to send. This is set by the server to + the "threadId" property of the Email referenced by the "emailId". + + o envelope: "Envelope|null" (immutable) + + Information for use when sending via SMTP. An *Envelope* object + has the following properties: + + * mailFrom: "Address" + + The email address to use as the return address in the SMTP + submission, plus any parameters to pass with the MAIL FROM + address. The JMAP server MAY allow the address to be the empty + string. + + When a JMAP server performs an SMTP message submission, it MAY + use the same id string for the ENVID parameter [RFC3461] and + the EmailSubmission object id. Servers that do this MAY + replace a client-provided value for ENVID with a server- + provided value. + + * rcptTo: "Address[]" + + The email addresses to send the message to, and any RCPT TO + parameters to pass with the recipient. + + An *Address* object has the following properties: + + * email: "String" + + The email address being represented by the object. This is a + "Mailbox" as used in the Reverse-path or Forward-path of the + MAIL FROM or RCPT TO command in [RFC5321]. + + * parameters: "Object|null" + + Any parameters to send with the email address (either mail- + parameter or rcpt-parameter as appropriate, as specified in + [RFC5321]). If supplied, each key in the object is a parameter + name, and the value is either the parameter value (type + + + +Jenkins & Newman Standards Track [Page 75] + +RFC 8621 JMAP Mail August 2019 + + + "String") or null if the parameter does not take a value. For + both name and value, any xtext or unitext encodings are removed + (see [RFC3461] and [RFC6533]) and JSON string encoding is + applied. + + If the "envelope" property is null or omitted on creation, the + server MUST generate this from the referenced Email as follows: + + * "mailFrom": The email address in the Sender header field, if + present; otherwise, it's the email address in the From header + field, if present. In either case, no parameters are added. + + If multiple addresses are present in one of these header + fields, or there is more than one Sender/From header field, the + server SHOULD reject the EmailSubmission as invalid; otherwise, + it MUST take the first address in the last Sender/From header + field. + + If the address found from this is not allowed by the Identity + associated with this submission, the "email" property from the + Identity MUST be used instead. + + * "rcptTo": The deduplicated set of email addresses from the To, + Cc, and Bcc header fields, if present, with no parameters for + any of them. + + o sendAt: "UTCDate" (immutable; server-set) + + The date the submission was/will be released for delivery. If the + client successfully used FUTURERELEASE [RFC4865] with the + submission, this MUST be the time when the server will release the + message; otherwise, it MUST be the time the EmailSubmission was + created. + + o undoStatus: "String" + + This represents whether the submission may be canceled. This is + server set on create and MUST be one of the following values: + + * "pending": It may be possible to cancel this submission. + + * "final": The message has been relayed to at least one recipient + in a manner that cannot be recalled. It is no longer possible + to cancel this submission. + + * "canceled": The submission was canceled and will not be + delivered to any recipient. + + + + +Jenkins & Newman Standards Track [Page 76] + +RFC 8621 JMAP Mail August 2019 + + + On systems that do not support unsending, the value of this + property will always be "final". On systems that do support + canceling submission, it will start as "pending" and MAY + transition to "final" when the server knows it definitely cannot + recall the message, but it MAY just remain "pending". If in + pending state, a client can attempt to cancel the submission by + setting this property to "canceled"; if the update succeeds, the + submission was successfully canceled, and the message has not been + delivered to any of the original recipients. + + o deliveryStatus: "String[DeliveryStatus]|null" (server-set) + + This represents the delivery status for each of the submission's + recipients, if known. This property MAY not be supported by all + servers, in which case it will remain null. Servers that support + it SHOULD update the EmailSubmission object each time the status + of any of the recipients changes, even if some recipients are + still being retried. + + This value is a map from the email address of each recipient to a + DeliveryStatus object. + + A *DeliveryStatus* object has the following properties: + + * smtpReply: "String" + + The SMTP reply string returned for this recipient when the + server last tried to relay the message, or in a later Delivery + Status Notification (DSN, as defined in [RFC3464]) response for + the message. This SHOULD be the response to the RCPT TO stage, + unless this was accepted and the message as a whole was + rejected at the end of the DATA stage, in which case the DATA + stage reply SHOULD be used instead. + + Multi-line SMTP responses should be concatenated to a single + string as follows: + + + The hyphen following the SMTP code on all but the last line + is replaced with a space. + + + Any prefix in common with the first line is stripped from + lines after the first. + + + CRLF is replaced by a space. + + + + + + + +Jenkins & Newman Standards Track [Page 77] + +RFC 8621 JMAP Mail August 2019 + + + For example: + + 550-5.7.1 Our system has detected that this message is + 550 5.7.1 likely spam. + + would become: + + 550 5.7.1 Our system has detected that this message is likely spam. + + For messages relayed via an alternative to SMTP, the server MAY + generate a synthetic string representing the status instead. + If it does this, the string MUST be of the following form: + + + A 3-digit SMTP reply code, as defined in [RFC5321], + Section 4.2.3. + + + Then a single space character. + + + Then an SMTP Enhanced Mail System Status Code as defined in + [RFC3463], with a registry defined in [RFC5248]. + + + Then a single space character. + + + Then an implementation-specific information string with a + human-readable explanation of the response. + + * delivered: "String" + + Represents whether the message has been successfully delivered + to the recipient. This MUST be one of the following values: + + + "queued": The message is in a local mail queue and the + status will change once it exits the local mail queues. The + "smtpReply" property may still change. + + + "yes": The message was successfully delivered to the mail + store of the recipient. The "smtpReply" property is final. + + + "no": Delivery to the recipient permanently failed. The + "smtpReply" property is final. + + + "unknown": The final delivery status is unknown, (e.g., it + was relayed to an external machine and no further + information is available). The "smtpReply" property may + still change if a DSN arrives. + + + + + + +Jenkins & Newman Standards Track [Page 78] + +RFC 8621 JMAP Mail August 2019 + + + Note that successful relaying to an external SMTP server SHOULD + NOT be taken as an indication that the message has successfully + reached the final mail store. In this case though, the server + may receive a DSN response, if requested. + + If a DSN is received for the recipient with Action equal to + "delivered", as per [RFC3464], Section 2.3.3, then the + "delivered" property SHOULD be set to "yes"; if the Action + equals "failed", the property SHOULD be set to "no". Receipt + of any other DSN SHOULD NOT affect this property. + + The server MAY also set this property based on other feedback + channels. + + * displayed: "String" + + Represents whether the message has been displayed to the + recipient. This MUST be one of the following values: + + + "unknown": The display status is unknown. This is the + initial value. + + + "yes": The recipient's system claims the message content has + been displayed to the recipient. Note that there is no + guarantee that the recipient has noticed, read, or + understood the content. + + If a Message Disposition Notification (MDN) is received for + this recipient with Disposition-Type (as per [RFC8098], + Section 3.2.6.2) equal to "displayed", this property SHOULD be + set to "yes". + + The server MAY also set this property based on other feedback + channels. + + o dsnBlobIds: "Id[]" (server-set) + + A list of blob ids for DSNs [RFC3464] received for this + submission, in order of receipt, oldest first. The blob is the + whole MIME message (with a top-level content-type of "multipart/ + report"), as received. + + o mdnBlobIds: "Id[]" (server-set) + + A list of blob ids for MDNs [RFC8098] received for this + submission, in order of receipt, oldest first. The blob is the + whole MIME message (with a top-level content-type of "multipart/ + report"), as received. + + + +Jenkins & Newman Standards Track [Page 79] + +RFC 8621 JMAP Mail August 2019 + + + JMAP servers MAY choose not to expose DSN and MDN responses as Email + objects if they correlate to an EmailSubmission object. It SHOULD + only do this if it exposes them in the "dsnBlobIds" and "mdnblobIds" + fields instead, and it expects the user to be using clients capable + of fetching and displaying delivery status via the EmailSubmission + object. + + For efficiency, a server MAY destroy EmailSubmission objects at any + time after the message is successfully sent or after it has finished + retrying to send the message. For very basic SMTP proxies, this MAY + be immediately after creation, as it has no way to assign a real id + and return the information again if fetched later. + + The following JMAP methods are supported. + +7.1. EmailSubmission/get + + This is a standard "/get" method as described in [RFC8620], + Section 5.1. + +7.2. EmailSubmission/changes + + This is a standard "/changes" method as described in [RFC8620], + Section 5.2. + +7.3. EmailSubmission/query + + This is a standard "/query" method as described in [RFC8620], + Section 5.5. + + A *FilterCondition* object has the following properties, any of which + may be omitted: + + o identityIds: "Id[]" + + The EmailSubmission "identityId" property must be in this list to + match the condition. + + o emailIds: "Id[]" + + The EmailSubmission "emailId" property must be in this list to + match the condition. + + o threadIds: "Id[]" + + The EmailSubmission "threadId" property must be in this list to + match the condition. + + + + +Jenkins & Newman Standards Track [Page 80] + +RFC 8621 JMAP Mail August 2019 + + + o undoStatus: "String" + + The EmailSubmission "undoStatus" property must be identical to the + value given to match the condition. + + o before: "UTCDate" + + The "sendAt" property of the EmailSubmission object must be before + this date-time to match the condition. + + o after: "UTCDate" + + The "sendAt" property of the EmailSubmission object must be the + same as or after this date-time to match the condition. + + An EmailSubmission object matches the FilterCondition if and only if + all of the given conditions match. If zero properties are specified, + it is automatically true for all objects. + + The following EmailSubmission properties MUST be supported for + sorting: + + o "emailId" + + o "threadId" + + o "sentAt" + +7.4. EmailSubmission/queryChanges + + This is a standard "/queryChanges" method as described in [RFC8620], + Section 5.6. + +7.5. EmailSubmission/set + + This is a standard "/set" method as described in [RFC8620], + Section 5.3 with the following two additional request arguments: + + o onSuccessUpdateEmail: "Id[PatchObject]|null" + + A map of EmailSubmission id to an object containing properties to + update on the Email object referenced by the EmailSubmission if + the create/update/destroy succeeds. (For references to + EmailSubmissions created in the same "/set" invocation, this is + equivalent to a creation-reference, so the id will be the creation + id prefixed with a "#".) + + + + + +Jenkins & Newman Standards Track [Page 81] + +RFC 8621 JMAP Mail August 2019 + + + o onSuccessDestroyEmail: "Id[]|null" + + A list of EmailSubmission ids for which the Email with the + corresponding "emailId" should be destroyed if the create/update/ + destroy succeeds. (For references to EmailSubmission creations, + this is equivalent to a creation-reference, so the id will be the + creation id prefixed with a "#".) + + After all create/update/destroy items in the "EmailSubmission/set" + invocation have been processed, a single implicit "Email/set" call + MUST be made to perform any changes requested in these two arguments. + The response to this MUST be returned after the "EmailSubmission/set" + response. + + An Email is sent by creating an EmailSubmission object. When + processing each create, the server must check that the message is + valid, and the user has sufficient authorisation to send it. If the + creation succeeds, the message will be sent to the recipients given + in the envelope "rcptTo" parameter. The server MUST remove any Bcc + header field present on the message during delivery. The server MAY + add or remove other header fields from the submitted message or make + further alterations in accordance with the server's policy during + delivery. + + If the referenced Email is destroyed at any point after the + EmailSubmission object is created, this MUST NOT change the behaviour + of the submission (i.e., it does not cancel a future send). The + "emailId" and "threadId" properties of the EmailSubmission object + remain, but trying to fetch them (with a standard "Email/get" call) + will return a "notFound" error if the corresponding objects have been + destroyed. + + Similarly, destroying an EmailSubmission object MUST NOT affect the + deliveries it represents. It purely removes the record of the + submission. The server MAY automatically destroy EmailSubmission + objects after some time or in response to other triggers, and MAY + forbid the client from manually destroying EmailSubmission objects. + + If the message to be sent is larger than the server supports sending, + a standard "tooLarge" SetError MUST be returned. A "maxSize" + "UnsignedInt" property MUST be present on the SetError specifying the + maximum size of a message that may be sent, in octets. + + If the Email or Identity id given cannot be found, the submission + creation is rejected with a standard "invalidProperties" SetError. + + + + + + +Jenkins & Newman Standards Track [Page 82] + +RFC 8621 JMAP Mail August 2019 + + + The following extra SetError types are defined: + + For "create": + + o "invalidEmail" - The Email to be sent is invalid in some way. The + SetError SHOULD contain a property called "properties" of type + "String[]" that lists *all* the properties of the Email that were + invalid. + + o "tooManyRecipients" - The envelope (supplied or generated) has + more recipients than the server allows. A "maxRecipients" + "UnsignedInt" property MUST also be present on the SetError + specifying the maximum number of allowed recipients. + + o "noRecipients" - The envelope (supplied or generated) does not + have any rcptTo email addresses. + + o "invalidRecipients" - The "rcptTo" property of the envelope + (supplied or generated) contains at least one rcptTo value, which + is not a valid email address for sending to. An + "invalidRecipients" "String[]" property MUST also be present on + the SetError, which is a list of the invalid addresses. + + o "forbiddenMailFrom" - The server does not permit the user to send + a message with the envelope From address [RFC5321]. + + o "forbiddenFrom" - The server does not permit the user to send a + message with the From header field [RFC5322] of the message to be + sent. + + o "forbiddenToSend" - The user does not have permission to send at + all right now for some reason. A "description" "String" property + MAY be present on the SetError object to display to the user why + they are not permitted. + + For "update": + + o "cannotUnsend" - The client attempted to update the "undoStatus" + of a valid EmailSubmission object from "pending" to "canceled", + but the message cannot be unsent. + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 83] + +RFC 8621 JMAP Mail August 2019 + + +7.5.1. Example + + The following example presumes a draft of the Email to be sent has + already been saved, and its Email id is "M7f6ed5bcfd7e2604d1753f6c". + This call then sends the Email immediately, and if successful, + removes the "$draft" flag and moves it from the drafts folder (which + has Mailbox id "7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e") to the sent + folder (which we presume has Mailbox id "73dbcb4b-bffc-48bd-8c2a- + a2e91ca672f6"). + + [[ "EmailSubmission/set", { + "accountId": "ue411d190", + "create": { + "k1490": { + "identityId": "I64588216", + "emailId": "M7f6ed5bcfd7e2604d1753f6c", + "envelope": { + "mailFrom": { + "email": "john@example.com", + "parameters": null + }, + "rcptTo": [{ + "email": "jane@example.com", + "parameters": null + }, + ... + ] + } + } + }, + "onSuccessUpdateEmail": { + "#k1490": { + "mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null, + "mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true, + "keywords/$draft": null + } + } + }, "0" ]] + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 84] + +RFC 8621 JMAP Mail August 2019 + + + A successful response might look like this. Note that there are two + responses due to the implicit "Email/set" call, but both have the + same method call id as they are due to the same call in the request: + + [[ "EmailSubmission/set", { + "accountId": "ue411d190", + "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", + "newState": "355421f6-8aed-4cf4-a0c4-7377e951af36", + "created": { + "k1490": { + "id": "ES-3bab7f9a-623e-4acf-99a5-2e67facb02a0" + } + } + }, "0" ], + [ "Email/set", { + "accountId": "ue411d190", + "oldState": "778193", + "newState": "778197", + "updated": { + "M7f6ed5bcfd7e2604d1753f6c": null + } + }, "0" ]] + + Suppose instead an admin has removed sending rights for the user, so + the submission is rejected with a "forbiddenToSend" error. The + description argument of the error is intended for display to the + user, so it should be localised appropriately. Let's suppose the + request was sent with an Accept-Language header like this: + + Accept-Language: de;q=0.9,en;q=0.8 + + + + + + + + + + + + + + + + + + + + + +Jenkins & Newman Standards Track [Page 85] + +RFC 8621 JMAP Mail August 2019 + + + The server should attempt to choose the best localisation from those + it has available based on the Accept-Language header, as described in + [RFC8620], Section 3.8. If the server has English, French, and + German translations, it would choose German as the preferred language + and return a response like this: + +[[ "EmailSubmission/set", { + "accountId": "ue411d190", + "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", + "newState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", + "notCreated": { + "k1490": { + "type": "forbiddenToSend", + "description": "Verzeihung, wegen verdaechtiger Aktivitaeten Ihres + Benutzerkontos haben wir den Versand von Nachrichten gesperrt. + Bitte wenden Sie sich fuer Hilfe an unser Support Team." + } + } +}, "0" ]] + +8. Vacation Response + + A vacation response sends an automatic reply when a message is + delivered to the mail store, informing the original sender that their + message may not be read for some time. + + Automated message sending can produce undesirable behaviour. To + avoid this, implementors MUST follow the recommendations set forth in + [RFC3834]. + + The *VacationResponse* object represents the state of vacation- + response-related settings for an account. It has the following + properties: + + o id: "Id" (immutable; server-set) + + The id of the object. There is only ever one VacationResponse + object, and its id is "singleton". + + o isEnabled: "Boolean" + + Should a vacation response be sent if a message arrives between + the "fromDate" and "toDate"? + + + + + + + + +Jenkins & Newman Standards Track [Page 86] + +RFC 8621 JMAP Mail August 2019 + + + o fromDate: "UTCDate|null" + + If "isEnabled" is true, messages that arrive on or after this + date-time (but before the "toDate" if defined) should receive the + user's vacation response. If null, the vacation response is + effective immediately. + + o toDate: "UTCDate|null" + + If "isEnabled" is true, messages that arrive before this date-time + (but on or after the "fromDate" if defined) should receive the + user's vacation response. If null, the vacation response is + effective indefinitely. + + o subject: "String|null" + + The subject that will be used by the message sent in response to + messages when the vacation response is enabled. If null, an + appropriate subject SHOULD be set by the server. + + o textBody: "String|null" + + The plaintext body to send in response to messages when the + vacation response is enabled. If this is null, the server SHOULD + generate a plaintext body part from the "htmlBody" when sending + vacation responses but MAY choose to send the response as HTML + only. If both "textBody" and "htmlBody" are null, an appropriate + default body SHOULD be generated for responses by the server. + + o htmlBody: "String|null" + + The HTML body to send in response to messages when the vacation + response is enabled. If this is null, the server MAY choose to + generate an HTML body part from the "textBody" when sending + vacation responses or MAY choose to send the response as plaintext + only. + + The following JMAP methods are supported. + +8.1. VacationResponse/get + + This is a standard "/get" method as described in [RFC8620], + Section 5.1. + + There MUST only be exactly one VacationResponse object in an account. + It MUST have the id "singleton". + + + + + +Jenkins & Newman Standards Track [Page 87] + +RFC 8621 JMAP Mail August 2019 + + +8.2. VacationResponse/set + + This is a standard "/set" method as described in [RFC8620], + Section 5.3. + +9. Security Considerations + + All security considerations of JMAP [RFC8620] apply to this + specification. Additional considerations specific to the data types + and functionality introduced by this document are described in the + following subsections. + +9.1. EmailBodyPart Value + + Service providers typically perform security filtering on incoming + messages, and it's important that the detection of content-type and + charset for the security filter aligns with the heuristics performed + by JMAP servers. Servers that apply heuristics to determine the + content-type or charset for an EmailBodyValue SHOULD document the + heuristics and provide a mechanism to turn them off in the event they + are misaligned with the security filter used at a particular mail + host. + + Automatic conversion of charsets that allow hidden channels for ASCII + text, such as UTF-7, have been problematic for security filters in + the past, so server implementations can mitigate this risk by having + such conversions off-by-default and/or separately configurable. + + To allow the client to restrict the volume of data it can receive in + response to a request, a maximum length may be requested for the data + returned for a textual body part. However, truncating the data may + change the semantic meaning, for example, truncating a URL changes + its location. Servers that scan for links to malicious sites should + take care to either ensure truncation is not at a semantically + significant point or rescan the truncated value for malicious content + before returning it. + +9.2. HTML Email Display + + HTML message bodies provide richer formatting for messages but + present a number of security challenges, especially when embedded in + a webmail context in combination with interface HTML. Clients that + render HTML messages should carefully consider the potential risks, + including: + + + + + + + +Jenkins & Newman Standards Track [Page 88] + +RFC 8621 JMAP Mail August 2019 + + + o Embedded JavaScript can rewrite the message to change its content + on subsequent opening, allowing users to be mislead. In webmail + systems, if run in the same origin as the interface, it can access + and exfiltrate all private data accessible to the user, including + all other messages and potentially contacts, calendar events, + settings, and credentials. It can also rewrite the interface to + undetectably phish passwords. A compromise is likely to be + persistent, not just for the duration of page load, due to + exfiltration of session credentials or installation of a service + worker that can intercept all subsequent network requests + (however, this would only be possible if blob downloads are also + available on the same origin, and the service worker script is + attached to the message). + + o HTML documents may load content directly from the Internet rather + than just referencing attached resources. For example, you may + have an "" tag with an external "src" attribute. This may + leak to the sender when a message is opened, as well as the IP + address of the recipient. Cookies may also be sent and set by the + server, allowing tracking between different messages and even + website visits and advertising profiles. + + o In webmail systems, CSS can break the layout or create phishing + vulnerabilities. For example, the use of "position:fixed" can + allow a message to draw content outside of its normal bounds, + potentially clickjacking a real interface element. + + o If in a webmail context and not inside a separate frame, any + styles defined in CSS rules will apply to interface elements as + well if the selector matches, allowing the interface to be + modified. Similarly, any interface styles that match elements in + the message will alter their appearance, potentially breaking the + layout of the message. + + o The link text in HTML has no necessary correlation with the actual + target of the link, which can be used to make phishing attacks + more convincing. + + o Links opened from a message or embedded external content may leak + private info in the Referer header sent by default in most + systems. + + o Forms can be used to mimic login boxes, providing a potent + phishing vector if allowed to submit directly from the message + display. + + + + + + +Jenkins & Newman Standards Track [Page 89] + +RFC 8621 JMAP Mail August 2019 + + + There are a number of ways clients can mitigate these issues, and a + defence-in-depth approach that uses a combination of techniques will + provide the strongest security. + + o HTML can be filtered before rendering, stripping potentially + malicious content. Sanitising HTML correctly is tricky, and + implementors are strongly recommended to use a well-tested library + with a carefully vetted whitelist-only approach. New features + with unexpected security characteristics may be added to HTML + rendering engines in the future; a blacklist approach is likely to + result in security issues. + + Subtle differences in parsing of HTML can introduce security + flaws: to filter with 100% accuracy, you need to use the same + parser that the HTML rendering engine will use. + + o Encapsulating the message in an "