6052 lines
196 KiB
Plaintext
6052 lines
196 KiB
Plaintext
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
<https://www.iana.org/assignments/mail-parameters>.
|
|
|
|
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
|
|
<https://www.iana.org/assignments/imap-mailbox-name-attributes/>,
|
|
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
|
|
<https://www.iana.org/assignments/imap-jmap-keywords/> 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" <james@example.com>, Friends:
|
|
jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?=
|
|
<john@example.com>;
|
|
|
|
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" <james@example.com>, Friends:
|
|
jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?=
|
|
<john@example.com>;
|
|
|
|
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 "<a href="https://example.com">". 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": "<html><body><p>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 "<head>" 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 "<a href="https://example.com">". 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: <bbce0ae9-58be-4b24-ac82-deb840d58016@sloti7d1t02>
|
|
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" <joe@example.com>
|
|
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": "<!DOCTYPE html><html><head><title></title>
|
|
<style type=\"text/css\">div{font-size:16px}</style></head>
|
|
<body><div>I have the most <b>brilliant</b> plan. Let me
|
|
tell you all about it. What we do is, we</div></body>
|
|
</html>",
|
|
"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
|
|
"<mark></mark>" 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 <mark>Foo</mark>sball competition",
|
|
"preview": "...year the <mark>foo</mark>sball competition will
|
|
be held in the Stadium de ..."
|
|
}, {
|
|
"emailId": "M28d12783a0969584b6deaac0",
|
|
"subject": null,
|
|
"preview": "...the <mark>Foo</mark>/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 "<body></body>" 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": "<div><b>Joe Bloggs</b></div>
|
|
<div>Master of Email</div>",
|
|
"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 "<img>" 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 "<iframe sandbox>", as defined in
|
|
[HTML], Section 4.7.6, can help mitigate a number of risks. This
|
|
will:
|
|
|
|
* Disable JavaScript.
|
|
|
|
* Disable form submission.
|
|
|
|
* Prevent drawing outside of its bounds or conflicts between
|
|
message CSS and interface CSS.
|
|
|
|
* Establish a unique anonymous origin, separate to the containing
|
|
origin.
|
|
|
|
o A strong Content Security Policy (see <https://www.w3.org/TR/
|
|
CSP3/>) can, among other things, block JavaScript and the loading
|
|
of external content should it manage to evade the filter.
|
|
|
|
o The leakage of information in the Referer header can be mitigated
|
|
with the use of a referrer policy (see <https://www.w3.org/TR/
|
|
referrer-policy/>).
|
|
|
|
o A "crossorigin=anonymous" attribute on tags that load remote
|
|
content can prevent cookies from being sent.
|
|
|
|
o If adding "target=_blank" to open links in new tabs, also add
|
|
"rel=noopener" to ensure the page that opens cannot change the URL
|
|
in the original tab to redirect the user to a phishing site.
|
|
|
|
As highly complex software components, HTML rendering engines
|
|
increase the attack surface of a client considerably, especially when
|
|
being used to process untrusted, potentially malicious content.
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 90]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
Serious bugs have been found in image decoders, JavaScript engines,
|
|
and HTML parsers in the past, which could lead to full system
|
|
compromise. Clients using an engine should ensure they get the
|
|
latest version and continue to incorporate any security patches
|
|
released by the vendor.
|
|
|
|
9.3. Multiple Part Display
|
|
|
|
Messages may consist of multiple parts to be displayed sequentially
|
|
as a body. Clients MUST render each part in isolation and MUST NOT
|
|
concatenate the raw text values to render. Doing so may change the
|
|
overall semantics of the message. If the client or server is
|
|
decrypting a Pretty Good Privacy (PGP) or S/MIME encrypted part,
|
|
concatenating with other parts may leak the decrypted text to an
|
|
attacker, as described in [EFAIL].
|
|
|
|
9.4. Email Submission
|
|
|
|
SMTP submission servers [RFC6409] use a number of mechanisms to
|
|
mitigate damage caused by compromised user accounts and end-user
|
|
systems including rate limiting, anti-virus/anti-spam milters (mail
|
|
filters), and other technologies. The technologies work better when
|
|
they have more information about the client connection. If JMAP
|
|
email submission is implemented as a proxy to an SMTP submission
|
|
server, it is useful to communicate this information from the JMAP
|
|
proxy to the submission server. The de facto XCLIENT extension to
|
|
SMTP [XCLIENT] can be used to do this, but use of an authenticated
|
|
channel is recommended to limit use of that extension to explicitly
|
|
authorised proxies.
|
|
|
|
JMAP servers that proxy to an SMTP submission server SHOULD allow use
|
|
of the submissions port [RFC8314]. Implementation of a mechanism
|
|
similar to SMTP XCLIENT is strongly encouraged. While Simple
|
|
Authentication and Security Layer (SASL) PLAIN over TLS [RFC4616] is
|
|
presently the mandatory-to-implement mechanism for interoperability
|
|
with SMTP submission servers [RFC4954], a JMAP submission proxy
|
|
SHOULD implement and prefer a stronger mechanism for this use case
|
|
such as TLS client certificate authentication with SASL EXTERNAL
|
|
([RFC4422], Appendix A) or Salted Challenge Response Authentication
|
|
Mechanism (SCRAM) [RFC7677].
|
|
|
|
In the event the JMAP server directly relays mail to SMTP servers in
|
|
other administrative domains, implementation of the de facto [milter]
|
|
protocol is strongly encouraged to integrate with third-party
|
|
products that address security issues including anti-virus/anti-spam,
|
|
reputation protection, compliance archiving, and data loss
|
|
prevention. Proxying to a local SMTP submission server may be a
|
|
simpler way to provide such security services.
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 91]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
9.5. Partial Account Access
|
|
|
|
A user may only have permission to access a subset of the data that
|
|
exists in an account. To avoid leaking unauthorised information, in
|
|
such a situation, the server MUST treat any data the user does not
|
|
have permission to access the same as if it did not exist.
|
|
|
|
For example, suppose user A has an account with two Mailboxes, inbox
|
|
and sent, but only shares the inbox with user B. In this case, when
|
|
user B fetches Mailboxes for this account, the server MUST behave as
|
|
though the sent Mailbox did not exist. Similarly, when querying or
|
|
fetching Email objects, it MUST treat any messages that just belong
|
|
to the sent Mailbox as though they did not exist. Fetching Thread
|
|
objects MUST only return ids for Email objects the user has
|
|
permission to access; if none, the Thread again MUST be treated the
|
|
same as if it did not exist.
|
|
|
|
If the server forbids a single account from having two identical
|
|
messages, or two messages with the same Message-Id header field, a
|
|
user with write access can use the error returned by trying to
|
|
create/import such a message to detect whether it already exists in
|
|
an inaccessible portion of the account.
|
|
|
|
9.6. Permission to Send from an Address
|
|
|
|
In recent years, the email ecosystem has moved towards associating
|
|
trust with the From address in the message [RFC5322], particularly
|
|
with schemes such as Domain-based Message Authentication, Reporting,
|
|
and Conformance (DMARC) [RFC7489].
|
|
|
|
The set of Identity objects (see Section 6) in an account lets the
|
|
client know which email addresses the user has permission to send
|
|
from. Each email submission is associated with an Identity, and
|
|
servers SHOULD reject submissions where the From header field of the
|
|
message does not correspond to the associated Identity.
|
|
|
|
The server MAY allow an exception to send an exact copy of an
|
|
existing message received into the mail store to another address
|
|
(otherwise known as "redirecting" or "bouncing"), although it is
|
|
RECOMMENDED the server limit this to destinations the user has
|
|
verified they also control.
|
|
|
|
If the user attempts to create a new Identity object, the server MUST
|
|
reject it with the appropriate error if the user does not have
|
|
permission to use that email address to send from.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 92]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
The SMTP MAIL FROM address [RFC5321] is often confused with the From
|
|
message header field [RFC5322]. The user generally only ever sees
|
|
the address in the message header field, and this is the primary one
|
|
to enforce. However, the server MUST also enforce appropriate
|
|
restrictions on the MAIL FROM address [RFC5321] to stop the user from
|
|
flooding a third-party address with bounces and non-delivery notices.
|
|
|
|
The JMAP submission model provides separate errors for impermissible
|
|
addresses in either context.
|
|
|
|
10. IANA Considerations
|
|
|
|
10.1. JMAP Capability Registration for "mail"
|
|
|
|
IANA has registered the "mail" JMAP Capability as follows:
|
|
|
|
Capability Name: urn:ietf:params:jmap:mail
|
|
|
|
Specification document: this document
|
|
|
|
Intended use: common
|
|
|
|
Change Controller: IETF
|
|
|
|
Security and privacy considerations: this document, Section 9
|
|
|
|
10.2. JMAP Capability Registration for "submission"
|
|
|
|
IANA has registered the "submission" JMAP Capability as follows:
|
|
|
|
Capability Name: urn:ietf:params:jmap:submission
|
|
|
|
Specification document: this document
|
|
|
|
Intended use: common
|
|
|
|
Change Controller: IETF
|
|
|
|
Security and privacy considerations: this document, Section 9
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 93]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.3. JMAP Capability Registration for "vacationresponse"
|
|
|
|
IANA has registered the "vacationresponse" JMAP Capability as
|
|
follows:
|
|
|
|
Capability Name: urn:ietf:params:jmap:vacationresponse
|
|
|
|
Specification document: this document
|
|
|
|
Intended use: common
|
|
|
|
Change Controller: IETF
|
|
|
|
Security and privacy considerations: this document, Section 9
|
|
|
|
10.4. IMAP and JMAP Keywords Registry
|
|
|
|
This document makes two changes to the IMAP keywords registry as
|
|
defined in [RFC5788].
|
|
|
|
First, the name of the registry is changed to the "IMAP and JMAP
|
|
Keywords" registry.
|
|
|
|
Second, a scope column is added to the template and registry
|
|
indicating whether a keyword applies to "IMAP-only", "JMAP-only",
|
|
"both", or "reserved". All keywords already in the IMAP keyword
|
|
registry have been marked with a scope of "both". The "reserved"
|
|
status can be used to prevent future registration of a name that
|
|
would be confusing if registered. Registration of keywords with
|
|
scope "reserved" omit most fields in the registration template (see
|
|
registration of "$recent" below for an example); such registrations
|
|
are intended to be infrequent.
|
|
|
|
IMAP clients MAY silently ignore any keywords marked "JMAP-only" or
|
|
"reserved" in the event they appear in protocol. JMAP clients MAY
|
|
silently ignore any keywords marked "IMAP-only" or "reserved" in the
|
|
event they appear in protocol.
|
|
|
|
New "JMAP-only" keywords are registered in the following subsections.
|
|
These keywords correspond to IMAP system keywords and are thus not
|
|
appropriate for use in IMAP. These keywords cannot be subsequently
|
|
registered for use in IMAP except via standards action.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 94]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.4.1. Registration of JMAP Keyword "$draft"
|
|
|
|
This registers the "JMAP-only" keyword "$draft" in the "IMAP and JMAP
|
|
Keywords" registry.
|
|
|
|
Keyword name: $draft
|
|
|
|
Scope: JMAP-only
|
|
|
|
Purpose (description): This is set when the user wants to treat the
|
|
message as a draft the user is composing. This is the JMAP
|
|
equivalent of the IMAP \Draft flag.
|
|
|
|
Private or Shared on a server: BOTH
|
|
|
|
Is it an advisory keyword or may it cause an automatic action:
|
|
Automatic. If the account has an IMAP mailbox marked with the
|
|
\Drafts special use attribute [RFC6154], setting this flag MAY cause
|
|
the message to appear in that mailbox automatically. Certain JMAP
|
|
computed values such as "unreadEmails" will change as a result of
|
|
changing this flag. In addition, mail clients will typically present
|
|
draft messages in a composer window rather than a viewer window.
|
|
|
|
When/by whom the keyword is set/cleared: This is typically set by a
|
|
JMAP client when referring to a draft message. One model for draft
|
|
Emails would result in clearing this flag in an "EmailSubmission/set"
|
|
operation with an "onSuccessUpdateEmail" argument. In a mail store
|
|
shared by JMAP and IMAP, this is also set and cleared as necessary so
|
|
it matches the IMAP \Draft flag.
|
|
|
|
Related keywords: None
|
|
|
|
Related IMAP/JMAP Capabilities: SPECIAL-USE [RFC6154]
|
|
|
|
Security Considerations: A server implementing this keyword as a
|
|
shared keyword may disclose that a user considers the message a draft
|
|
message. This information would be exposed to other users with read
|
|
permission for the Mailbox keywords.
|
|
|
|
Published specification: this document
|
|
|
|
Person & email address to contact for further information:
|
|
JMAP mailing list <jmap@ietf.org>
|
|
|
|
Intended usage: COMMON
|
|
|
|
Owner/Change controller: IESG
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 95]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.4.2. Registration of JMAP Keyword "$seen"
|
|
|
|
This registers the "JMAP-only" keyword "$seen" in the "IMAP and JMAP
|
|
Keywords" registry.
|
|
|
|
Keyword name: $seen
|
|
|
|
Scope: JMAP-only
|
|
|
|
Purpose (description): This is set when the user wants to treat the
|
|
message as read. This is the JMAP equivalent of the IMAP \Seen flag.
|
|
|
|
Private or Shared on a server: BOTH
|
|
|
|
Is it an advisory keyword or may it cause an automatic action:
|
|
Advisory. However, certain JMAP computed values such as
|
|
"unreadEmails" will change as a result of changing this flag.
|
|
|
|
When/by whom the keyword is set/cleared: This is set by a JMAP client
|
|
when it presents the message content to the user; clients often offer
|
|
an option to clear this flag. In a mail store shared by JMAP and
|
|
IMAP, this is also set and cleared as necessary so it matches the
|
|
IMAP \Seen flag.
|
|
|
|
Related keywords: None
|
|
|
|
Related IMAP/JMAP Capabilities: None
|
|
|
|
Security Considerations: A server implementing this keyword as a
|
|
shared keyword may disclose that a user considers the message to have
|
|
been read. This information would be exposed to other users with
|
|
read permission for the Mailbox keywords.
|
|
|
|
Published specification: this document
|
|
|
|
Person & email address to contact for further information:
|
|
JMAP mailing list <jmap@ietf.org>
|
|
|
|
Intended usage: COMMON
|
|
|
|
Owner/Change controller: IESG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 96]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.4.3. Registration of JMAP Keyword "$flagged"
|
|
|
|
This registers the "JMAP-only" keyword "$flagged" in the "IMAP and
|
|
JMAP Keywords" registry.
|
|
|
|
Keyword name: $flagged
|
|
|
|
Scope: JMAP-only
|
|
|
|
Purpose (description): This is set when the user wants to treat the
|
|
message as flagged for urgent/special attention. This is the JMAP
|
|
equivalent of the IMAP \Flagged flag.
|
|
|
|
Private or Shared on a server: BOTH
|
|
|
|
Is it an advisory keyword or may it cause an automatic action:
|
|
Automatic. If the account has an IMAP mailbox marked with the
|
|
\Flagged special use attribute [RFC6154], setting this flag MAY cause
|
|
the message to appear in that mailbox automatically.
|
|
|
|
When/by whom the keyword is set/cleared: JMAP clients typically allow
|
|
a user to set/clear this flag as desired. In a mail store shared by
|
|
JMAP and IMAP, this is also set and cleared as necessary so it
|
|
matches the IMAP \Flagged flag.
|
|
|
|
Related keywords: None
|
|
|
|
Related IMAP/JMAP Capabilities: SPECIAL-USE [RFC6154]
|
|
|
|
Security Considerations: A server implementing this keyword as a
|
|
shared keyword may disclose that a user considers the message as
|
|
flagged for urgent/special attention. This information would be
|
|
exposed to other users with read permission for the Mailbox keywords.
|
|
|
|
Published specification: this document
|
|
|
|
Person & email address to contact for further information:
|
|
JMAP mailing list <jmap@ietf.org>
|
|
|
|
Intended usage: COMMON
|
|
|
|
Owner/Change controller: IESG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 97]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.4.4. Registration of JMAP Keyword "$answered"
|
|
|
|
This registers the "JMAP-only" keyword "$answered" in the "IMAP and
|
|
JMAP Keywords" registry.
|
|
|
|
Keyword name: $answered
|
|
|
|
Scope: JMAP-only
|
|
|
|
Purpose (description): This is set when the message has been
|
|
answered.
|
|
|
|
Private or Shared on a server: BOTH
|
|
|
|
Is it an advisory keyword or may it cause an automatic action:
|
|
Advisory.
|
|
|
|
When/by whom the keyword is set/cleared: JMAP clients typically set
|
|
this when submitting a reply or answer to the message. It may be set
|
|
by the "EmailSubmission/set" operation with an "onSuccessUpdateEmail"
|
|
argument. In a mail store shared by JMAP and IMAP, this is also set
|
|
and cleared as necessary so it matches the IMAP \Answered flag.
|
|
|
|
Related keywords: None
|
|
|
|
Related IMAP/JMAP Capabilities: None
|
|
|
|
Security Considerations: A server implementing this keyword as a
|
|
shared keyword may disclose that a user has replied to a message.
|
|
This information would be exposed to other users with read permission
|
|
for the Mailbox keywords.
|
|
|
|
Published specification: this document
|
|
|
|
Person & email address to contact for further information:
|
|
JMAP mailing list <jmap@ietf.org>
|
|
|
|
Intended usage: COMMON
|
|
|
|
Owner/Change controller: IESG
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 98]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.4.5. Registration of "$recent" Keyword
|
|
|
|
This registers the keyword "$recent" in the "IMAP and JMAP Keywords"
|
|
registry.
|
|
|
|
Keyword name: $recent
|
|
|
|
Scope: reserved
|
|
|
|
Purpose (description): This keyword is not used to avoid confusion
|
|
with the IMAP \Recent system flag.
|
|
|
|
Published specification: this document
|
|
|
|
Person & email address to contact for further information:
|
|
JMAP mailing list <jmap@ietf.org>
|
|
|
|
Owner/Change controller: IESG
|
|
|
|
10.5. IMAP Mailbox Name Attributes Registry
|
|
|
|
10.5.1. Registration of "inbox" Role
|
|
|
|
This registers the "JMAP-only" "inbox" attribute in the "IMAP Mailbox
|
|
Name Attributes" registry, as established in [RFC8457].
|
|
|
|
Attribute Name: Inbox
|
|
|
|
Description: New mail is delivered here by default.
|
|
|
|
Reference: This document, Section 10.5.1
|
|
|
|
Usage Notes: JMAP only
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 99]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.6. JMAP Error Codes Registry
|
|
|
|
The following subsections register several new error codes in the
|
|
"JMAP Error Codes" registry, as defined in [RFC8620].
|
|
|
|
10.6.1. mailboxHasChild
|
|
|
|
JMAP Error Code: mailboxHasChild
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 2.5
|
|
|
|
Description: The Mailbox still has at least one child Mailbox. The
|
|
client MUST remove these before it can delete the parent Mailbox.
|
|
|
|
10.6.2. mailboxHasEmail
|
|
|
|
JMAP Error Code: mailboxHasEmail
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 2.5
|
|
|
|
Description: The Mailbox has at least one message assigned to it, and
|
|
the onDestroyRemoveEmails argument was false.
|
|
|
|
10.6.3. blobNotFound
|
|
|
|
JMAP Error Code: blobNotFound
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 4.6
|
|
|
|
Description: At least one blob id referenced in the object doesn't
|
|
exist.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 100]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.6.4. tooManyKeywords
|
|
|
|
JMAP Error Code: tooManyKeywords
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 4.6
|
|
|
|
Description: The change to the Email's keywords would exceed a
|
|
server-defined maximum.
|
|
|
|
10.6.5. tooManyMailboxes
|
|
|
|
JMAP Error Code: tooManyMailboxes
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 4.6
|
|
|
|
Description: The change to the set of Mailboxes that this Email is in
|
|
would exceed a server-defined maximum.
|
|
|
|
10.6.6. invalidEmail
|
|
|
|
JMAP Error Code: invalidEmail
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 7.5
|
|
|
|
Description: The Email to be sent is invalid in some way.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 101]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.6.7. tooManyRecipients
|
|
|
|
JMAP Error Code: tooManyRecipients
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 7.5
|
|
|
|
Description: The envelope [RFC5321] (supplied or generated) has more
|
|
recipients than the server allows.
|
|
|
|
10.6.8. noRecipients
|
|
|
|
JMAP Error Code: noRecipients
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 7.5
|
|
|
|
Description: The envelope [RFC5321] (supplied or generated) does not
|
|
have any rcptTo email addresses.
|
|
|
|
10.6.9. invalidRecipients
|
|
|
|
JMAP Error Code: invalidRecipients
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 7.5
|
|
|
|
Description: The rcptTo property of the envelope [RFC5321] (supplied
|
|
or generated) contains at least one rcptTo value that is not a valid
|
|
email address for sending to.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 102]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
10.6.10. forbiddenMailFrom
|
|
|
|
JMAP Error Code: forbiddenMailFrom
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 7.5
|
|
|
|
Description: The server does not permit the user to send a message
|
|
with this envelope From address [RFC5321].
|
|
|
|
10.6.11. forbiddenFrom
|
|
|
|
JMAP Error Code: forbiddenFrom
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Sections 6.3 and 7.5
|
|
|
|
Description: The server does not permit the user to send a message
|
|
with the From header field [RFC5322] of the message to be sent.
|
|
|
|
10.6.12. forbiddenToSend
|
|
|
|
JMAP Error Code: forbiddenToSend
|
|
|
|
Intended use: common
|
|
|
|
Change controller: IETF
|
|
|
|
Reference: This document, Section 7.5
|
|
|
|
Description: The user does not have permission to send at all right
|
|
now.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 103]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
11. References
|
|
|
|
11.1. Normative References
|
|
|
|
[HTML] Faulkner, S., Eicholz, A., Leithead, T., Danilo, A., and
|
|
S. Moon, "HTML 5.2", World Wide Web Consortium
|
|
Recommendation REC-html52-20171214, December 2017,
|
|
<https://www.w3.org/TR/html52/>.
|
|
|
|
[RFC1870] Klensin, J., Freed, N., and K. Moore, "SMTP Service
|
|
Extension for Message Size Declaration", STD 10, RFC 1870,
|
|
DOI 10.17487/RFC1870, November 1995,
|
|
<https://www.rfc-editor.org/info/rfc1870>.
|
|
|
|
[RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
|
|
Extensions (MIME) Part One: Format of Internet Message
|
|
Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996,
|
|
<https://www.rfc-editor.org/info/rfc2045>.
|
|
|
|
[RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions)
|
|
Part Three: Message Header Extensions for Non-ASCII Text",
|
|
RFC 2047, DOI 10.17487/RFC2047, November 1996,
|
|
<https://www.rfc-editor.org/info/rfc2047>.
|
|
|
|
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
|
Requirement Levels", BCP 14, RFC 2119,
|
|
DOI 10.17487/RFC2119, March 1997,
|
|
<https://www.rfc-editor.org/info/rfc2119>.
|
|
|
|
[RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and Encoded
|
|
Word Extensions: Character Sets, Languages, and
|
|
Continuations", RFC 2231, DOI 10.17487/RFC2231, November
|
|
1997, <https://www.rfc-editor.org/info/rfc2231>.
|
|
|
|
[RFC2369] Neufeld, G. and J. Baer, "The Use of URLs as Meta-Syntax
|
|
for Core Mail List Commands and their Transport through
|
|
Message Header Fields", RFC 2369, DOI 10.17487/RFC2369,
|
|
July 1998, <https://www.rfc-editor.org/info/rfc2369>.
|
|
|
|
[RFC2392] Levinson, E., "Content-ID and Message-ID Uniform Resource
|
|
Locators", RFC 2392, DOI 10.17487/RFC2392, August 1998,
|
|
<https://www.rfc-editor.org/info/rfc2392>.
|
|
|
|
[RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME
|
|
Encapsulation of Aggregate Documents, such as HTML
|
|
(MHTML)", RFC 2557, DOI 10.17487/RFC2557, March 1999,
|
|
<https://www.rfc-editor.org/info/rfc2557>.
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 104]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
[RFC2852] Newman, D., "Deliver By SMTP Service Extension", RFC 2852,
|
|
DOI 10.17487/RFC2852, June 2000,
|
|
<https://www.rfc-editor.org/info/rfc2852>.
|
|
|
|
[RFC3282] Alvestrand, H., "Content Language Headers", RFC 3282,
|
|
DOI 10.17487/RFC3282, May 2002,
|
|
<https://www.rfc-editor.org/info/rfc3282>.
|
|
|
|
[RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service
|
|
Extension for Delivery Status Notifications (DSNs)",
|
|
RFC 3461, DOI 10.17487/RFC3461, January 2003,
|
|
<https://www.rfc-editor.org/info/rfc3461>.
|
|
|
|
[RFC3463] Vaudreuil, G., "Enhanced Mail System Status Codes",
|
|
RFC 3463, DOI 10.17487/RFC3463, January 2003,
|
|
<https://www.rfc-editor.org/info/rfc3463>.
|
|
|
|
[RFC3464] Moore, K. and G. Vaudreuil, "An Extensible Message Format
|
|
for Delivery Status Notifications", RFC 3464,
|
|
DOI 10.17487/RFC3464, January 2003,
|
|
<https://www.rfc-editor.org/info/rfc3464>.
|
|
|
|
[RFC3834] Moore, K., "Recommendations for Automatic Responses to
|
|
Electronic Mail", RFC 3834, DOI 10.17487/RFC3834, August
|
|
2004, <https://www.rfc-editor.org/info/rfc3834>.
|
|
|
|
[RFC4314] Melnikov, A., "IMAP4 Access Control List (ACL) Extension",
|
|
RFC 4314, DOI 10.17487/RFC4314, December 2005,
|
|
<https://www.rfc-editor.org/info/rfc4314>.
|
|
|
|
[RFC4422] Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
|
|
Authentication and Security Layer (SASL)", RFC 4422,
|
|
DOI 10.17487/RFC4422, June 2006,
|
|
<https://www.rfc-editor.org/info/rfc4422>.
|
|
|
|
[RFC4616] Zeilenga, K., Ed., "The PLAIN Simple Authentication and
|
|
Security Layer (SASL) Mechanism", RFC 4616,
|
|
DOI 10.17487/RFC4616, August 2006,
|
|
<https://www.rfc-editor.org/info/rfc4616>.
|
|
|
|
[RFC4865] White, G. and G. Vaudreuil, "SMTP Submission Service
|
|
Extension for Future Message Release", RFC 4865,
|
|
DOI 10.17487/RFC4865, May 2007,
|
|
<https://www.rfc-editor.org/info/rfc4865>.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 105]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
[RFC4954] Siemborski, R., Ed. and A. Melnikov, Ed., "SMTP Service
|
|
Extension for Authentication", RFC 4954,
|
|
DOI 10.17487/RFC4954, July 2007,
|
|
<https://www.rfc-editor.org/info/rfc4954>.
|
|
|
|
[RFC5198] Klensin, J. and M. Padlipsky, "Unicode Format for Network
|
|
Interchange", RFC 5198, DOI 10.17487/RFC5198, March 2008,
|
|
<https://www.rfc-editor.org/info/rfc5198>.
|
|
|
|
[RFC5248] Hansen, T. and J. Klensin, "A Registry for SMTP Enhanced
|
|
Mail System Status Codes", BCP 138, RFC 5248,
|
|
DOI 10.17487/RFC5248, June 2008,
|
|
<https://www.rfc-editor.org/info/rfc5248>.
|
|
|
|
[RFC5256] Crispin, M. and K. Murchison, "Internet Message Access
|
|
Protocol - SORT and THREAD Extensions", RFC 5256,
|
|
DOI 10.17487/RFC5256, June 2008,
|
|
<https://www.rfc-editor.org/info/rfc5256>.
|
|
|
|
[RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321,
|
|
DOI 10.17487/RFC5321, October 2008,
|
|
<https://www.rfc-editor.org/info/rfc5321>.
|
|
|
|
[RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
|
|
DOI 10.17487/RFC5322, October 2008,
|
|
<https://www.rfc-editor.org/info/rfc5322>.
|
|
|
|
[RFC5788] Melnikov, A. and D. Cridland, "IMAP4 Keyword Registry",
|
|
RFC 5788, DOI 10.17487/RFC5788, March 2010,
|
|
<https://www.rfc-editor.org/info/rfc5788>.
|
|
|
|
[RFC6154] Leiba, B. and J. Nicolson, "IMAP LIST Extension for
|
|
Special-Use Mailboxes", RFC 6154, DOI 10.17487/RFC6154,
|
|
March 2011, <https://www.rfc-editor.org/info/rfc6154>.
|
|
|
|
[RFC6409] Gellens, R. and J. Klensin, "Message Submission for Mail",
|
|
STD 72, RFC 6409, DOI 10.17487/RFC6409, November 2011,
|
|
<https://www.rfc-editor.org/info/rfc6409>.
|
|
|
|
[RFC6532] Yang, A., Steele, S., and N. Freed, "Internationalized
|
|
Email Headers", RFC 6532, DOI 10.17487/RFC6532, February
|
|
2012, <https://www.rfc-editor.org/info/rfc6532>.
|
|
|
|
[RFC6533] Hansen, T., Ed., Newman, C., and A. Melnikov,
|
|
"Internationalized Delivery Status and Disposition
|
|
Notifications", RFC 6533, DOI 10.17487/RFC6533, February
|
|
2012, <https://www.rfc-editor.org/info/rfc6533>.
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 106]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
[RFC6710] Melnikov, A. and K. Carlberg, "Simple Mail Transfer
|
|
Protocol Extension for Message Transfer Priorities",
|
|
RFC 6710, DOI 10.17487/RFC6710, August 2012,
|
|
<https://www.rfc-editor.org/info/rfc6710>.
|
|
|
|
[RFC7677] Hansen, T., "SCRAM-SHA-256 and SCRAM-SHA-256-PLUS Simple
|
|
Authentication and Security Layer (SASL) Mechanisms",
|
|
RFC 7677, DOI 10.17487/RFC7677, November 2015,
|
|
<https://www.rfc-editor.org/info/rfc7677>.
|
|
|
|
[RFC8098] Hansen, T., Ed. and A. Melnikov, Ed., "Message Disposition
|
|
Notification", STD 85, RFC 8098, DOI 10.17487/RFC8098,
|
|
February 2017, <https://www.rfc-editor.org/info/rfc8098>.
|
|
|
|
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
|
|
2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
|
|
May 2017, <https://www.rfc-editor.org/info/rfc8174>.
|
|
|
|
[RFC8314] Moore, K. and C. Newman, "Cleartext Considered Obsolete:
|
|
Use of Transport Layer Security (TLS) for Email Submission
|
|
and Access", RFC 8314, DOI 10.17487/RFC8314, January 2018,
|
|
<https://www.rfc-editor.org/info/rfc8314>.
|
|
|
|
[RFC8457] Leiba, B., Ed., "IMAP "$Important" Keyword and
|
|
"\Important" Special-Use Attribute", RFC 8457,
|
|
DOI 10.17487/RFC8457, September 2018,
|
|
<https://www.rfc-editor.org/info/rfc8457>.
|
|
|
|
[RFC8474] Gondwana, B., Ed., "IMAP Extension for Object
|
|
Identifiers", RFC 8474, DOI 10.17487/RFC8474, September
|
|
2018, <https://www.rfc-editor.org/info/rfc8474>.
|
|
|
|
[RFC8620] Jenkins, N. and C. Newman, "The JSON Meta Application
|
|
Protocol", RFC 8620, DOI 10.17487/RFC8620, June 2019,
|
|
<https://www.rfc-editor.org/info/rfc8620>.
|
|
|
|
11.2. Informative References
|
|
|
|
[EFAIL] Poddebniak, D., Dresen, C., Mueller, J., Ising, F.,
|
|
Schinzel, S., Friedberger, S., Somorovsky, J., and J.
|
|
Schwenk, "Efail: Breaking S/MIME and OpenPGP Email
|
|
Encryption using Exfiltration Channels", August 2018,
|
|
<https://www.usenix.org/system/files/conference/
|
|
usenixsecurity18/sec18-poddebniak.pdf>.
|
|
|
|
[milter] Postfix, "Postfix before-queue Milter support", 2019,
|
|
<http://www.postfix.org/MILTER_README.html>.
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 107]
|
|
|
|
RFC 8621 JMAP Mail August 2019
|
|
|
|
|
|
[RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
|
|
4rev1", RFC 3501, DOI 10.17487/RFC3501, March 2003,
|
|
<https://www.rfc-editor.org/info/rfc3501>.
|
|
|
|
[RFC7489] Kucherawy, M., Ed. and E. Zwicky, Ed., "Domain-based
|
|
Message Authentication, Reporting, and Conformance
|
|
(DMARC)", RFC 7489, DOI 10.17487/RFC7489, March 2015,
|
|
<https://www.rfc-editor.org/info/rfc7489>.
|
|
|
|
[XCLIENT] Postfix, "Postfix XCLIENT Howto", 2019,
|
|
<http://www.postfix.org/XCLIENT_README.html>.
|
|
|
|
Authors' Addresses
|
|
|
|
Neil Jenkins
|
|
Fastmail
|
|
PO Box 234, Collins St. West
|
|
Melbourne, VIC 8007
|
|
Australia
|
|
|
|
Email: neilj@fastmailteam.com
|
|
URI: https://www.fastmail.com
|
|
|
|
|
|
Chris Newman
|
|
Oracle
|
|
440 E. Huntington Dr., Suite 400
|
|
Arcadia, CA 91006
|
|
United States of America
|
|
|
|
Email: chris.newman@oracle.com
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Jenkins & Newman Standards Track [Page 108]
|
|
|