draft-ietf-jmap-mail-14.txt   draft-ietf-jmap-mail-15.txt 
JMAP N. Jenkins JMAP N. Jenkins
Internet-Draft FastMail Internet-Draft FastMail
Updates: 5788 (if approved) C. Newman Updates: 5788 (if approved) C. Newman
Intended status: Standards Track Oracle Intended status: Standards Track Oracle
Expires: July 21, 2019 January 17, 2019 Expires: September 2, 2019 March 1, 2019
JMAP for Mail JMAP for Mail
draft-ietf-jmap-mail-14 draft-ietf-jmap-mail-15
Abstract Abstract
This document specifies a data model for synchronising email data This document specifies a data model for synchronising email data
with a server using JMAP. Clients can use this to efficiently with a server using JMAP. Clients can use this to efficiently
search, access, organise and send messages, and get pushed search, access, organise and send messages, and get pushed
notifications for fast resynchronisation when new messages are notifications for fast resynchronisation when new messages are
delivered or a change is made in another client. delivered or a change is made in another client.
Status of This Memo Status of This Memo
skipping to change at page 1, line 35 skipping to change at page 1, line 35
Internet-Drafts are working documents of the Internet Engineering Internet-Drafts are working documents of the Internet Engineering
Task Force (IETF). Note that other groups may also distribute Task Force (IETF). Note that other groups may also distribute
working documents as Internet-Drafts. The list of current Internet- working documents as Internet-Drafts. The list of current Internet-
Drafts is at https://datatracker.ietf.org/drafts/current/. Drafts is at https://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress." material or to cite them other than as "work in progress."
This Internet-Draft will expire on July 21, 2019. This Internet-Draft will expire on September 2, 2019.
Copyright Notice Copyright Notice
Copyright (c) 2019 IETF Trust and the persons identified as the Copyright (c) 2019 IETF Trust and the persons identified as the
document authors. All rights reserved. document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info) in effect on the date of (https://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License. described in the Simplified BSD License.
Table of Contents Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1. Notational conventions . . . . . . . . . . . . . . . . . 4 1.1. Notational conventions . . . . . . . . . . . . . . . . . 4
1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5
1.3. Additions to the capabilities object . . . . . . . . . . 4 1.3. Additions to the capabilities object . . . . . . . . . . 5
1.3.1. urn:ietf:params:jmap:mail . . . . . . . . . . . . . . 4 1.3.1. urn:ietf:params:jmap:mail . . . . . . . . . . . . . . 5
1.3.2. urn:ietf:params:jmap:submission . . . . . . . . . . . 5 1.3.2. urn:ietf:params:jmap:submission . . . . . . . . . . . 6
1.3.3. urn:ietf:params:jmap:vacationresponse . . . . . . . . 6 1.3.3. urn:ietf:params:jmap:vacationresponse . . . . . . . . 7
1.4. Data type support in different accounts . . . . . . . . . 6 1.4. Data type support in different accounts . . . . . . . . . 7
1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 7 1.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 8
1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 11 2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 11
2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 11 2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 12
2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 11 2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 12
2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 12 2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 13
2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 12 2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 13
2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 14
3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 18 3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 18
3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 18 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 18
3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 18 3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 18
4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.1. Properties of the Email object . . . . . . . . . . . . . 19 4.1. Properties of the Email object . . . . . . . . . . . . . 19
4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 20 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 20
4.1.2. Header fields parsed forms . . . . . . . . . . . . . 22 4.1.2. Header fields parsed forms . . . . . . . . . . . . . 22
4.1.3. Header fields properties . . . . . . . . . . . . . . 27 4.1.3. Header fields properties . . . . . . . . . . . . . . 27
4.1.4. Body parts . . . . . . . . . . . . . . . . . . . . . 29 4.1.4. Body parts . . . . . . . . . . . . . . . . . . . . . 29
skipping to change at page 3, line 24 skipping to change at page 3, line 24
7.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 68 7.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 68
7.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 68 7.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 68
7.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 70 7.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 70
8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 73 8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 73
8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 74 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 74
8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 74 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 74
9. Security considerations . . . . . . . . . . . . . . . . . . . 74 9. Security considerations . . . . . . . . . . . . . . . . . . . 74
9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 74 9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 74
9.2. HTML email display . . . . . . . . . . . . . . . . . . . 74 9.2. HTML email display . . . . . . . . . . . . . . . . . . . 74
9.3. Email submission . . . . . . . . . . . . . . . . . . . . 77 9.3. Email submission . . . . . . . . . . . . . . . . . . . . 77
10. IANA considerations . . . . . . . . . . . . . . . . . . . . . 77 9.4. Partial account access . . . . . . . . . . . . . . . . . 77
10.1. JMAP capability registration for "mail" . . . . . . . . 77 10. IANA considerations . . . . . . . . . . . . . . . . . . . . . 78
10.1. JMAP capability registration for "mail" . . . . . . . . 78
10.2. JMAP capability registration for "submission" . . . . . 78 10.2. JMAP capability registration for "submission" . . . . . 78
10.3. JMAP capability registration for "vacationresponse" . . 78 10.3. JMAP capability registration for "vacationresponse" . . 78
10.4. IMAP and JMAP keywords registry . . . . . . . . . . . . 78 10.4. IMAP and JMAP keywords registry . . . . . . . . . . . . 79
10.4.1. Registration of JMAP keyword '$draft' . . . . . . . 79 10.4.1. Registration of JMAP keyword '$draft' . . . . . . . 79
10.4.2. Registration of JMAP keyword '$seen' . . . . . . . . 80 10.4.2. Registration of JMAP keyword '$seen' . . . . . . . . 80
10.4.3. Registration of JMAP keyword '$flagged' . . . . . . 81 10.4.3. Registration of JMAP keyword '$flagged' . . . . . . 81
10.4.4. Registration of JMAP keyword '$answered' . . . . . . 81 10.4.4. Registration of JMAP keyword '$answered' . . . . . . 82
10.4.5. Registration of '$recent' keyword . . . . . . . . . 82 10.4.5. Registration of '$recent' keyword . . . . . . . . . 83
10.5. Registration of "inbox" role in . . . . . . . . . . . . 83 10.5. Registration of "inbox" role in . . . . . . . . . . . . 83
10.6. JMAP Error Codes registry . . . . . . . . . . . . . . . 83 10.6. JMAP Error Codes registry . . . . . . . . . . . . . . . 83
10.6.1. mailboxHasChild . . . . . . . . . . . . . . . . . . 83 10.6.1. mailboxHasChild . . . . . . . . . . . . . . . . . . 84
10.6.2. mailboxHasEmail . . . . . . . . . . . . . . . . . . 83 10.6.2. mailboxHasEmail . . . . . . . . . . . . . . . . . . 84
10.6.3. blobNotFound . . . . . . . . . . . . . . . . . . . . 84 10.6.3. blobNotFound . . . . . . . . . . . . . . . . . . . . 84
10.6.4. tooManyKeywords . . . . . . . . . . . . . . . . . . 84 10.6.4. tooManyKeywords . . . . . . . . . . . . . . . . . . 84
10.6.5. tooManyMailboxes . . . . . . . . . . . . . . . . . . 84 10.6.5. tooManyMailboxes . . . . . . . . . . . . . . . . . . 84
10.6.6. invalidEmail . . . . . . . . . . . . . . . . . . . . 84 10.6.6. invalidEmail . . . . . . . . . . . . . . . . . . . . 85
10.6.7. tooManyRecipients . . . . . . . . . . . . . . . . . 84 10.6.7. tooManyRecipients . . . . . . . . . . . . . . . . . 85
10.6.8. noRecipients . . . . . . . . . . . . . . . . . . . . 85 10.6.8. noRecipients . . . . . . . . . . . . . . . . . . . . 85
10.6.9. invalidRecipients . . . . . . . . . . . . . . . . . 85 10.6.9. invalidRecipients . . . . . . . . . . . . . . . . . 85
10.6.10. forbiddenMailFrom . . . . . . . . . . . . . . . . . 85 10.6.10. forbiddenMailFrom . . . . . . . . . . . . . . . . . 85
10.6.11. forbiddenFrom . . . . . . . . . . . . . . . . . . . 85 10.6.11. forbiddenFrom . . . . . . . . . . . . . . . . . . . 86
10.6.12. forbiddenToSend . . . . . . . . . . . . . . . . . . 85 10.6.12. forbiddenToSend . . . . . . . . . . . . . . . . . . 86
11. References . . . . . . . . . . . . . . . . . . . . . . . . . 86 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 86
11.1. Normative References . . . . . . . . . . . . . . . . . . 86 11.1. Normative References . . . . . . . . . . . . . . . . . . 86
11.2. Informative References . . . . . . . . . . . . . . . . . 89 11.2. Informative References . . . . . . . . . . . . . . . . . 90
11.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 89 11.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 90
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 90 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 90
1. Introduction 1. Introduction
JMAP ([I-D.ietf-jmap-core]) is a generic protocol for synchronising JMAP ([I-D.ietf-jmap-core] - JSON Meta Application Protocol) is a
data, such as mail, calendars or contacts, between a client and a generic protocol for synchronising data, such as mail, calendars or
server. It is optimised for mobile and web environments, and aims to contacts, between a client and a server. It is optimised for mobile
provide a consistent interface to different data types. and web environments, and aims to provide a consistent interface to
different data types.
This specification defines a data model for mail over JMAP. 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, emails 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 read-
only with them.
1.1. Notational conventions 1.1. Notational conventions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
document are to be interpreted as described in [RFC2119]. "OPTIONAL" in this document are to be interpreted as described in BCP
14 [RFC2119] [RFC8174] when, and only when, they appear in all
capitals, as shown here.
Type signatures, examples and property descriptions in this document Type signatures, examples and property descriptions in this document
follow the conventions established in section 1.1 of follow the conventions established in section 1.1 of
[I-D.ietf-jmap-core]. Data types defined in the core specification [I-D.ietf-jmap-core]. Data types defined in the core specification
are also used in this document. are also used in this document.
Servers MUST support all properties specified for the new data types
defined in this document.
1.2. Terminology 1.2. Terminology
The same terminology is used in this document as in the core JMAP The same terminology is used in this document as in the core JMAP
specification. specification.
1.3. Additions to the capabilities object 1.3. Additions to the capabilities object
The capabilities object is returned as part of the standard JMAP The capabilities object is returned as part of the JMAP Session
Session object; see [I-D.ietf-jmap-core], section 2. object; see [I-D.ietf-jmap-core], section 2.
This document defines three additional capability URIs. This document defines three additional capability URIs.
1.3.1. urn:ietf:params:jmap:mail 1.3.1. urn:ietf:params:jmap:mail
This represents support for the Mailbox, Thread, Email, and This represents support for the Mailbox, Thread, Email, and
SearchSnippet data types and associated API methods. The value of SearchSnippet data types and associated API methods. The value of
this property is an object which MUST contain the following this property is an object which MUST contain the following
information on server capabilities: information on server capabilities:
o *maxMailboxesPerEmail*: "PositiveInt|null" The maximum number of o *maxMailboxesPerEmail*: "UnsignedInt|null" The maximum number of
mailboxes that can be can assigned to a single email. This MUST mailboxes that can be can assigned to a single email. This MUST
be an integer >= 1, or "null" for no limit (or rather, the limit be an integer >= 1, or "null" for no limit (or rather, the limit
is always the number of mailboxes in the account). is always the number of mailboxes in the account).
o *maxMailboxDepth*: "PositiveInt|null" The maximum depth of the o *maxMailboxDepth*: "UnsignedInt|null" The maximum depth of the
mailbox hierarchy (i.e. one more than the maximum number of mailbox hierarchy (i.e. one more than the maximum number of
ancestors a mailbox may have), or "null" for no limit. ancestors a mailbox may have), or "null" for no limit.
o *maxSizeMailboxName*: "PositiveInt" The maximum length, in (UTF-8) o *maxSizeMailboxName*: "UnsignedInt" The maximum length, in (UTF-8)
octets, allowed for the name of a mailbox. This MUST be at least octets, allowed for the name of a mailbox. This MUST be at least
100, although it is recommended servers allow more. 100, although it is recommended servers allow more.
o *maxSizeAttachmentsPerEmail*: "PositiveInt" The maximum total size o *maxSizeAttachmentsPerEmail*: "UnsignedInt" The maximum total size
of attachments, in octets, allowed for a single email. A server of attachments, in octets, allowed for a single email. A server
MAY still reject import or creation of emails with a lower MAY still reject import or creation of emails with a lower
attachment size total (for example, if the body includes several attachment size total (for example, if the body includes several
megabytes of text, causing the size of the encoded MIME structure megabytes of text, causing the size of the encoded MIME structure
to be over some server-defined limit). Note, this limit is for to be over some server-defined limit). Note, this limit is for
the sum of unencoded attachment sizes. Users are generally not the sum of unencoded attachment sizes. Users are generally not
knowledgeable about encoding overhead etc., nor should they need knowledgeable about encoding overhead etc., nor should they need
to be, so marketing and help materials normally tell them the "max to be, so marketing and help materials normally tell them the "max
size attachments". This is the unencoded size they see on their size attachments". This is the unencoded size they see on their
hard drive, and so this capability matches that and allows the hard drive, and so this capability matches that and allows the
skipping to change at page 5, line 46 skipping to change at page 6, line 27
properties specified in a vendor extension). Clients MUST ignore properties specified in a vendor extension). Clients MUST ignore
any unknown properties in the list. any unknown properties in the list.
1.3.2. urn:ietf:params:jmap:submission 1.3.2. urn:ietf:params:jmap:submission
This represents support for the Identity and MessageSubmission data This represents support for the Identity and MessageSubmission data
types and associated API methods. The value of this property is an types and associated API methods. The value of this property is an
object which MUST contain the following information on server object which MUST contain the following information on server
capabilities: capabilities:
o *maxDelayedSend*: "PositiveInt" The number in seconds of the o *maxDelayedSend*: "UnsignedInt" The number in seconds of the
maximum delay the server supports in sending (see the maximum delay the server supports in sending (see the
EmailSubmission object description). This is "0" if the server EmailSubmission object description). This is "0" if the server
does not support delayed send. does not support delayed send.
o *submissionExtensions*: "String[String[]]" A JMAP implementation o *submissionExtensions*: "String[String[]]" A JMAP implementation
that talks to a Submission [RFC6409] server SHOULD have a that talks to a Submission [RFC6409] server SHOULD have a
configuration setting that allows an administrator to expose a new configuration setting that allows an administrator to expose a new
submission EHLO capability in this field. This allows a JMAP submission EHLO capability in this field. This allows a JMAP
server to gain access to a new submission extension without code server to gain access to a new submission extension without code
changes. By default, the JMAP server should hide EHLO changes. By default, the JMAP server should hide EHLO
skipping to change at page 7, line 7 skipping to change at page 7, line 34
between accounts the user has access to. For example, in the user's 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 personal account they may have access to all three sets of data, but
in a shared account they may only have data for in a shared account they may only have data for
"urn:ietf:params:jmap:mail". This means they can access "urn:ietf:params:jmap:mail". This means they can access
Mailbox/Thread/Email data in the shared account but are not allowed 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/ to send as that account (and so do not have access to Identity/
MessageSubmission objects) or view/set its vacation response. MessageSubmission objects) or view/set its vacation response.
1.5. Push 1.5. Push
Servers MUST support the standard JMAP push mechanisms to receive Servers MUST support the JMAP push mechanisms, as specified in
notifications when the state changes for any of the types defined in [I-D.ietf-jmap-core] section 7, to receive notifications when the
this specification. state changes for any of the types defined in this specification.
In addition, servers MUST support pushing state changes for a type In addition, servers MUST support pushing state changes for a type
called "EmailDelivery". There are no methods to act on this type; it 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 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 SHOULD MUST change whenever a new Email is added to the store, but SHOULD
NOT change upon any other change to the Email objects, for example if NOT change upon any other change to the Email objects, for example if
one is marked as read or deleted. one is marked as read or deleted.
Clients in battery constrained environments may wish to delay Clients in battery constrained environments may wish to delay
fetching changes initiated by the user, but fetch new messages fetching changes initiated by the user, but fetch new messages
skipping to change at page 8, line 10 skipping to change at page 8, line 40
For compatibility with IMAP, an email MUST belong to one or more For compatibility with IMAP, an email MUST belong to one or more
mailboxes. The email id does not change if the email changes mailboxes. The email id does not change if the email changes
mailboxes. mailboxes.
A *Mailbox* object has the following properties: A *Mailbox* object has the following properties:
o *id*: "Id" (immutable; server-set) The id of the mailbox. o *id*: "Id" (immutable; server-set) The id of the mailbox.
o *name*: "String" User-visible name for the mailbox, e.g. "Inbox". o *name*: "String" User-visible name for the mailbox, e.g. "Inbox".
This may be any Net-Unicode string ([RFC5198]) of at least 1 This MUST be a Net-Unicode string ([RFC5198]) of at least 1
character in length, subject to the maximum size given in the character in length, subject to the maximum size given in the
capability object. There MUST NOT be two sibling mailboxes with capability object. There MUST NOT be two sibling mailboxes with
both the same parent and the same name. Servers MAY reject names both the same parent and the same name. Servers MAY reject names
that violate server policy (e.g., names containing slash (/) or that violate server policy (e.g., names containing slash (/) or
control characters). control characters).
o *parentId*: "Id|null" (default: null) The mailbox id for the o *parentId*: "Id|null" (default: null) The mailbox id for the
parent of this mailbox, or "null" if this mailbox is at the top parent of this mailbox, or "null" if this mailbox is at the top
level. Mailboxes form acyclic graphs (forests) directed by the level. Mailboxes form acyclic graphs (forests) directed by the
child-to-parent relationship. There MUST NOT be a loop. child-to-parent relationship. There MUST NOT be a loop.
o *role*: "String|null" (default: null) Identifies mailboxes that o *role*: "String|null" (default: null) Identifies mailboxes that
have a particular common purpose (e.g. the "inbox"), regardless of have a particular common purpose (e.g. the "inbox"), regardless of
the _name_ (which may be localised). This value is shared with the _name_ (which may be localised). This value is shared with
IMAP (exposed in IMAP via the [RFC6154] SPECIAL-USE extension). IMAP (exposed in IMAP via the [RFC6154] SPECIAL-USE extension).
However, unlike in IMAP, a mailbox may only have a single role, However, unlike in IMAP, a mailbox MUST only have a single role,
and no two mailboxes in the same account may have the same 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, it is implementation dependent how to modify the IMAP
attributes to ensure compliance when exposing the data over JMAP.
The value MUST be one of the mailbox attribute names listed in the The value MUST be one of the mailbox attribute names listed in the
IANA IMAP Mailbox Name Attributes Registry [1], as established in IANA IMAP Mailbox Name Attributes Registry [1], as established in
[RFC8457], converted to lower-case. New roles may be established [RFC8457], converted to lower-case. New roles may be established
here in the future. An account is not required to have mailboxes here in the future. An account is not required to have mailboxes
with any particular roles. with any particular roles.
o *sortOrder*: "PositiveInt" (default: 0) Defines the sort order of o *sortOrder*: "UnsignedInt" (default: 0) Defines the sort order of
mailboxes when presented in the client's UI, so it is consistent mailboxes when presented in the client's UI, so it is consistent
between devices. The number MUST be an integer in the range 0 <= between devices. The number MUST be an integer in the range 0 <=
sortOrder < 2^31. A mailbox with a lower order should be sortOrder < 2^31. A mailbox with a lower order should be
displayed before a mailbox with a higher order (that has the same displayed before a mailbox with a higher order (that has the same
parent) in any mailbox listing in the client's UI. Mailboxes with parent) in any mailbox listing in the client's UI. Mailboxes with
equal order SHOULD be sorted in alphabetical order by name. The equal order SHOULD be sorted in alphabetical order by name. The
sorting SHOULD take into account locale-specific character order sorting SHOULD take into account locale-specific character order
convention. convention.
o *totalEmails*: "PositiveInt" (server-set) The number of emails in o *totalEmails*: "UnsignedInt" (server-set) The number of emails in
this mailbox. this mailbox.
o *unreadEmails*: "PositiveInt" (server-set) The number of emails in o *unreadEmails*: "UnsignedInt" (server-set) The number of emails in
this mailbox that have neither the "$seen" keyword nor the this mailbox that have neither the "$seen" keyword nor the
"$draft" keyword. "$draft" keyword.
o *totalThreads*: "PositiveInt" (server-set) The number of threads o *totalThreads*: "UnsignedInt" (server-set) The number of threads
where at least one email in the thread is in this mailbox. where at least one email in the thread is in this mailbox.
o *unreadThreads*: "PositiveInt" (server-set) An indication of the o *unreadThreads*: "UnsignedInt" (server-set) An indication of the
number of "unread" threads in the mailbox. This may be presented number of "unread" threads in the mailbox. For compatibility with
by the client as a badge or marker associated with the mailbox. existing implementations, the way "unread threads" is determined
For compatibility with existing implementations, the way "unread is not mandated in this document. The simplest solution to
threads" is determined is not mandated in this document. The implement is simply the number of threads where at least one email
simplest solution to implement is simply the number of threads in the thread is both in this mailbox and has neither the "$seen"
where at least one email in the thread is both in this mailbox and nor "$draft" keywords. However, a quality implementation will
has neither the "$seen" nor "$draft" keywords. However, a quality return the number of unread items the user would see if they
implementation will return the number of unread items the user opened that mailbox. A thread is shown as unread if it contains
would see if they opened that mailbox. A thread is shown as any unread messages that will be displayed when the thread is
unread if it contains any unread messages that will be displayed opened. Therefore "unreadThreads" should be the number of threads
when the thread is opened. Therefore "unreadThreads" should be where at least one email in the thread has neither the "$seen" nor
the number of threads where at least one email in the thread has the "$draft" keyword AND at least one email in the thread is in
neither the "$seen" nor the "$draft" keyword AND at least one this mailbox. Note, the unread email does not need to be the one
email in the thread is in this mailbox. Note, the unread email in this mailbox. In addition, the Trash mailbox (that is a
does not need to be the one in this mailbox. In addition, the mailbox whose "role" is "trash") is treated specially:
Trash mailbox (that is a mailbox whose "role" is "trash") is
treated specially:
1. Emails that are *only* in the Trash (and no other mailbox) are 1. Emails that are *only* in the Trash (and no other mailbox) are
ignored when calculating the "unreadThreads" count of other ignored when calculating the "unreadThreads" count of other
mailboxes. mailboxes.
2. Emails that are *not* in the Trash are ignored when 2. Emails that are *not* in the Trash are ignored when
calculating the "unreadThreads" count for the Trash mailbox. calculating the "unreadThreads" count for the Trash mailbox.
The result of this is that emails in the Trash are treated as 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 though they are in a separate thread for the purposes of unread
skipping to change at page 9, line 49 skipping to change at page 10, line 34
would be "1" for the Trash and "0" for the Inbox. would be "1" for the Trash and "0" for the Inbox.
o *myRights*: "MailboxRights" (server-set) The set of rights (ACLs) o *myRights*: "MailboxRights" (server-set) The set of rights (ACLs)
the user has in relation to this mailbox. These are backwards the user has in relation to this mailbox. These are backwards
compatible with IMAP ACLs, as defined in [RFC4314]. A compatible with IMAP ACLs, as defined in [RFC4314]. A
_MailboxRights_ object has the following properties: _MailboxRights_ object has the following properties:
* *mayReadItems*: "Boolean" If true, the user may use this * *mayReadItems*: "Boolean" If true, the user may use this
mailbox as part of a filter in a _Email/query_ call and the mailbox as part of a filter in a _Email/query_ call and the
mailbox may be included in the _mailboxIds_ set of _Email_ mailbox may be included in the _mailboxIds_ set of _Email_
objects. If a sub-mailbox is shared but not the parent objects. Email objects may be fetched if they are in *at least
mailbox, this may be "false". Corresponds to IMAP ACLs "lr". 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".
* *mayAddItems*: "Boolean" The user may add mail to this mailbox * *mayAddItems*: "Boolean" The user may add mail to this mailbox
(by either creating a new email or moving an existing one). (by either creating a new email or moving an existing one).
Corresponds to IMAP ACL "i". Corresponds to IMAP ACL "i".
* *mayRemoveItems*: "Boolean" The user may remove mail from this * *mayRemoveItems*: "Boolean" The user may remove mail from this
mailbox (by either changing the mailboxes of an email or mailbox (by either changing the mailboxes of an email or
deleting it). Corresponds to IMAP ACLs "te". deleting it). Corresponds to IMAP ACLs "te".
* *maySetSeen*: "Boolean" The user may add or remove the "$seen" * *maySetSeen*: "Boolean" The user may add or remove the "$seen"
skipping to change at page 12, line 33 skipping to change at page 13, line 21
o *role*: "String|null" The Mailbox _role_ property must match the o *role*: "String|null" The Mailbox _role_ property must match the
given value exactly. given value exactly.
o *hasAnyRole*: "Boolean" If "true", a Mailbox matches if it has any o *hasAnyRole*: "Boolean" If "true", a Mailbox matches if it has any
non-"null" value for its _role_ property. non-"null" value for its _role_ property.
o *isSubscribed*: "Boolean" The "isSubscribed" property of the o *isSubscribed*: "Boolean" The "isSubscribed" property of the
mailbox must be identical to the value given to match the mailbox must be identical to the value given to match the
condition. condition.
A Mailbox object matches the filter if and only if all of the given A Mailbox object matches the FilterCondition if and only if all of
conditions match. If zero properties are specified, it is the given conditions match. If zero properties are specified, it is
automatically "true" for all objects. automatically "true" for all objects.
The following properties MUST be supported for sorting: The following properties MUST be supported for sorting:
o "sortOrder" o "sortOrder"
o "name" o "name"
2.4. Mailbox/queryChanges 2.4. Mailbox/queryChanges
skipping to change at page 14, line 5 skipping to change at page 14, line 19
Fetching all mailboxes in an account: Fetching all mailboxes in an account:
[[ "Mailbox/get", { [[ "Mailbox/get", {
"accountId": "u33084183", "accountId": "u33084183",
"ids": null "ids": null
}, "0" ]] }, "0" ]]
And response: And response:
[[ "Mailbox/get", { [[ "Mailbox/get", {
"accountId": "u33084183", "accountId": "u33084183",
"state": "78540", "state": "78540",
"list": [{ "list": [{
"id": "23cfa8094c0f41e6", "id": "MB23cfa8094c0f41e6",
"name": "Inbox", "name": "Inbox",
"parentId": null, "parentId": null,
"role": "inbox", "role": "inbox",
"sortOrder": 10, "sortOrder": 10,
"totalEmails": 16307, "totalEmails": 16307,
"unreadEmails": 13905, "unreadEmails": 13905,
"totalThreads": 5833, "totalThreads": 5833,
"unreadThreads": 5128, "unreadThreads": 5128,
"myRights": { "myRights": {
"mayAddItems": true, "mayAddItems": true,
"mayRename": false, "mayRename": false,
"maySubmit": true, "maySubmit": true,
"mayDelete": false, "mayDelete": false,
"maySetKeywords": true, "maySetKeywords": true,
"mayRemoveItems": true, "mayRemoveItems": true,
"mayCreateChild": true, "mayCreateChild": true,
"maySetSeen": true, "maySetSeen": true,
"mayReadItems": true "mayReadItems": true
}, },
"isSubscribed": true "isSubscribed": true
}, { }, {
"id": "674cc24095db49ce", "id": "MB674cc24095db49ce",
"name": "Important mail", "name": "Important mail",
... ...
}, ... ], }, ... ],
"notFound": [] "notFound": []
}, "0" ]] }, "0" ]]
Now suppose a message is marked read and we get a push update that Now suppose a message is marked read and we get a push update that
the Mailbox state has changed. You might fetch the updates like the Mailbox state has changed. You might fetch the updates like
this: this:
[[ "Mailbox/changes", { [[ "Mailbox/changes", {
"accountId": "u33084183", "accountId": "u33084183",
"sinceState": "78540" "sinceState": "78540"
}, "0" ], }, "0" ],
[ "Mailbox/get", { [ "Mailbox/get", {
skipping to change at page 16, line 5 skipping to change at page 16, line 5
"name": "Mailbox/changes", "name": "Mailbox/changes",
"path": "/updatedProperties" "path": "/updatedProperties"
} }
}, "2" ]] }, "2" ]]
This fetches the list of ids for created/updated/destroyed mailboxes, This fetches the list of ids for created/updated/destroyed mailboxes,
then using back-references fetches the data for just the created/ then using back-references fetches the data for just the created/
updated mailboxes in the same request. The response may look updated mailboxes in the same request. The response may look
something like this: something like this:
[[ "Mailbox/changes", { [[ "Mailbox/changes", {
"accountId": "u33084183", "accountId": "u33084183",
"oldState": "78541", "oldState": "78541",
"newState": "78542", "newState": "78542",
"hasMoreChanges": false, "hasMoreChanges": false,
"updatedProperties": [ "updatedProperties": [
"totalEmails", "unreadEmails", "totalEmails", "unreadEmails",
"totalThreads", "unreadThreads" "totalThreads", "unreadThreads"
], ],
"created": [], "created": [],
"updated": ["23cfa8094c0f41e6"], "updated": ["MB23cfa8094c0f41e6"],
"destroyed": [] "destroyed": []
}, "0" ], }, "0" ],
[ "Mailbox/get", { [ "Mailbox/get", {
"accountId": "u33084183", "accountId": "u33084183",
"state": "78542", "state": "78542",
"list": [], "list": [],
"notFound": [] "notFound": []
}, "1" ], }, "1" ],
[ "Mailbox/get", { [ "Mailbox/get", {
"accountId": "u33084183", "accountId": "u33084183",
"state": "78542", "state": "78542",
"list": [{ "list": [{
"id": "23cfa8094c0f41e6", "id": "MB23cfa8094c0f41e6",
"totalEmails": 16307, "totalEmails": 16307,
"unreadEmails": 13903, "unreadEmails": 13903,
"totalThreads": 5833, "totalThreads": 5833,
"unreadThreads": 5127 "unreadThreads": 5127
}], }],
"notFound": [] "notFound": []
}, "2" ]] }, "2" ]]
Here's an example where we try to rename one mailbox and destroy Here's an example where we try to rename one mailbox and destroy
another: another:
[[ "Mailbox/set", { [[ "Mailbox/set", {
"accountId": "u33084183", "accountId": "u33084183",
"ifInState": "78542", "ifInState": "78542",
"update": { "update": {
"674cc24095db49ce": { "MB674cc24095db49ce": {
"name": "Maybe important mail" "name": "Maybe important mail"
} }
}, },
"destroy": [ "23cfa8094c0f41e6" ] "destroy": [ "MB23cfa8094c0f41e6" ]
}, "0" ]] }, "0" ]]
Suppose the rename succeeds, but we don't have permission to destroy Suppose the rename succeeds, but we don't have permission to destroy
the mailbox we tried to destroy, we might get back: the mailbox we tried to destroy, we might get back:
[[ "Mailbox/set", { [[ "Mailbox/set", {
"accountId": "u33084183", "accountId": "u33084183",
"oldState": "78542", "oldState": "78542",
"newState": "78549", "newState": "78549",
"updated": { "updated": {
"674cc24095db49ce": null "MB674cc24095db49ce": null
}, },
"notDestroyed": { "notDestroyed": {
"23cfa8094c0f41e6": { "MB23cfa8094c0f41e6": {
"type": "forbidden" "type": "forbidden"
} }
} }
}, "0" ]] }, "0" ]]
3. Threads 3. Threads
Replies are grouped together with the original message to form a Replies are grouped together with the original message to form a
thread. In JMAP, a thread is simply a flat list of emails, ordered 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 by date. Every email MUST belong to a thread, even if it is the only
email in the thread. email in the thread.
The exact algorithm for determining whether two emails belong to the The exact algorithm for determining whether two emails belong to the
same thread is not mandated in this spec to allow for compatibility same thread is not mandated in this spec to allow for compatibility
skipping to change at page 20, line 43 skipping to change at page 20, line 43
o *threadId*: "Id" (immutable; server-set) The id of the Thread to o *threadId*: "Id" (immutable; server-set) The id of the Thread to
which this Email belongs. which this Email belongs.
o *mailboxIds*: "Id[Boolean]" The set of Mailbox ids this email o *mailboxIds*: "Id[Boolean]" The set of Mailbox ids this email
belongs to. An email MUST belong to one or more mailboxes at all belongs to. An email MUST belong to one or more mailboxes at all
times (until it is deleted). The set is represented as an object, times (until it is deleted). The set is represented as an object,
with each key being a _Mailbox id_. The value for each key in the with each key being a _Mailbox id_. The value for each key in the
object MUST be "true". object MUST be "true".
o *keywords*: "String[Boolean]" (default: ) A set of keywords that o *keywords*: "String[Boolean]" (default: {}) A set of keywords that
apply to the email. The set is represented as an object, with the 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 keys being the _keywords_. The value for each key in the object
MUST be "true". Keywords are shared with IMAP. The six system MUST be "true". Keywords are shared with IMAP. The six system
keywords from IMAP are treated specially. The following four keywords from IMAP are treated specially. The following four
keywords have their first character changed from "\" in IMAP to keywords have their first character changed from "\" in IMAP to
"$" in JMAP and have particular semantic meaning: "$" in JMAP and have particular semantic meaning:
* "$draft": The email is a draft the user is composing. * "$draft": The email is a draft the user is composing.
* "$seen": The email has been read. * "$seen": The email has been read.
skipping to change at page 21, line 40 skipping to change at page 21, line 40
and disable links and attachments. and disable links and attachments.
* "$junk": The email is definitely spam. Clients SHOULD set this * "$junk": The email is definitely spam. Clients SHOULD set this
flag when users report spam to help train automated spam- flag when users report spam to help train automated spam-
detection systems. detection systems.
* "$notjunk": The email is definitely not spam. Clients SHOULD * "$notjunk": The email is definitely not spam. Clients SHOULD
set this flag when users indicate an email is legitimate, to set this flag when users indicate an email is legitimate, to
help train automated spam-detection systems. help train automated spam-detection systems.
o *size*: "PositiveInt" (immutable; server-set) The size, in octets, o *size*: "UnsignedInt" (immutable; server-set) The size, in octets,
of the raw data for the [RFC5322] message (as referenced by the of the raw data for the [RFC5322] message (as referenced by the
_blobId_, i.e. the number of octets in the file the user would _blobId_, i.e. the number of octets in the file the user would
download). download).
o *receivedAt*: "UTCDate" (immutable; default: time of creation on o *receivedAt*: "UTCDate" (immutable; default: time of creation on
server) The date the email was received by the message store. server) The date the email was received by the message store.
This is the _internal date_ in IMAP ([RFC3501]). This is the _internal date_ in IMAP ([RFC3501]).
4.1.2. Header fields parsed forms 4.1.2. Header fields parsed forms
skipping to change at page 23, line 31 skipping to change at page 23, line 31
Type: "EmailAddress[]" Type: "EmailAddress[]"
The header is parsed as an "address-list" value, as specified in The header is parsed as an "address-list" value, as specified in
[RFC5322] section 3.4, into the "EmailAddress[]" type. There is an [RFC5322] section 3.4, into the "EmailAddress[]" type. There is an
EmailAddress item for each "mailbox" parsed from the "address-list". EmailAddress item for each "mailbox" parsed from the "address-list".
Group and comment information is discarded. Group and comment information is discarded.
The *EmailAddress* object has the following properties: The *EmailAddress* object has the following properties:
o *name*: "String|null" The _display-name_ of the [RFC5322] o *name*: "String|null" The _display-name_ of the [RFC5322]
_mailbox_, or "null" if none. If this is a _quoted-string_: _mailbox_. If this is a _quoted-string_:
1. The surrounding DQUOTE characters are removed. 1. The surrounding DQUOTE characters are removed.
2. Any _quoted-pair_ is decoded. 2. Any _quoted-pair_ is decoded.
3. White-space is unfolded, and then any leading and trailing 3. White-space is unfolded, and then any leading and trailing
white-space is removed. 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 [RFC5322] _mailbox_. o *email*: "String" The _addr-spec_ of the [RFC5322] _mailbox_.
Any syntactically correct [RFC2047] encoded sections with a known Any syntactically correct [RFC2047] encoded sections with a known
encoding MUST be decoded, following the same rules as for the _Text_ encoding MUST be decoded, following the same rules as for the _Text_
form. form.
Parsing SHOULD be best-effort in the face of invalid structure to Parsing SHOULD be best-effort in the face of invalid structure to
accommodate invalid messages and semi-complete drafts. EmailAddress accommodate invalid messages and semi-complete drafts. EmailAddress
objects MAY have an _email_ property that does not conform to the objects MAY have an _email_ property that does not conform to the
_addr-spec_ form (for example, may not contain an @ symbol). _addr-spec_ form (for example, may not contain an @ symbol).
skipping to change at page 30, line 5 skipping to change at page 30, line 8
o *blobId*: "Id|null" The id representing the raw octets of the o *blobId*: "Id|null" The id representing the raw octets of the
contents of the part, after decoding any known _Content-Transfer- contents of the part, after decoding any known _Content-Transfer-
Encoding_ (as defined in [RFC2045]), or "null" if, and only if, Encoding_ (as defined in [RFC2045]), or "null" if, and only if,
the part is of type "multipart/*". Note, two parts may be the part is of type "multipart/*". Note, two parts may be
transfer-encoded differently but have the same blob id if their transfer-encoded differently but have the same blob id if their
decoded octets are identical and the server is using a secure hash 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, of the data for the blob id. If the transfer encoding is unknown,
it is treated as though it had no transfer-encoding. it is treated as though it had no transfer-encoding.
o *size*: "PositiveInt" The size, in octets, of the raw data after o *size*: "UnsignedInt" The size, in octets, of the raw data after
content transfer decoding (as referenced by the _blobId_, i.e. the content transfer decoding (as referenced by the _blobId_, i.e. the
number of octets in the file the user would download). number of octets in the file the user would download).
o *headers*: "EmailHeader[]" This is a list of all header fields in 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 the part, in the order they appear in the message. The values are
in _Raw_ form. in _Raw_ form.
o *name*: "String|null" This is the [RFC2231] decoded _filename_ o *name*: "String|null" This is the [RFC2231] decoded _filename_
parameter of the _Content-Disposition_ header field, or (for parameter of the _Content-Disposition_ header field, or (for
compatibility with existing systems) if not present then the compatibility with existing systems) if not present then the
skipping to change at page 31, line 40 skipping to change at page 31, line 43
unknown, or if no charset is given, or if it believes the unknown, or if no charset is given, or if it believes the
charset given is incorrect. Decoding is best-effort and SHOULD charset given is incorrect. Decoding is best-effort and SHOULD
insert the unicode replacement character (U+FFFD) and continue insert the unicode replacement character (U+FFFD) and continue
when a malformed section is encountered. Note that due to the when a malformed section is encountered. Note that due to the
charset decoding and line ending normalisation, the length of charset decoding and line ending normalisation, the length of
this string will probably not be exactly the same as the _size_ this string will probably not be exactly the same as the _size_
property on the corresponding EmailBodyPart. property on the corresponding EmailBodyPart.
* *isEncodingProblem*: "Boolean" (default: false) This is "true" * *isEncodingProblem*: "Boolean" (default: false) This is "true"
if malformed sections were found while decoding the charset, or if malformed sections were found while decoding the charset, or
the charset was unknown, or the content-trasfer-encoding was the charset was unknown, or the content-transfer-encoding was
unknown. unknown.
* *isTruncated*: "Boolean" (default: false) This is "true" if the * *isTruncated*: "Boolean" (default: false) This is "true" if the
_value_ has been truncated. _value_ has been truncated.
See the security considerations section for issues related to See the security considerations section for issues related to
truncation and heuristic determination of content-type and truncation and heuristic determination of content-type and
charset. charset.
o *textBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", o *textBody*: "EmailBodyPart[]" (immutable) A list of "text/plain",
skipping to change at page 36, line 13 skipping to change at page 36, line 13
property. property.
o *fetchHTMLBodyValues*: "Boolean" (default: false) If "true", the o *fetchHTMLBodyValues*: "Boolean" (default: false) If "true", the
_bodyValues_ property includes any "text/*" part in the "htmlBody" _bodyValues_ property includes any "text/*" part in the "htmlBody"
property. property.
o *fetchAllBodyValues*: "Boolean" (default: false) If "true", the o *fetchAllBodyValues*: "Boolean" (default: false) If "true", the
_bodyValues_ property includes any "text/*" part in the _bodyValues_ property includes any "text/*" part in the
"bodyStructure" property. "bodyStructure" property.
o *maxBodyValueBytes*: "PositiveInt" (default: 0) If greater than o *maxBodyValueBytes*: "UnsignedInt" (default: 0) If greater than
zero, the _value_ property of any EmailBodyValue object returned zero, the _value_ property of any EmailBodyValue object returned
in _bodyValues_ MUST be truncated if necessary so it does not in _bodyValues_ MUST be truncated if necessary so it does not
exceed this number of octets in size. If "0" (the default), no exceed this number of octets in size. If "0" (the default), no
truncation occurs. The server MUST ensure the truncation results truncation occurs. The server MUST ensure the truncation results
in valid UTF-8 and does not occur mid-codepoint. If the part is 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 of type "text/html", the server SHOULD NOT truncate inside an HTML
tag, e.g. in the middle of "<a href="https://example.com">". tag, e.g. in the middle of "<a href="https://example.com">".
There is no requirement for the truncated form to be a balanced There is no requirement for the truncated form to be a balanced
tree or valid HTML (indeed, the original source may well be tree or valid HTML (indeed, the original source may well be
neither of these things). neither of these things).
skipping to change at page 38, line 21 skipping to change at page 38, line 21
"threadId": "ef1314a", "threadId": "ef1314a",
"mailboxIds": { "f123": true }, "mailboxIds": { "f123": true },
"from": [{ "name": "Joe Bloggs", "email": "joe@example.com" }], "from": [{ "name": "Joe Bloggs", "email": "joe@example.com" }],
"subject": "Dinner on Thursday?", "subject": "Dinner on Thursday?",
"receivedAt": "2013-10-13T14:12:00Z", "receivedAt": "2013-10-13T14:12:00Z",
"header:List-POST:asURLs": [ "header:List-POST:asURLs": [
"mailto:partytime@lists.example.com" "mailto:partytime@lists.example.com"
], ],
"htmlBody": [{ "htmlBody": [{
"partId": "1", "partId": "1",
"blobId": "841623871", "blobId": "B841623871",
"size": 283331, "size": 283331,
"type": "text/html" "type": "text/html"
}, { }, {
"partId": "2", "partId": "2",
"blobId": "319437193", "blobId": "B319437193",
"size": 10343, "size": 10343,
"type": "text/plain" "type": "text/plain"
}], }],
"bodyValues": { "bodyValues": {
"1": { "1": {
"isEncodingProblem": false, "isEncodingProblem": false,
"isTruncated": true, "isTruncated": true,
"value": "<html><body><p>Hello ..." "value": "<html><body><p>Hello ..."
}, },
"2": { "2": {
skipping to change at page 39, line 41 skipping to change at page 39, line 41
be in at least one mailbox not in this list to match the 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 condition. This is to allow messages solely in trash/spam to be
easily excluded from a search. easily excluded from a search.
o *before*: "UTCDate" The _receivedAt_ date-time of the email must o *before*: "UTCDate" The _receivedAt_ date-time of the email must
be before this date-time to match the condition. be before this date-time to match the condition.
o *after*: "UTCDate" The _receivedAt_ date-time of the email must be o *after*: "UTCDate" The _receivedAt_ date-time of the email must be
the same or after this date-time to match the condition. the same or after this date-time to match the condition.
o *minSize*: "PositiveInt" The _size_ of the email in octets must be o *minSize*: "UnsignedInt" The _size_ of the email in octets must be
equal to or greater than this number to match the condition. equal to or greater than this number to match the condition.
o *maxSize*: "PositiveInt" The _size_ of the email in octets must be o *maxSize*: "UnsignedInt" The _size_ of the email in octets must be
less than this number to match the condition. less than this number to match the condition.
o *allInThreadHaveKeyword*: "String" All emails (including this one) o *allInThreadHaveKeyword*: "String" All emails (including this one)
in the same thread as this email must have the given keyword to in the same thread as this email must have the given keyword to
match the condition. match the condition.
o *someInThreadHaveKeyword*: "String" At least one email (possibly o *someInThreadHaveKeyword*: "String" At least one email (possibly
this one) in the same thread as this email must have the given this one) in the same thread as this email must have the given
keyword to match the condition. keyword to match the condition.
skipping to change at page 47, line 8 skipping to change at page 47, line 8
specified) to EmailImport objects specified) to EmailImport objects
An *EmailImport* object has the following properties: An *EmailImport* object has the following properties:
o *blobId*: "Id" The id of the blob containing the raw [RFC5322] o *blobId*: "Id" The id of the blob containing the raw [RFC5322]
message. message.
o *mailboxIds*: "Id[Boolean]" The ids of the mailboxes to assign o *mailboxIds*: "Id[Boolean]" The ids of the mailboxes to assign
this email to. At least one mailbox MUST be given. this email to. At least one mailbox MUST be given.
o *keywords*: "String[Boolean]" (default: ) The keywords to apply to o *keywords*: "String[Boolean]" (default: {}) The keywords to apply
the email. to the email.
o *receivedAt*: "UTCDate" (default: time of most recent Received o *receivedAt*: "UTCDate" (default: time of most recent Received
header, or time of import on server if none) The _receivedAt_ date header, or time of import on server if none) The _receivedAt_ date
to set on the email. to set on the email.
Each email to import is considered an atomic unit which may succeed Each email to import is considered an atomic unit which may succeed
or fail individually. Importing successfully creates a new email or fail individually. Importing successfully creates a new email
object from the data referenced by the blobId and applies the given object from the data referenced by the blobId and applies the given
mailboxes, keywords and receivedAt date. mailboxes, keywords and receivedAt date.
skipping to change at page 49, line 25 skipping to change at page 49, line 25
property. property.
o *fetchHTMLBodyValues*: "Boolean" (default: false) If "true", the o *fetchHTMLBodyValues*: "Boolean" (default: false) If "true", the
_bodyValues_ property includes any "text/*" part in the "htmlBody" _bodyValues_ property includes any "text/*" part in the "htmlBody"
property. property.
o *fetchAllBodyValues*: "Boolean" (default: false) If "true", the o *fetchAllBodyValues*: "Boolean" (default: false) If "true", the
_bodyValues_ property includes any "text/*" part in the _bodyValues_ property includes any "text/*" part in the
"bodyStructure" property. "bodyStructure" property.
o *maxBodyValueBytes*: "PositiveInt" (default: 0) If greater than o *maxBodyValueBytes*: "UnsignedInt" (default: 0) If greater than
zero, the _value_ property of any EmailBodyValue object returned zero, the _value_ property of any EmailBodyValue object returned
in _bodyValues_ MUST be truncated if necessary so it does not in _bodyValues_ MUST be truncated if necessary so it does not
exceed this number of octets in size. If "0" (the default), no exceed this number of octets in size. If "0" (the default), no
truncation occurs. The server MUST ensure the truncation results truncation occurs. The server MUST ensure the truncation results
in valid UTF-8 and does not occur mid-codepoint. If the part is 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 of type "text/html", the server SHOULD NOT truncate inside an HTML
tag, e.g. in the middle of "<a href="https://example.com">". tag, e.g. in the middle of "<a href="https://example.com">".
There is no requirement for the truncated form to be a balanced There is no requirement for the truncated form to be a balanced
tree or valid HTML (indeed, the original source may well be tree or valid HTML (indeed, the original source may well be
neither of these things). neither of these things).
skipping to change at page 55, line 38 skipping to change at page 55, line 38
"to": [{ "to": [{
"name": "John", "name": "John",
"email": "john@example.com" "email": "john@example.com"
}], }],
"subject": "World domination", "subject": "World domination",
"receivedAt": "2018-07-10T01:05:08Z", "receivedAt": "2018-07-10T01:05:08Z",
"sentAt": "2018-07-10T11:05:08+10:00", "sentAt": "2018-07-10T11:05:08+10:00",
"bodyStructure": { "bodyStructure": {
"type": "multipart/alternative", "type": "multipart/alternative",
"subParts": [{ "subParts": [{
"partId": "49db", "partId": "a49d",
"type": "text/html" "type": "text/html"
}, { }, {
"partId": "bd48", "partId": "bd48",
"type": "text/plain" "type": "text/plain"
}] }]
}, },
"bodyValues": { "bodyValues": {
"bd48": { "bd48": {
"value": "I have the most brilliant plan. Let me tell you "value": "I have the most brilliant plan. Let me tell you
all about it. What we do is, we", all about it. What we do is, we",
skipping to change at page 56, line 39 skipping to change at page 56, line 39
... ...
}, "0" ]] }, "0" ]]
The client moves this draft to a different account. The only way to The client moves this draft to a different account. The only way to
do this is via the "/copy" method. It MUST set a new mailboxIds do this is via the "/copy" method. It MUST set a new mailboxIds
property, since the current value will not be valid mailbox ids in property, since the current value will not be valid mailbox ids in
the destination account: the destination account:
[[ "Email/copy", { [[ "Email/copy", {
"fromAccountId": "ue150411c", "fromAccountId": "ue150411c",
"accountId": "6c6c41ac", "accountId": "u6c6c41ac",
"create": { "create": {
"k45": { "k45": {
"id": "Md45b47b4877521042cec0938", "id": "Md45b47b4877521042cec0938",
"mailboxIds": { "mailboxIds": {
"75a4c956": true "75a4c956": true
} }
} }
}, },
"onSuccessDestroyOriginal": true "onSuccessDestroyOriginal": true
}, "0" ]] }, "0" ]]
The server successfully copies the email and deletes the original. The server successfully copies the email and deletes the original.
Due to the implicit call to "Email/set", there are two responses to Due to the implicit call to "Email/set", there are two responses to
the single method call, both with the same client id: the single method call, both with the same method call id:
[[ "Email/copy", { [[ "Email/copy", {
"fromAccountId": "ue150411c", "fromAccountId": "ue150411c",
"accountId": "6c6c41ac", "accountId": "u6c6c41ac",
"oldState": "7ee7e9263a6d", "oldState": "7ee7e9263a6d",
"newState": "5a0d2447ed26", "newState": "5a0d2447ed26",
"created": { "created": {
"k45": { "k45": {
"id": "M138f9954a5cd2423daeafa55", "id": "M138f9954a5cd2423daeafa55",
"blobId": "G6b9fb047cba722c48c611e79233d057c6b0b74e8", "blobId": "G6b9fb047cba722c48c611e79233d057c6b0b74e8",
"threadId": "T2f242ea424a4079a", "threadId": "T2f242ea424a4079a",
"size": 11721 "size": 11721
} }
}, },
skipping to change at page 62, line 20 skipping to change at page 62, line 20
"accountId": "acme" "accountId": "acme"
}, "0" ] }, "0" ]
with response: with response:
[ "Identity/get", { [ "Identity/get", {
"accountId": "acme", "accountId": "acme",
"state": "99401312ae-11-333", "state": "99401312ae-11-333",
"list": [ "list": [
{ {
"id": "3301-222-11_22AAz", "id": "XD-3301-222-11_22AAz",
"name": "Joe Bloggs", "name": "Joe Bloggs",
"email": "joe@example.com", "email": "joe@example.com",
"replyTo": null, "replyTo": null,
"bcc": [{ "bcc": [{
"name": null, "name": null,
"email": "joe+archive@example.com" "email": "joe+archive@example.com"
}], }],
"textSignature": "-- \nJoe Bloggs\nMaster of Email", "textSignature": "-- \nJoe Bloggs\nMaster of Email",
"htmlSignature": "<div><b>Joe Bloggs</b></div> "htmlSignature": "<div><b>Joe Bloggs</b></div>
<div>Master of Email</div>", <div>Master of Email</div>",
"mayDelete": false "mayDelete": false
}, },
{ {
"id": "9911312-11_22AAz", "id": "XD-9911312-11_22AAz",
"name": "Joe B", "name": "Joe B",
"email": "*@example.com", "email": "*@example.com",
"replyTo": null, "replyTo": null,
"bcc": null, "bcc": null,
"textSignature": "", "textSignature": "",
"htmlSignature": "", "htmlSignature": "",
"mayDelete": true "mayDelete": true
} }
], ],
"notFound": [] "notFound": []
skipping to change at page 64, line 26 skipping to change at page 64, line 26
o *sendAt*: "UTCDate" (immutable; server-set) The date the email o *sendAt*: "UTCDate" (immutable; server-set) The date the email
was/will be released for delivery. If the client successfully was/will be released for delivery. If the client successfully
used [RFC4865] FUTURERELEASE with the email, this MUST be the time used [RFC4865] FUTURERELEASE with the email, this MUST be the time
when the server will release the email; otherwise it MUST be the when the server will release the email; otherwise it MUST be the
time the EmailSubmission was created. time the EmailSubmission was created.
o *undoStatus*: "String" This represents whether the submission may o *undoStatus*: "String" This represents whether the submission may
be canceled. This is server set and MUST be one of the following be canceled. This is server set and MUST be one of the following
values: values:
* "pending": It MAY be possible to cancel this submission. * "pending": It may be possible to cancel this submission.
* "final": The email has been relayed to at least one recipient * "final": The email has been relayed to at least one recipient
in a manner that cannot be recalled. It is no longer possible in a manner that cannot be recalled. It is no longer possible
to cancel this submission. to cancel this submission.
* "canceled": The email submission was canceled and will not be * "canceled": The email submission was canceled and will not be
delivered to any recipient. delivered to any recipient.
On systems that do not support unsending, the value of this On systems that do not support unsending, the value of this
property will always be "final". On systems that do support property will always be "final". On systems that do support
skipping to change at page 68, line 15 skipping to change at page 68, line 15
o *undoStatus*: "String" The EmailSubmission _undoStatus_ property o *undoStatus*: "String" The EmailSubmission _undoStatus_ property
must be identical to the value given to match the condition. must be identical to the value given to match the condition.
o *before*: "UTCDate" The _sendAt_ property of the EmailSubmission o *before*: "UTCDate" The _sendAt_ property of the EmailSubmission
object must be before this date-time to match the condition. object must be before this date-time to match the condition.
o *after*: "UTCDate" The _sendAt_ property of the EmailSubmission o *after*: "UTCDate" The _sendAt_ property of the EmailSubmission
object must be the same as or after this date-time to match the object must be the same as or after this date-time to match the
condition. condition.
An EmailSubmission object matches the filter if and only if all of An EmailSubmission object matches the FilterCondition if and only if
the given conditions match. If zero properties are specified, it is all of the given conditions match. If zero properties are specified,
automatically "true" for all objects. it is automatically "true" for all objects.
The following properties MUST be supported for sorting: The following properties MUST be supported for sorting:
o "emailId" o "emailId"
o "threadId" o "threadId"
o "sentAt" o "sentAt"
7.4. EmailSubmission/queryChanges 7.4. EmailSubmission/queryChanges
skipping to change at page 69, line 27 skipping to change at page 69, line 27
Similarly, destroying an EmailSubmission object MUST NOT affect the Similarly, destroying an EmailSubmission object MUST NOT affect the
deliveries it represents. It purely removes the record of the email deliveries it represents. It purely removes the record of the email
submission. The server MAY automatically destroy EmailSubmission submission. The server MAY automatically destroy EmailSubmission
objects after a certain time or in response to other triggers, and objects after a certain time or in response to other triggers, and
MAY forbid the client from manually destroying EmailSubmission MAY forbid the client from manually destroying EmailSubmission
objects. objects.
If the email to be sent is larger than the server supports sending, a If the email to be sent is larger than the server supports sending, a
standard "tooLarge" SetError MUST be returned. A _maxSize_ standard "tooLarge" SetError MUST be returned. A _maxSize_
"PositiveInt" property MUST be present on the SetError specifying the "UnsignedInt" property MUST be present on the SetError specifying the
maximum size of an email that may be sent, in octets. maximum size of an email that may be sent, in octets.
If the email or identity id given cannot be found, the submission If the email or identity id given cannot be found, the submission
creation is rejected with a standard "invalidProperties" SetError. creation is rejected with a standard "invalidProperties" SetError.
The following extra _SetError_ types are defined: The following extra _SetError_ types are defined:
For *create*: For *create*:
o "invalidEmail" - The email to be sent is invalid in some way. The o "invalidEmail" - The email to be sent is invalid in some way. The
SetError SHOULD contain a property called _properties_ of type SetError SHOULD contain a property called _properties_ of type
"String[]" that lists *all* the properties of the email that were "String[]" that lists *all* the properties of the email that were
invalid. invalid.
o "tooManyRecipients" - The envelope (supplied or generated) has o "tooManyRecipients" - The envelope (supplied or generated) has
more recipients than the server allows. A _maxRecipients_ more recipients than the server allows. A _maxRecipients_
"PositiveInt" property MUST also be present on the SetError "UnsignedInt" property MUST also be present on the SetError
specifying the maximum number of allowed recipients. specifying the maximum number of allowed recipients.
o "noRecipients" - The envelope (supplied or generated) does not o "noRecipients" - The envelope (supplied or generated) does not
have any rcptTo emails. have any rcptTo emails.
o "invalidRecipients" - The _rcptTo_ property of the envelope o "invalidRecipients" - The _rcptTo_ property of the envelope
(supplied or generated) contains at least one rcptTo value which (supplied or generated) contains at least one rcptTo value which
is not a valid email for sending to. An _invalidRecipients_ is not a valid email for sending to. An _invalidRecipients_
"String[]" property MUST also be present on the SetError, which is "String[]" property MUST also be present on the SetError, which is
a list of the invalid addresses. a list of the invalid addresses.
skipping to change at page 71, line 9 skipping to change at page 71, line 9
already been saved, and its Email id is "M7f6ed5bcfd7e2604d1753f6c". already been saved, and its Email id is "M7f6ed5bcfd7e2604d1753f6c".
This call then sends the email immediately, and if successful removes This call then sends the email immediately, and if successful removes
the draft flag and moves it from the Drafts folder (which has Mailbox the draft flag and moves it from the Drafts folder (which has Mailbox
id "7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e") to the Sent folder (which id "7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e") to the Sent folder (which
we presume has Mailbox id "73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6"). we presume has Mailbox id "73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6").
[[ "EmailSubmission/set", { [[ "EmailSubmission/set", {
"accountId": "ue411d190", "accountId": "ue411d190",
"create": { "create": {
"k1490": { "k1490": {
"identityId": "64588216", "identityId": "I64588216",
"emailId": "M7f6ed5bcfd7e2604d1753f6c", "emailId": "M7f6ed5bcfd7e2604d1753f6c",
"envelope": { "envelope": {
"mailFrom": { "mailFrom": {
"email": "john@example.com", "email": "john@example.com",
"parameters": null "parameters": null
}, },
"rcptTo": [{ "rcptTo": [{
"email": "jane@example.com", "email": "jane@example.com",
"parameters": null "parameters": null
}, },
skipping to change at page 71, line 36 skipping to change at page 71, line 36
"#k1490": { "#k1490": {
"mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null, "mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null,
"mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true, "mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true,
"keywords/$draft": null "keywords/$draft": null
} }
} }
}, "0" ]] }, "0" ]]
A successful response might look like this. Note there are two A successful response might look like this. Note there are two
responses due to the implicit Email/set call, but both have the same responses due to the implicit Email/set call, but both have the same
client id as they are due to the same call in the request: method call id as they are due to the same call in the request:
[[ "EmailSubmission/set", { [[ "EmailSubmission/set", {
"accountId": "ue411d190", "accountId": "ue411d190",
"oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21",
"newState": "355421f6-8aed-4cf4-a0c4-7377e951af36", "newState": "355421f6-8aed-4cf4-a0c4-7377e951af36",
"created": { "created": {
"k1490": { "k1490": {
"id": "3bab7f9a-623e-4acf-99a5-2e67facb02a0" "id": "ES-3bab7f9a-623e-4acf-99a5-2e67facb02a0"
} }
} }
}, "0" ], }, "0" ],
[ "Email/set", { [ "Email/set", {
"accountId": "ue411d190", "accountId": "ue411d190",
"oldState": "778193", "oldState": "778193",
"newState": "778197", "newState": "778197",
"updated": { "updated": {
"M7f6ed5bcfd7e2604d1753f6c": null "M7f6ed5bcfd7e2604d1753f6c": null
} }
skipping to change at page 76, line 21 skipping to change at page 76, line 21
implementers are strongly recommended to use a well-tested library implementers are strongly recommended to use a well-tested library
with a carefully vetted whitelist-only approach. New features with a carefully vetted whitelist-only approach. New features
with unexpected security characteristics may be added to HTML with unexpected security characteristics may be added to HTML
rendering engines in the future; a blacklist approach is likely to rendering engines in the future; a blacklist approach is likely to
result in security issues. result in security issues.
Subtle differences in parsing of HTML can introduce security flaws: Subtle differences in parsing of HTML can introduce security flaws:
to filter with 100% accuracy you need to use the same parser when to filter with 100% accuracy you need to use the same parser when
sanitizing that the HTML rendering engine will use. sanitizing that the HTML rendering engine will use.
o Encapsulating the message in an "<iframe sandbox>" can help o Encapsulating the message in an "<iframe sandbox>", as defined in
mitigate a number of risks. This will: [HTML], section 4.7.6, can help mitigate a number of risks. This
will:
* Disable JavaScript. * Disable JavaScript.
* Disable form submission. * Disable form submission.
* Prevent drawing outside of its bounds, or conflict with * Prevent drawing outside of its bounds, or conflict with
interface CSS. interface CSS.
* Establish a unique anonymous origin, separate to the containing * Establish a unique anonymous origin, separate to the containing
origin. origin.
skipping to change at page 77, line 12 skipping to change at page 77, line 13
Serious bugs have been found in image decoders, JavaScript engines Serious bugs have been found in image decoders, JavaScript engines
and HTML parsers in the past, which could lead to full system and HTML parsers in the past, which could lead to full system
compromise. Clients using an engine should ensure they get the compromise. Clients using an engine should ensure they get the
latest version and continue to incorporate any security patches latest version and continue to incorporate any security patches
released by the vendor. released by the vendor.
9.3. Email submission 9.3. Email submission
SMTP submission servers [RFC6409] use a number of mechanisms to SMTP submission servers [RFC6409] use a number of mechanisms to
mitigate damage caused by compromised user accounts and end-user mitigate damage caused by compromised user accounts and end-user
systems including rate limiting, anti-virus/anti-spam milters and systems including rate limiting, anti-virus/anti-spam milters (mail
other technologies. The technologies work better when they have more filters) and other technologies. The technologies work better when
information about the client connection. If JMAP email submission is they have more information about the client connection. If JMAP
implemented as a proxy to an SMTP Submission server, it is useful to email submission is implemented as a proxy to an SMTP Submission
communicate this information from the JMAP proxy to the submission server, it is useful to communicate this information from the JMAP
server. The de-facto [XCLIENT] extension to SMTP can be used to do proxy to the submission server. The de-facto [XCLIENT] extension to
this, but use of an authenticated channel is recommended to limit use SMTP can be used to do this, but use of an authenticated channel is
of that extension to explicitly authorized proxies. recommended to limit use of that extension to explicitly authorized
proxies.
JMAP servers that proxy to an SMTP Submission server SHOULD allow use JMAP servers that proxy to an SMTP Submission server SHOULD allow use
of the _submissions_ port [RFC8314] and SHOULD implement SASL PLAIN of the _submissions_ port [RFC8314] and SHOULD implement SASL PLAIN
over TLS [RFC4616] and/or TLS client certificate authentication with over TLS [RFC4616] and/or TLS client certificate authentication with
SASL EXTERNAL [RFC4422] appendix A. Implementation of a mechanism SASL EXTERNAL [RFC4422] appendix A. Implementation of a mechanism
similar to SMTP XCLIENT is strongly encouraged. similar to SMTP XCLIENT is strongly encouraged.
In the event the JMAP server directly relays mail to SMTP servers in In the event the JMAP server directly relays mail to SMTP servers in
other administrative domains, then implementation of the de-facto other administrative domains, then implementation of the de-facto
milter protocol is strongly encouraged to integrate with third-party [milter] protocol is strongly encouraged to integrate with third-
products that address security issues including anti-virus/anti-spam, party products that address security issues including anti-virus/
reputation protection, compliance archiving, and data loss anti-spam, reputation protection, compliance archiving, and data loss
prevention. Proxying to a local SMTP Submission server may be a prevention. Proxying to a local SMTP Submission server may be a
simpler way to provide such security services. simpler way to provide such security services.
9.4. Partial account access
A user may only have permission to access a subset of the data that
exists in an account. To avoid leaking any 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.
10. IANA considerations 10. IANA considerations
10.1. JMAP capability registration for "mail" 10.1. JMAP capability registration for "mail"
IANA will register the "mail" JMAP Capability as follows: IANA will register the "mail" JMAP Capability as follows:
Capability Name: "urn:ietf:params:jmap:mail" Capability Name: "urn:ietf:params:jmap:mail"
Specification document: this document Specification document: this document
skipping to change at page 86, line 4 skipping to change at page 86, line 23
Change controller: IETF Change controller: IETF
Reference: This document, sections 6.3 and 7.5 Reference: This document, sections 6.3 and 7.5
10.6.12. forbiddenToSend 10.6.12. forbiddenToSend
JMAP Error Code: forbiddenToSend JMAP Error Code: forbiddenToSend
Intended use: common Intended use: common
Change controller: IETF Change controller: IETF
Reference: This document, section 7.5 Reference: This document, section 7.5
11. References 11. References
11.1. Normative References 11.1. Normative References
[HTML] Berners-Lee et al., T., "HTML Standard", 2019, [HTML] Faulkner, S., Eicholz, A., Leithead, T., Danilo, A., and
<https://html.spec.whatwg.org/>. S. Moon, "HTML 5.2", 2017,
<https://www.w3.org/TR/html52/>.
[I-D.ietf-jmap-core] [I-D.ietf-jmap-core]
Jenkins, N. and C. Newman, "JSON Meta Application Jenkins, N. and C. Newman, "JSON Meta Application
Protocol", draft-ietf-jmap-core-12 (work in progress), Protocol", draft-ietf-jmap-core-14 (work in progress),
December 2018. January 2019.
[RFC1870] Klensin, J., Freed, N., and K. Moore, "SMTP Service [RFC1870] Klensin, J., Freed, N., and K. Moore, "SMTP Service
Extension for Message Size Declaration", STD 10, RFC 1870, Extension for Message Size Declaration", STD 10, RFC 1870,
DOI 10.17487/RFC1870, November 1995, DOI 10.17487/RFC1870, November 1995,
<https://www.rfc-editor.org/info/rfc1870>. <https://www.rfc-editor.org/info/rfc1870>.
[RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
Extensions (MIME) Part One: Format of Internet Message Extensions (MIME) Part One: Format of Internet Message
Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996, Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996,
<https://www.rfc-editor.org/info/rfc2045>. <https://www.rfc-editor.org/info/rfc2045>.
skipping to change at page 89, line 14 skipping to change at page 89, line 39
[RFC6710] Melnikov, A. and K. Carlberg, "Simple Mail Transfer [RFC6710] Melnikov, A. and K. Carlberg, "Simple Mail Transfer
Protocol Extension for Message Transfer Priorities", Protocol Extension for Message Transfer Priorities",
RFC 6710, DOI 10.17487/RFC6710, August 2012, RFC 6710, DOI 10.17487/RFC6710, August 2012,
<https://www.rfc-editor.org/info/rfc6710>. <https://www.rfc-editor.org/info/rfc6710>.
[RFC8098] Hansen, T., Ed. and A. Melnikov, Ed., "Message Disposition [RFC8098] Hansen, T., Ed. and A. Melnikov, Ed., "Message Disposition
Notification", STD 85, RFC 8098, DOI 10.17487/RFC8098, Notification", STD 85, RFC 8098, DOI 10.17487/RFC8098,
February 2017, <https://www.rfc-editor.org/info/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: [RFC8314] Moore, K. and C. Newman, "Cleartext Considered Obsolete:
Use of Transport Layer Security (TLS) for Email Submission Use of Transport Layer Security (TLS) for Email Submission
and Access", RFC 8314, DOI 10.17487/RFC8314, January 2018, and Access", RFC 8314, DOI 10.17487/RFC8314, January 2018,
<https://www.rfc-editor.org/info/rfc8314>. <https://www.rfc-editor.org/info/rfc8314>.
[RFC8457] Leiba, B., Ed., "IMAP "$Important" Keyword and [RFC8457] Leiba, B., Ed., "IMAP "$Important" Keyword and
"\Important" Special-Use Attribute", RFC 8457, "\Important" Special-Use Attribute", RFC 8457,
DOI 10.17487/RFC8457, September 2018, DOI 10.17487/RFC8457, September 2018,
<https://www.rfc-editor.org/info/rfc8457>. <https://www.rfc-editor.org/info/rfc8457>.
[RFC8474] Gondwana, B., Ed., "IMAP Extension for Object [RFC8474] Gondwana, B., Ed., "IMAP Extension for Object
Identifiers", RFC 8474, DOI 10.17487/RFC8474, September Identifiers", RFC 8474, DOI 10.17487/RFC8474, September
2018, <https://www.rfc-editor.org/info/rfc8474>. 2018, <https://www.rfc-editor.org/info/rfc8474>.
11.2. Informative References 11.2. Informative References
[milter] Postfix, "Postfix before-queue Milter support", 2019,
<http://www.postfix.org/MILTER_README.html>.
[RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION [RFC3501] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
4rev1", RFC 3501, DOI 10.17487/RFC3501, March 2003, 4rev1", RFC 3501, DOI 10.17487/RFC3501, March 2003,
<https://www.rfc-editor.org/info/rfc3501>. <https://www.rfc-editor.org/info/rfc3501>.
[XCLIENT] Postfix, "Postfix XCLIENT Howto", 2019, [XCLIENT] Postfix, "Postfix XCLIENT Howto", 2019,
<http://www.postfix.org/XCLIENT_README.html>. <http://www.postfix.org/XCLIENT_README.html>.
11.3. URIs 11.3. URIs
[1] https://www.iana.org/assignments/imap-mailbox-name-attributes/ [1] https://www.iana.org/assignments/imap-mailbox-name-attributes/
 End of changes. 74 change blocks. 
200 lines changed or deleted 267 lines changed or added

This html diff was produced by rfcdiff 1.47. The latest version is available from http://tools.ietf.org/tools/rfcdiff/