draft-ietf-jmap-mail-06.txt   draft-ietf-jmap-mail-07.txt 
JMAP N. Jenkins JMAP N. Jenkins
Internet-Draft FastMail Internet-Draft FastMail
Updates: 5788 (if approved) July 2, 2018 Updates: 5788 (if approved) C. Newman
Intended status: Standards Track Intended status: Standards Track Oracle
Expires: January 3, 2019 Expires: February 8, 2019 August 7, 2018
JMAP for Mail JMAP for Mail
draft-ietf-jmap-mail-06 draft-ietf-jmap-mail-07
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. with a server using JMAP.
Status of This Memo Status of This Memo
This Internet-Draft is submitted in full conformance with the This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79. provisions of BCP 78 and BCP 79.
skipping to change at page 1, line 32 skipping to change at page 1, line 32
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 January 3, 2019. This Internet-Draft will expire on February 8, 2019.
Copyright Notice Copyright Notice
Copyright (c) 2018 IETF Trust and the persons identified as the Copyright (c) 2018 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 . . . . . . . . . . . . . . . . . . . . . . . . 3 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1. Notational conventions . . . . . . . . . . . . . . . . . 3 1.1. Notational conventions . . . . . . . . . . . . . . . . . 4
1.2. The Date data types . . . . . . . . . . . . . . . . . . . 4 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4
1.3. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 1.3. Additions to the capabilities object . . . . . . . . . . 4
1.4. Addition to the capabilities object . . . . . . . . . . . 4 1.3.1. urn:ietf:params:jmap:mail . . . . . . . . . . . . . . 5
1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.3.2. urn:ietf:params:jmap:submission . . . . . . . . . . . 5
2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.3.3. urn:ietf:params:jmap:vacationresponse . . . . . . . . 6
2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 9 1.4. Data type support in different accounts . . . . . . . . . 6
2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 9 1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 10 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 10 2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 10
2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 10 2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 10
2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 11
3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 11
2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 12
2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 12
3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 17 3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 17
3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 17 3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 18
4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.1. Properties of the Email object . . . . . . . . . . . . . 17 4.1. Properties of the Email object . . . . . . . . . . . . . 18
4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 19 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 19
4.1.2. Header fields . . . . . . . . . . . . . . . . . . . . 20 4.1.2. Header fields parsed forms . . . . . . . . . . . . . 21
4.1.3. Body parts . . . . . . . . . . . . . . . . . . . . . 26 4.1.3. Header fields properties . . . . . . . . . . . . . . 26
4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 32 4.1.4. Body parts . . . . . . . . . . . . . . . . . . . . . 28
4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 34 4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 34
4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 35 4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 36
4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 36 4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 37
4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 36 4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 38
4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 38 4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 38
4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 40 4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 40
4.4.4. Response . . . . . . . . . . . . . . . . . . . . . . 40 4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 42
4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 40 4.4.4. Response . . . . . . . . . . . . . . . . . . . . . . 42
4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 40 4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 42
4.7. Email/import . . . . . . . . . . . . . . . . . . . . . . 43 4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 42
4.8. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 44 4.7. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 45
4.8. Email/import . . . . . . . . . . . . . . . . . . . . . . 45
4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 46 4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 46
5. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 48 4.10. Examples . . . . . . . . . . . . . . . . . . . . . . . . 48
5.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 49 5. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 56
5.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 49 5.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 57
5.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 49 5.2. Example . . . . . . . . . . . . . . . . . . . . . . . . . 58
5.4. Example . . . . . . . . . . . . . . . . . . . . . . . . . 49 6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 59
6. Email submission . . . . . . . . . . . . . . . . . . . . . . 50 6.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 60
6.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 55 6.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 60
6.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 55 6.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 60
6.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 55 6.4. Example . . . . . . . . . . . . . . . . . . . . . . . . . 60
6.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 56 7. Email submission . . . . . . . . . . . . . . . . . . . . . . 61
6.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 56 7.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 66
6.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 58 7.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 66
7. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 59 7.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 66
7.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 60 7.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 67
7.2. Example . . . . . . . . . . . . . . . . . . . . . . . . . 61 7.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 67
8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 62 7.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 69
8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 63 8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 71
8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 63 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 72
9. Security considerations . . . . . . . . . . . . . . . . . . . 63 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 72
9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 63 9. Security considerations . . . . . . . . . . . . . . . . . . . 72
9.2. HTML email display . . . . . . . . . . . . . . . . . . . 64 9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 72
9.3. Email submission . . . . . . . . . . . . . . . . . . . . 66 9.2. HTML email display . . . . . . . . . . . . . . . . . . . 72
10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 67 9.3. Email submission . . . . . . . . . . . . . . . . . . . . 75
10.1. JMAP Capability Registration for "mail" . . . . . . . . 67 10. IANA considerations . . . . . . . . . . . . . . . . . . . . . 75
10.2. IMAP and JMAP Keywords Registry . . . . . . . . . . . . 67 10.1. JMAP capability registration for "mail" . . . . . . . . 75
10.2.1. Registration of JMAP keyword '$draft' . . . . . . . 68 10.2. JMAP capability registration for "submission" . . . . . 76
10.2.2. Registration of JMAP keyword '$seen' . . . . . . . . 69 10.3. JMAP capability registration for "vacationresponse" . . 76
10.2.3. Registration of JMAP keyword '$flagged' . . . . . . 69 10.4. IMAP and JMAP keywords registry . . . . . . . . . . . . 76
10.2.4. Registration of JMAP keyword '$answered' . . . . . . 70 10.4.1. Registration of JMAP keyword '$draft' . . . . . . . 77
10.2.5. Registration of '$recent' Keyword . . . . . . . . . 71 10.4.2. Registration of JMAP keyword '$seen' . . . . . . . . 78
11. References . . . . . . . . . . . . . . . . . . . . . . . . . 72 10.4.3. Registration of JMAP keyword '$flagged' . . . . . . 79
11.1. Normative References . . . . . . . . . . . . . . . . . . 72 10.4.4. Registration of JMAP keyword '$answered' . . . . . . 79
11.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 75 10.4.5. Registration of '$recent' keyword . . . . . . . . . 80
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 75 10.5. JMAP Error Codes registry . . . . . . . . . . . . . . . 81
10.5.1. mailboxHasChild . . . . . . . . . . . . . . . . . . 81
10.5.2. mailboxHasEmail . . . . . . . . . . . . . . . . . . 81
10.5.3. blobNotFound . . . . . . . . . . . . . . . . . . . . 81
10.5.4. tooManyKeywords . . . . . . . . . . . . . . . . . . 81
10.5.5. tooManyMailboxes . . . . . . . . . . . . . . . . . . 82
10.5.6. emailNotFound . . . . . . . . . . . . . . . . . . . 82
10.5.7. emailTooLarge . . . . . . . . . . . . . . . . . . . 82
10.5.8. invalidEmail . . . . . . . . . . . . . . . . . . . . 82
10.5.9. tooManyRecipients . . . . . . . . . . . . . . . . . 83
10.5.10. noRecipients . . . . . . . . . . . . . . . . . . . . 83
10.5.11. invalidRecipients . . . . . . . . . . . . . . . . . 83
10.5.12. forbiddenMailFrom . . . . . . . . . . . . . . . . . 83
10.5.13. forbiddenFrom . . . . . . . . . . . . . . . . . . . 83
10.5.14. forbiddenToSend . . . . . . . . . . . . . . . . . . 84
11. References . . . . . . . . . . . . . . . . . . . . . . . . . 84
11.1. Normative References . . . . . . . . . . . . . . . . . . 84
11.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 87
1. Introduction 1. Introduction
JMAP <https://tools.ietf.org/html/draft-ietf-jmap-core-05> is a JMAP <https://tools.ietf.org/html/draft-ietf-jmap-core-05> is a
generic protocol for synchronising data, such as mail, calendars or generic protocol for synchronising data, such as mail, calendars or
contacts, between a client and a server. It is optimised for mobile contacts, between a client and a server. It is optimised for mobile
and web environments, and aims to provide a consistent interface to and web environments, and aims to provide a consistent interface to
different data types. different data types.
This specification defines a data model for synchronising mail This specification defines a data model for synchronising mail
skipping to change at page 4, line 5 skipping to change at page 4, line 29
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC2119]. document are to be interpreted as described in [RFC2119].
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
<https://tools.ietf.org/html/draft-ietf-jmap-core-05>. <https://tools.ietf.org/html/draft-ietf-jmap-core-05>.
Object properties may also have a set of attributes defined along Object properties may also have a set of attributes defined along
with the type signature. These have the following meanings: with the type signature. These have the following meanings:
o *sever-set*: Only the server can set the value for this property. o *server-set*: Only the server can set the value for this property.
The client MUST NOT send this property when creating a new object The client MUST NOT send this property when creating a new object
of this type. of this type.
o *immutable*: The value MUST NOT change after the object is o *immutable*: The value MUST NOT change after the object is
created. created.
o *default*: (This is followed by a JSON value). The value that o *default*: (This is followed by a JSON value). The value that
will be used for this property if it is omitted in an argument, or will be used for this property if it is omitted in an argument, or
when creating a new object of this type. when creating a new object of this type.
1.2. The Date data types Data types defined in the core specification are used in this
document.
Where "Date" is given as a type, it means a string in [RFC3339]
_date-time_ format. To ensure a normalised form, the _time-secfrac_
MUST always be omitted and any letters in the string (e.g. "T" and
"Z") MUST be upper-case. For example, ""2014-10-30T14:12:00+08:00"".
Where "UTCDate" is given as a type, it means a "Date" where the
_time-offset_ component MUST be "Z" (i.e. it must be in UTC time).
For example, ""2014-10-30T06:12:00Z"".
1.3. 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.4. Addition 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 standard JMAP
Session object; see the JMAP spec. Servers supporting _this_ Session object; see the JMAP Core specification.
specification MUST add a property called "urn:ietf:params:jmap:mail"
to the capabilities object. The value of this property is an object
which MUST contain the following information on server capabilities:
o *maxMailboxesPerEmail*: "Number|null" The maximum number of This document defines three additional capability objects.
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 is an object which MUST contain the following
information on server capabilities:
o *maxMailboxesPerEmail*: "PositiveInt|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 *maxSizeAttachmentsPerEmail*: "Number" The maximum total size of o *maxSizeAttachmentsPerEmail*: "PositiveInt" The maximum total size
attachments, in octets, allowed for a single email. A server MAY of attachments, in octets, allowed for a single email. A server
still reject emails with a lower attachment size total (for MAY still reject import or creation of emails with a lower
example, if the body includes several megabytes of text, causing attachment size total (for example, if the body includes several
the size of the encoded MIME structure to be over some server- megabytes of text, causing the size of the encoded MIME structure
defined limit). Note, this limit is for the sum of unencoded to be over some server-defined limit). Note, this limit is for
attachment sizes. Users are generally not knowledgeable about the sum of unencoded attachment sizes. Users are generally not
encoding overhead etc., nor should they need to be, so services knowledgeable about encoding overhead etc., nor should they need
marketing and help materials normally tells them the "max size to be, so services marketing and help materials normally tells
attachments". This is the unencoded size they see on their hard them the "max size attachments". This is the unencoded size they
drive, and so this capability matches that and allows the client see on their hard drive, and so this capability matches that and
to consistently enforce what the user understands as the limit. allows the client to consistently enforce what the user
The server may separately have a limit for the total size of the understands as the limit. The server may separately have a limit
RFC5322 message, which will have attachments Base64 encoded and for the total size of the RFC5322 message, which will have
message headers and bodies too. For example, suppose the server attachments Base64 encoded and message headers and bodies too.
advertises "maxSizeAttachmentsPerEmail: 50000000" (50 MB). The For example, suppose the server advertises
enforced server limit may be for an RFC5322 size of 70000000 "maxSizeAttachmentsPerEmail: 50000000" (50 MB). The enforced
octets (70 MB). Even with Base64 encoding and a 2 MB HTML body, server limit may be for an RFC5322 size of 70000000 octets (70
50 MB attachments would fit under this limit. MB). Even with Base64 encoding and a 2 MB HTML body, 50 MB
attachments would fit under this limit.
o *maxDelayedSend*: "Number" The number in seconds of the maximum
delay the server supports in sending (see the EmailSubmission
object). This is "0" if the server does not support delayed send.
o *emailsListSortOptions*: "String[]" A list of all the email o *emailsListSortOptions*: "String[]" A list of all the email
properties the server supports for sorting by. This MAY include properties the server supports for sorting by. This MAY include
properties the client does not recognise (for example custom properties the client does not recognise (for example custom
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
This represents support for the Identity and MessageSubmission data
types and associated API methods. The value of this property is an
object which MUST contain the following information on server
capabilities:
o *maxDelayedSend*: "PositiveInt" 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[]]" 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 show only known safe- changes. By default, the JMAP server should show only known safe-
to-expose EHLO capabilities in this field, and hide EHLO to-expose EHLO capabilities in this field, and hide EHLO
capabilities that are only relevant to the JMAP server. Each key capabilities that are only relevant to the JMAP server. Each key
in the object is the _ehlo-name_, and the value is a list of in the object is the _ehlo-name_, and the value is a list of
_ehlo-args_. Examples of safe-to-expose Submission extensions _ehlo-args_. Examples of safe-to-expose Submission extensions
skipping to change at page 6, line 7 skipping to change at page 6, line 39
* MT-PRIORITY ([RFC6710]) * MT-PRIORITY ([RFC6710])
A JMAP server MAY advertise an extension and implement the A JMAP server MAY advertise an extension and implement the
semantics of that extension locally on the JMAP server even if a semantics of that extension locally on the JMAP server even if a
submission server used by JMAP doesn't implement it. The full submission server used by JMAP doesn't implement it. The full
IANA registry of submission extensions can be found at IANA registry of submission extensions can be found at
<https://www.iana.org/assignments/mail-parameters/mail- <https://www.iana.org/assignments/mail-parameters/mail-
parameters.xhtml#mail-parameters-2> parameters.xhtml#mail-parameters-2>
The server MUST also include the string "urn:ietf:params:jmap:mail" 1.3.3. urn:ietf:params:jmap:vacationresponse
in the _hasDataFor_ property of any account in which the user may use
the data types contained in this specification. This represents support for the VacationResponse data type and
associated API methods. The value of this property is an empty
object.
1.4. Data type support in different accounts
The server MUST include the appropriate capability strings in the
_hasDataFor_ property of any account in which the user may use the
data types represented by that URN. 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/
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 standard JMAP push mechanisms to receive
notifications when the state changes for any of the types defined in notifications when the state changes for any of the types defined in
this specification. this specification.
In addition, servers MUST support a psuedo-type called In addition, servers MUST support a psuedo-type called
"EmailDelivery" in the push mechanisms. The state string for this "EmailDelivery" in the push mechanisms. 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
skipping to change at page 6, line 48 skipping to change at page 7, line 46
o *id*: "String" (immutable; server-set) The id of the mailbox. o *id*: "String" (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 may be any Net-Unicode string ([RFC5198]) of at least 1
character in length and maximum 255 octets in size. Servers MUST character in length and maximum 255 octets in size. Servers MUST
forbid sibling Mailboxes with the same name. Servers MAY reject forbid sibling Mailboxes with the same name. Servers MAY reject
names that violate server policy (e.g., names containing slash (/) names that violate server policy (e.g., names containing slash (/)
or control characters). or control characters).
o *parentId*: "String|null" (default: "null") The mailbox id for the o *parentId*: "String|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 may only have a single role,
and no two mailboxes in the same account may have the same role. and no two mailboxes in the same account may have the same role.
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 Mailbox Name Attributes Registry [1], as established in IANA Mailbox Name Attributes Registry [1], as established in
[TODO:being established in EXTRA], converted to lower-case. New [TODO:being established in EXTRA], converted to lower-case. New
roles may be established here in the future. An account is not roles may be established here in the future. An account is not
required to have mailboxes with any particular roles. required to have mailboxes with any particular roles.
o *sortOrder*: "Number" (default: "0") Defines the sort order of o *sortOrder*: "PositiveInt" (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*: "Number" (server-set) The number of emails in this o *totalEmails*: "PositiveInt" (server-set) The number of emails in
mailbox. this mailbox.
o *unreadEmails*: "Number" (server-set) The number of emails in this o *unreadEmails*: "PositiveInt" (server-set) The number of emails in
mailbox that have neither the "$seen" keyword nor the "$draft" this mailbox that have neither the "$seen" keyword nor the
keyword. "$draft" keyword.
o *totalThreads*: "Number" (server-set) The number of threads where o *totalThreads*: "PositiveInt" (server-set) The number of threads
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*: "Number" (server-set) The number of threads where o *unreadThreads*: "PositiveInt" (server-set) The number of threads
at least one email in the thread has neither the "$seen" keyword 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 keyword nor the "$draft" keyword AND at least one email in the
in this mailbox (but see below for special case handling of thread is in this mailbox (but see below for special case handling
Trash). Note, the unread email does not need to be the one in of Trash). Note, the unread email does not need to be the one in
this mailbox. this mailbox.
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. A _MailboxRights_ the user has in relation to this mailbox. A _MailboxRights_
object has the following properties: 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. If a sub-mailbox is shared but not the parent
skipping to change at page 9, line 35 skipping to change at page 10, line 35
For IMAP compatibility, an email in both the Trash and another For IMAP compatibility, an email in both the Trash and another
mailbox SHOULD be treated by the client as existing in both places mailbox SHOULD be treated by the client as existing in both places
(i.e. when emptying the trash, the client SHOULD just remove the (i.e. when emptying the trash, the client SHOULD just remove the
Trash mailbox and leave it in the other mailbox). Trash mailbox and leave it in the other mailbox).
The following JMAP methods are supported: The following JMAP methods are supported:
2.1. Mailbox/get 2.1. Mailbox/get
Standard _/get_ method. The _ids_ argument may be "null" to fetch Standard "/get" method. The _ids_ argument may be "null" to fetch
all at once. all at once.
2.2. Mailbox/changes 2.2. Mailbox/changes
Standard _/changes_ method, but with one extra argument to the Standard "/changes" method, but with one extra argument to the
response: response:
o *changedProperties*: "String[]|null" If only the mailbox counts o *updatedProperties*: "String[]|null" If only the mailbox counts
(unread/total emails/threads) have changed since the old state, (unread/total emails/threads) have changed since the old state,
this will be the list of properties that may have changed, i.e. this will be the list of properties that may have changed, i.e.
"["totalEmails", "unreadEmails", "totalThreads", "["totalEmails", "unreadEmails", "totalThreads",
"unreadThreads"]". If the server is unable to tell if only counts "unreadThreads"]". If the server is unable to tell if only counts
have changed, it MUST just be "null". have changed, it MUST just be "null".
Since counts frequently change but the rest of the mailboxes state Since counts frequently change but the rest of the mailboxes state
for most use cases changes rarely, the server can help the client for most use cases changes rarely, the server can help the client
optimise data transfer by keeping track of changes to email/thread optimise data transfer by keeping track of changes to email/thread
counts separately to other state changes. The _changedProperties_ counts separately to other state changes. The _updatedProperties_
array may be used directly via a result reference in a subsequent array may be used directly via a result reference in a subsequent
Mailbox/get call in a single request. Mailbox/get call in a single request.
2.3. Mailbox/query 2.3. Mailbox/query
Standard _/query_ method. Standard "/query" method.
A *FilterCondition* object has the following properties, any of which A *FilterCondition* object has the following properties, any of which
may be omitted: may be omitted:
o *parentId*: "String|null" The Mailbox _parentId_ property must o *parentId*: "String|null" The Mailbox _parentId_ property must
match the given value exactly. match the given value exactly.
o *hasRole*: "Boolean" If this is "true", a Mailbox matches if it o *name*: "String" The Mailbox _name_ property contains the given
has a non-"null" value for its _role_ property. If "false", it string.
must has a "null" _role_ value to match.
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 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 filter if and only if all of the given
conditions given match. If zero properties are specified, it is conditions given 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:
skipping to change at page 10, line 44 skipping to change at page 11, line 49
o "name" o "name"
o "parent/name": This is a pseudo-property, just for sorting, with o "parent/name": This is a pseudo-property, just for sorting, with
the following semantics: if two mailboxes have a common parent, the following semantics: if two mailboxes have a common parent,
sort them by name. Otherwise, find the nearest ancestors of each sort them by name. Otherwise, find the nearest ancestors of each
that share a common parent and sort by their names instead. (i.e. that share a common parent and sort by their names instead. (i.e.
This sorts the mailbox list in tree order). This sorts the mailbox list in tree order).
2.4. Mailbox/queryChanges 2.4. Mailbox/queryChanges
Standard _/queryChanges_ method. Standard "/queryChanges" method.
2.5. Mailbox/set 2.5. Mailbox/set
Standard _/set_ method, but with the following additional argument: Standard "/set" method, but with the following additional argument:
o *onDestroyRemoveMessages*: "Boolean" (default: "false") If o *onDestroyRemoveMessages*: "Boolean" (default: false) If "false",
"false", attempts to destroy a mailbox that still has any messages attempts to destroy a mailbox that still has any messages in it
in it will be rejected with a "mailboxHasEmail" SetError. If will be rejected with a "mailboxHasEmail" SetError. If "true",
"true", any messages that were in the mailbox will be removed from any messages that were in the mailbox will be removed from it, and
it, and if in no other mailboxes will be destroyed when the if in no other mailboxes will be destroyed when the mailbox is
mailbox is destroyed. destroyed.
The following extra _SetError_ types are defined: The following extra _SetError_ types are defined:
For *destroy*: For *destroy*:
o "mailboxHasChild": The mailbox still has at least one child o "mailboxHasChild": The mailbox still has at least one child
mailbox. The client MUST remove these before it can delete the mailbox. The client MUST remove these before it can delete the
parent mailbox. parent mailbox.
o "mailboxHasEmail": The mailbox has at least one message assigned o "mailboxHasEmail": The mailbox has at least one message assigned
to it and the _onDestroyRemoveMessages_ argument was "false". to it and the _onDestroyRemoveMessages_ argument was "false".
2.6. Example 2.6. Example
Fetching all mailboxes in an account: Fetching all mailboxes in an account:
[ [[ "Mailbox/get", {
"Mailbox/get", "accountId": "u33084183",
{ "ids": null
"accountId": "u33084183", }, "0" ]]
"ids": null
},
"0"
]
And response: And response:
[ "Mailbox/get", [[ "Mailbox/get", {
{ "accountId": "u33084183",
"accountId": "u33084183", "state": "78540",
"state": "78540", "list": [
"list": [ {
{ "id": "23cfa8094c0f41e6",
"id": "23cfa8094c0f41e6", "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": "674cc24095db49ce", "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",
{ "sinceState": "78540"
"accountId": "u33084183", }, "0" ],
"sinceState": "78540" [ "Mailbox/get", {
}, "accountId": "u33084183",
"0" "#ids": {
], "resultOf": "0",
[ "name": "Mailbox/changes",
"Mailbox/get", "path": "/created"
{ }
"accountId": "u33084183", }, "1" ],
"#ids": { [ "Mailbox/get", {
"resultOf": "0", "accountId": "u33084183",
"name": "Mailbox/changes", "#ids": {
"path": "/created" "resultOf": "0",
} "name": "Mailbox/changes",
}, "path": "/updated"
"1" },
], "#properties": {
[ "resultOf": "0",
"Mailbox/get", "name": "Mailbox/changes",
{ "path": "/updatedProperties"
"accountId": "u33084183", }
"#ids": { }, "2" ]]
"resultOf": "0",
"name": "Mailbox/changes",
"path": "/updated"
},
"#properties": {
"resultOf": "0",
"name": "Mailbox/changes",
"path": "/changedProperties"
}
},
"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",
{ "oldState": "78541",
"accountId": "u33084183", "newState": "78542",
"oldState": "78541", "hasMoreChanges": false,
"newState": "78542", "updatedProperties": [
"hasMoreChanges": false, "totalEmails", "unreadEmails",
"changedProperties": [ "totalThreads", "unreadThreads"
"totalEmails", "unreadEmails", ],
"totalThreads", "unreadThreads" "created": [],
], "updated": ["23cfa8094c0f41e6"],
"created": [], "destroyed": []
"updated": ["23cfa8094c0f41e6"], }, "0" ],
"destroyed": [] [ "Mailbox/get", {
}, "accountId": "u33084183",
"0" "state": "78542",
], "list": [],
["Mailbox/get", { "notFound": []
"accountId": "u33084183", }, "1" ],
"state": "78542", [ "Mailbox/get", {
"list": [], "accountId": "u33084183",
"notFound": [] "state": "78542",
}, "1"], "list": [{
["Mailbox/get", { "id": "23cfa8094c0f41e6",
"accountId": "u33084183", "totalEmails": 16307,
"state": "78542", "unreadEmails": 13903,
"list": [{ "totalThreads": 5833,
"id": "23cfa8094c0f41e6", "unreadThreads": 5127
"totalEmails": 16307, }],
"unreadEmails": 13903, "notFound": []
"totalThreads": 5833, }, "2" ]]
"unreadThreads": 5127
}],
"notFound": []
}, "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",
{ "ifInState": "78542",
"accountId": "u33084183", "update": {
"ifInState": "78542", "674cc24095db49ce": {
"update": { "name": "Maybe important mail"
"674cc24095db49ce": { }
"name": "Maybe important mail" },
} "destroy": [ "23cfa8094c0f41e6" ]
}, }, "0" ]]
"destroy": [ "23cfa8094c0f41e6" ]
},
"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",
{ "oldState": "78542",
"accountId": "u33084183", "newState": "78549",
"oldState": "78542", "created": null,
"newState": "78549", "notCreated": null,
"created": null, "updated": {
"notCreated": null, "674cc24095db49ce": null
"updated": { },
"674cc24095db49ce": null "notUpdated": null,
}, "destroyed": null,
"notUpdated": null, "notDestroyed": {
"destroyed": null, "23cfa8094c0f41e6": {
"notDestroyed": { "type": "forbidden"
"23cfa8094c0f41e6": { }
"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 16, line 35 skipping to change at page 17, line 12
into a single thread. Since the _threadId_ of an email is immutable, 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 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 deleting and reinserting (with a new email id) the emails that change
threadId. threadId.
A *Thread* object has the following properties: A *Thread* object has the following properties:
o *id*: "String" (immutable) The id of the thread. o *id*: "String" (immutable) The id of the thread.
o *emailIds*: "String[]" The ids of the emails in the thread, sorted o *emailIds*: "String[]" The ids of the emails in the thread, sorted
such that: by the _receivedAt_ date of the email, oldest first. If two
emails have an identical date, the sort is server-dependent but
* Any email with the "$draft" keyword that has an "In-Reply-To" MUST be stable (sorting by id is recommended).
header is sorted after the _first_ non-draft email in the
thread with the corresponding "Message-Id" header, but before
any subsequent non-draft emails.
* Other than that, everything is sorted by the _receivedAt_ date
of the email, oldest first.
* If two emails are identical under the above two conditions, the
sort is server-dependent but MUST be stable (sorting by id is
recommended).
The following JMAP methods are supported: The following JMAP methods are supported:
3.1. Thread/get 3.1. Thread/get
Standard _/get_ method. Standard "/get" method.
3.1.1. Example 3.1.1. Example
Request: Request:
[ "Thread/get", { [[ "Thread/get", {
"ids": ["f123u4", "f41u44"], "ids": ["f123u4", "f41u44"],
}, "#1" ] }, "#1" ]]
with response: with response:
[ "Thread/get", { [[ "Thread/get", {
"accountId": "acme", "accountId": "acme",
"state": "f6a7e214", "state": "f6a7e214",
"list": [ "list": [
{ {
"id": "f123u4", "id": "f123u4",
"emailIds": [ "eaa623", "f782cbb"] "emailIds": [ "eaa623", "f782cbb"]
}, },
{ {
"id": "f41u44", "id": "f41u44",
"emailIds": [ "82cf7bb" ] "emailIds": [ "82cf7bb" ]
} }
], ],
"notFound": [] "notFound": []
}, "#1" ] }, "#1" ]]
3.2. Thread/changes 3.2. Thread/changes
Standard _/changes_ method. Standard "/changes" method.
4. Emails 4. Emails
The *Email* object is a representation of an [RFC5322] message, which The *Email* object is a representation of an [RFC5322] message, which
allows clients to avoid the complexities of MIME parsing, transport allows clients to avoid the complexities of MIME parsing, transport
encoding and character encoding. encoding and character encoding.
4.1. Properties of the Email object 4.1. Properties of the Email object
Broadly, a message consists of two parts: a list of header fields, Broadly, a message consists of two parts: a list of header fields,
skipping to change at page 19, line 31 skipping to change at page 19, line 48
o *threadId*: "String" (immutable; server-set) The id of the Thread o *threadId*: "String" (immutable; server-set) The id of the Thread
to which this Email belongs. to which this Email belongs.
o *mailboxIds*: "String[Boolean]" The set of mailbox ids this email o *mailboxIds*: "String[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 o *keywords*: "String[Boolean]" (default: ) A set of keywords that
that apply to the email. The set is represented as an object, apply to the email. The set is represented as an object, with the
with the keys being the _keywords_. The value for each key in the keys being the _keywords_. The value for each key in the object
object MUST be "true". Keywords are shared with IMAP. The six MUST be "true". Keywords are shared with IMAP. The six system
system keywords from IMAP are treated specially. The following keywords from IMAP are treated specially. The following four
four keywords have their first character changed from "\" in IMAP keywords have their first character changed from "\" in IMAP to
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.
* "$flagged": The email has been flagged for urgent/special * "$flagged": The email has been flagged for urgent/special
attention. attention.
* "$answered": The email has been replied to. * "$answered": The email has been replied to.
skipping to change at page 20, line 26 skipping to change at page 20, line 43
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*: "Number" (immutable; server-set) The size, in octets, of o *size*: "PositiveInt" (immutable; server-set) The size, in octets,
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. This is the _internal date_ in IMAP.
4.1.2. Header fields 4.1.2. Header fields parsed forms
These properties are derived from the [RFC5322] and [RFC6532] message Header field properties are derived from the [RFC5322] and [RFC6532]
header fields. All header fields may be fetched in a raw form. Some message header fields. All header fields may be fetched in a raw
headers may also be fetched in a parsed form. The structured form form. Some headers may also be fetched in a parsed form. The
that may be fetched depends on the header. The following forms are structured form that may be fetched depends on the header. The
defined: following forms are defined:
o *Raw* ("String") The raw octets of the header field value from the 4.1.2.1. Raw
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 (RFC5322) or
UTF-8 (RFC6532), however other encodings exist in the wild. A
server MAY use heuristics to determine a charset and decode the
octets, or MAY 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.
o *Text* ("String") The header field value with: Type: "String"
1. White space unfolded (as defined in [RFC5322] section 2.2.3) 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 (RFC5322) or UTF-8 (RFC6532), however
other encodings exist in the wild. A server MAY use heuristics to
determine a charset and decode the octets, or MAY 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.
2. The terminating CRLF at the end of the value removed 4.1.2.2. Text
3. Any SP characters at the beginning of the value removed Type: "String"
4. Any syntactically correct [RFC2047] encoded sections with a The header field value with:
known character set decoded. Any [RFC2047] encoded NUL octets
or control characters are dropped from the decoded value. Any
text that looks like [RFC2047] syntax but violates [RFC2047]
placement or whitespace rules MUST NOT be decoded.
5. Any [RFC6532] UTF-8 values decoded. 1. White space unfolded (as defined in [RFC5322] section 2.2.3)
6. The resulting unicode converted to NFC form. 2. The terminating CRLF at the end of the value removed
If any decodings fail, the parser SHOULD insert a unicode 3. Any SP characters at the beginning of the value removed
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:
* Subject 4. Any syntactically correct [RFC2047] encoded sections with a known
character set decoded. Any [RFC2047] encoded NUL octets or
control characters are dropped from the decoded value. Any text
that looks like [RFC2047] syntax but violates [RFC2047] placement
or whitespace rules MUST NOT be decoded.
* Comment 5. Any [RFC6532] UTF-8 values decoded.
* List-Id 6. The resulting unicode converted to NFC form.
* Any header not defined in [RFC5322] or [RFC2369] If any decodings fail, the parser SHOULD insert a unicode replacement
character (U+FFFD) and attempt to continue as much as possible.
o *Addresses* ("EmailAddress[]") The header is parsed as an To prevent obviously nonsense behaviour, which can lead to
"address-list" value, as specified in [RFC5322] section 3.4, into interoperability issues, this form may only be fetched or set for the
the "EmailAddress[]" type. The *EmailAddress* object has the following header fields:
following properties:
* *name*: "String|null" The _display-name_ of the [RFC5322] o Subject
_mailbox_ or _group_, or "null" if none. If this is a _quoted-
string_:
1. The surrounding DQUOTE characters are removed. o Comment
2. Any _quoted-pair_ is decoded. o List-Id
3. White-space is unfolded, and then any leading or trailing o Any header not defined in [RFC5322] or [RFC2369]
white-space is removed.
* *email*: "String|null" The _addr-spec_ of the [RFC5322] 4.1.2.3. Addresses
_mailbox_, or "null" if a _group_.
Any syntactically correct [RFC2047] encoded sections with a known Type: "EmailAddress[]"
encoding MUST be decoded, following the same rules as for the
_Text_ form. Any [RFC6532] UTF-8 values MUST be decoded. 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). To prevent obviously nonsense behaviour, which can lead
to interoperability issues, this form may only be fetched or set
for the following header fields:
* From The header 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.
* Sender The *EmailAddress* object has the following properties:
* Reply-To o *name*: "String|null" The _display-name_ of the [RFC5322]
_mailbox_, or "null" if none. If this is a _quoted-string_:
* To 1. The surrounding DQUOTE characters are removed.
* Cc 2. Any _quoted-pair_ is decoded.
* Bcc 3. White-space is unfolded, and then any leading and trailing
white-space is removed.
* Resent-From o *email*: "String" The _addr-spec_ of the [RFC5322] _mailbox_.
* Resent-Sender Any syntactically correct [RFC2047] encoded sections with a known
encoding MUST be decoded, following the same rules as for the _Text_
form. Any [RFC6532] UTF-8 values MUST be decoded.
* Resent-Reply-To 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).
* Resent-To For example, the following "address-list" string:
* Resent-Cc " James Smythe" <james@example.com>, Friends: jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= <john@example.com>;
would be parsed as:
* Resent-Bcc [
{ "name": "James Smythe", "email": "james@example.com" },
{ "name": null, "email": "jane@example.com" },
{ "name": "John Smith", "email": "john@example.com" },
]
* Any header not defined in [RFC5322] or [RFC2369] 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 *MessageIds* ("String[]|null") The header is parsed as a list of o From
"msg-id" values, as specified in [RFC5322] section 3.6.4, into the
"String[]" type. 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:
* Message-ID o Sender
* In-Reply-To o Reply-To
* References o To
* Resent-Message-ID o Cc
* Any header not defined in [RFC5322] or [RFC2369] o Bcc
o *Date* ("Date|null") The header is parsed as a "date-time" value, o Resent-From
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:
* Date o Resent-Sender
* Resent-Date o Resent-Reply-To
* Any header not defined in [RFC5322] or [RFC2369] o Resent-To
o *URLs* ("String[]|null") The header is parsed as a list of URLs, o Resent-Cc
as described in [RFC2369], into the "String[]" type. Values do
not include the surrounding angle brackets or any comments in the
header 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:
* List-Help o Resent-Bcc
* List-Unsubscribe o Any header not defined in [RFC5322] or [RFC2369]
* List-Subscribe 4.1.2.4. GroupedAddresses
* List-Post Type: "EmailAddressGroup[]"
* List-Owner This is similar to the Addresses form but preserves group
information. The header is parsed as an "address-list" value, as
specified in [RFC5322] section 3.4, into the "GroupedAddresses[]"
type. Consecutive mailboxes that are not part of a group are still
collected under an EmailAddressGroup object to provide a uniform
type.
* List-Archive The *EmailAddressGroup* object has the following properties:
* Any header not defined in [RFC5322] or [RFC2369] o *name*: "String|null" The _display-name_ of the [RFC5322] _group_,
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_es that belong to this
group, represented as EmailAddress objects.
Any syntactically correct [RFC2047] encoded sections with a known
encoding MUST be decoded, following the same rules as for the _Text_
form. Any [RFC6532] UTF-8 values MUST be decoded.
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.
4.1.2.5. MessageIds
Type: "String[]|null"
The header is parsed as a list of "msg-id" values, as specified in
[RFC5322] section 3.6.4, into the "String[]" type. 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 not defined in [RFC5322] or [RFC2369]
4.1.2.6. Date
Type: "Date|null"
The header 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 not defined in [RFC5322] or [RFC2369]
4.1.2.7. URLs
Type: "String[]|null"
The header 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 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 not defined in [RFC5322] or [RFC2369]
4.1.3. Header fields properties
The following low-level *Email* property is specified for complete The following low-level *Email* property is specified for complete
access to the header data of the message: access to the header data of the message:
o *headers*: "EmailHeader[]" (immutable) This is a list of all o *headers*: "EmailHeader[]" (immutable) This is a list of all
[RFC5322] header fields, in the same order they appear in the [RFC5322] header fields, in the same order they appear in the
message. An *EmailHeader* object has the following properties: message. An *EmailHeader* object has the following properties:
* *name*: "String" The header _field name_ as defined in * *name*: "String" The header _field name_ as defined in
[RFC5322], with the same capitalization that it has in the [RFC5322], with the same capitalization that it has in the
skipping to change at page 26, line 5 skipping to change at page 28, line 21
o *replyTo*: "EmailAddress[]|null" (immutable) The value is o *replyTo*: "EmailAddress[]|null" (immutable) The value is
identical to the value of _header:Reply-To:asAddresses_. identical to the value of _header:Reply-To:asAddresses_.
o *subject*: "String|null" (immutable) The value is identical to the o *subject*: "String|null" (immutable) The value is identical to the
value of _header:Subject:asText_. value of _header:Subject:asText_.
o *sentAt*: "Date|null" (immutable; default on creation: current o *sentAt*: "Date|null" (immutable; default on creation: current
server time) The value is identical to the value of server time) The value is identical to the value of
_header:Date:asDate_. _header:Date:asDate_.
4.1.3. Body parts 4.1.4. Body parts
These properties are derived from the [RFC5322] message body and its These properties are derived from the [RFC5322] message body and its
[RFC2045] MIME entities. [RFC2045] MIME entities.
A *EmailBodyPart* object has the following properties: A *EmailBodyPart* object has the following properties:
o *partId*: "String|null" Identifies this part uniquely within the o *partId*: "String|null" Identifies this part uniquely within the
Email. This is scoped to the _emailId_ and has no meaning outside Email. This is scoped to the _emailId_ and has no meaning outside
of the JMAP Email object representation. This is "null" if, and of the JMAP Email object representation. This is "null" if, and
only if, the part is of type "multipart/*". only if, the part is of type "multipart/*".
o *blobId*: "String|null" The id representing the raw octets of the o *blobId*: "String|null" The id representing the raw octets of the
contents of the part after decoding any _Content-Transfer- contents of the part after decoding any _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 same the same blob id if transfer-encoded differently but have same the same blob id if
their decoded octets are identical and the server is using a their decoded octets are identical and the server is using a
secure hash of the data for the blob id. secure hash of the data for the blob id.
o *size*: "Number" The size, in octets, of the raw data after o *size*: "PositiveInt" 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. The values are in _Raw_ form. the part, in the order they appear. The values are 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
[RFC2047] decoded _name_ parameter of the _Content-Type_ header [RFC2047] decoded _name_ parameter of the _Content-Type_ header
field. field.
o *type*: "String" The value of the _Content-Type_ header field of o *type*: "String" The value of the _Content-Type_ header field of
the part, if present, otherwise the implicit type as per the MIME the part, if present, otherwise the implicit type as per the MIME
standard ("text/plain", or "message/rfc822" if inside a standard ("text/plain", or "message/rfc822" if inside a
"multipart/digest"). CFWS is removed and any parameters are "multipart/digest"). CFWS is removed and any parameters are
stripped. stripped.
o *charset*: "String|null" The value of the charset parameter of the o *charset*: "String|null" The value of the charset parameter of the
_Content-Type_ header field, if present, or "null" if the header _Content-Type_ header field, if present, or "null" if the header
field is present but has no charset parameter. If there is no field is present but not of type "text/*". If there is no
_Content-Type_ header field, this is the implicit charset as per _Content-Type_ header field, or it exists and is of type "text/*"
the MIME standard ("us-ascii"). 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- o *disposition*: "String|null" The value of the _Content-
Disposition_ header field of the part, if present, otherwise Disposition_ header field of the part, if present, otherwise
"null". CFWS is removed and any parameters are stripped. "null". CFWS is removed and any parameters are stripped.
o *cid*: "String|null" The value of the _Content-Id_ header field of o *cid*: "String|null" The value of the _Content-Id_ header field of
the part, if present, otherwise "null". CFWS and surrounding the part, if present, otherwise "null". CFWS and surrounding
angle brackets ("<>") are removed. This may be used to reference angle brackets ("<>") are removed. This may be used to reference
the content from within an html body part using the "cid:" the content from within an html body part using the "cid:"
protocol. protocol.
o *language*: "String[]|null" The list of language tags, as defined o *language*: "String[]|null" The list of language tags, as defined
in [RFC3282], in the _Content-Language_ header field of the part, in [RFC3282], in the _Content-Language_ header field of the part,
if present. if present.
o *location*: "String|null" The URI, as defined in [RFC2557], in the o *location*: "String|null" The URI, as defined in [RFC2557], in the
_Content-Location_ header field of the part, if present. _Content-Location_ header field of the part, if present.
o *subParts*: "EmailBodyPart[]" (optional) If type is "multipart/*", o *subParts*: "EmailBodyPart[]|null" If type is "multipart/*", this
this contains the body parts of each child. contains the body parts of each child.
In addition, the client may request/send EmailBodyPart properties In addition, the client may request/send EmailBodyPart properties
representing individual header fields, following the same syntax and representing individual header fields, following the same syntax and
semantics as for the Email object, e.g. "header:Content-Type". semantics as for the Email object, e.g. "header:Content-Type".
The following *Email* properties are specified for access to the body The following *Email* properties are specified for access to the body
data of the message: data of the message:
o *bodyStructure*: "EmailBodyPart" (immutable) This is the full MIME o *bodyStructure*: "EmailBodyPart" (immutable) This is the full MIME
structure of the message body, represented as an array of the structure of the message body, represented as an array of the
skipping to change at page 28, line 5 skipping to change at page 30, line 22
with a single LF. The server MAY use heuristics to determine with a single LF. The server MAY use heuristics to determine
the charset to use for decoding if the charset is unknown, or the charset to use for decoding if the charset is unknown, or
if no charset is given, or if it believes the charset given is if no charset is given, or if it believes the charset given is
incorrect. Decoding is best-effort and SHOULD insert the incorrect. Decoding is best-effort and SHOULD insert the
unicode replacement character (U+FFFD) and continue when a unicode replacement character (U+FFFD) and continue when a
malformed section is encountered. Note that due to the charset malformed section is encountered. Note that due to the charset
decoding and line ending normalisation, the length of this decoding and line ending normalisation, the length of this
string will probably not be exactly the same as the _size_ 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 * *isEncodingProblem*: "Boolean" (default: false) This is "true"
"true" if malformed sections were found while decoding the if malformed sections were found while decoding the charset, or
charset, or the charset was unknown. the charset was unknown.
* *isTruncated*: "Boolean" (default: "false") This is "true" if * *isTruncated*: "Boolean" (default: false) This is "true" if the
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",
"text/html", "image/*", "audio/*" and/or "video/*" parts to "text/html", "image/*", "audio/*" and/or "video/*" parts to
display (sequentially) as the message body, with a preference for display (sequentially) as the message body, with a preference for
"text/plain" when alternative versions are available. "text/plain" when alternative versions are available.
skipping to change at page 32, line 7 skipping to change at page 34, line 29
text/plain, content-disposition=inline - K text/plain, content-disposition=inline - K
In this case, the above algorithm would decompose this to: In this case, the above algorithm would decompose this to:
textBody => [ A, B, C, D, K ] textBody => [ A, B, C, D, K ]
htmlBody => [ A, E, K ] htmlBody => [ A, E, K ]
attachments => [ C, F, G, H, J ] attachments => [ C, F, G, H, J ]
4.2. Email/get 4.2. Email/get
Standard _/get_ method, with the following additional arguments: Standard "/get" method, with the following additional arguments:
o *bodyProperties*: "String[]" (optional) A list of properties to o *bodyProperties*: "String[]" A list of properties to fetch for
fetch for each EmailBodyPart returned. If omitted, this defaults each EmailBodyPart returned. If omitted, this defaults to:
to: [ "partId", "blobId", "size", "name", "type", "charset",
"disposition", cid", "language", "location" ]
o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the [ "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" _bodyValues_ property includes any "text/*" part in the "textBody"
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*: "Number" (optional) If supplied by the o *maxBodyValueBytes*: "PositiveInt" (default: 0) If greater than
client, the value MUST be a positive integer greater than 0. If a zero, the _value_ property of any EmailBodyValue object returned
value outside of this range is given, the server MUST reject the in _bodyValues_ MUST be truncated if necessary so it does not
call with an "invalidArguments" error. When given, the _value_ exceed this number of octets in size. If "0" (the default), no
property of any EmailBodyValue object returned in _bodyValues_ truncation occurs. The server MUST ensure the truncation results
MUST be truncated if necessary so it does not exceed this number
of octets in size. 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">". There 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 is no requirement for the truncated form to be a balanced tree or
valid HTML (indeed, the original source may well be neither of valid HTML (indeed, the original source may well be neither of
these things). these things).
If the standard _properties_ argument is omitted or "null", the If the standard _properties_ argument is omitted or "null", the
following default MUST be used instead of "all" properties: following default MUST be used instead of "all" properties:
skipping to change at page 34, line 9 skipping to change at page 36, line 29
being rejected with an "invalidArguments" error. being rejected with an "invalidArguments" error.
Where a specific header is requested as a property, the Where a specific header is requested as a property, the
capitalization of the property name in the response MUST be identical capitalization of the property name in the response MUST be identical
to that used in the request. to that used in the request.
4.2.1. Example 4.2.1. Example
Request: Request:
["Email/get", { [ "Email/get", {
"ids": [ "f123u456", "f123u457" ], "ids": [ "f123u456", "f123u457" ],
"properties": [ "threadId", "mailboxIds", "from", "subject", "receivedAt", "header:List-POST:asURLs" "htmlBody", "bodyValues" ], "properties": [ "threadId", "mailboxIds", "from", "subject", "receivedAt", "header:List-POST:asURLs", "htmlBody", "bodyValues" ],
"bodyProperties": [ "partId", "blobId", "size", "type" ], "bodyProperties": [ "partId", "blobId", "size", "type" ],
"fetchHTMLBodyValues": true, "fetchHTMLBodyValues": true,
"maxBodyValueBytes": 256 "maxBodyValueBytes": 256
}, "#1"] }, "#1" ]
and response: and response:
["Email/get", { [ "Email/get", {
"accountId": "abc", "accountId": "abc",
"state": "41234123231", "state": "41234123231",
"list": [ "list": [
{ {
"id": "f123u457", "id": "f123u457",
"threadId": "ef1314a", "threadId": "ef1314a",
"mailboxIds": { "f123": true }, "mailboxIds": { "f123": true },
"from": [{name: "Joe Bloggs", email: "joe@bloggs.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": [ "mailto:partytime@lists.example.com" ], "header:List-POST:asURLs": [ "mailto:partytime@lists.example.com" ],
"htmlBody": [{ "htmlBody": [{
"partId": "1", "partId": "1",
"blobId": "841623871", "blobId": "841623871",
"size": 283331, "size": 283331,
"type": "text/html" "type": "text/html"
}, { }, {
"partId": "2", "partId": "2",
skipping to change at page 35, line 43 skipping to change at page 37, line 43
}, },
"2": { "2": {
"isEncodingProblem": false, "isEncodingProblem": false,
"isTruncated": false, "isTruncated": false,
"value": "-- \nSent by your friendly mailing list ..." "value": "-- \nSent by your friendly mailing list ..."
} }
} }
} }
], ],
notFound: [ "f123u456" ] notFound: [ "f123u456" ]
}, "#1"] }, "#1" ]
4.3. Email/changes 4.3. Email/changes
Standard _/changes_ method. Standard "/changes" method. If generating intermediate states for a
large set of changes, it is recommended that newer changes are
returned first, as these are generally of more interest to users.
4.4. Email/query 4.4. Email/query
Standard _/query_ method, but with the following additional Standard "/query" method, but with the following additional
arguments: arguments:
o *collapseThreads*: "Boolean" (default: "false") If "true", emails o *collapseThreads*: "Boolean" (default: false) If "true", emails in
in the same thread as a previous email in the list (given the the same thread as a previous email in the list (given the filter
filter and sort order) will be removed from the list. This means and sort order) will be removed from the list. This means at most
at most only one email will be included in the list for any given only one email will be included in the list for any given thread.
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.
4.4.1. Filtering 4.4.1. Filtering
A *FilterCondition* object has the following properties, any of which A *FilterCondition* object has the following properties, any of which
may be omitted: may be omitted:
o *inMailbox*: "String" A mailbox id. An email must be in this o *inMailbox*: "String" A mailbox id. An email must be in this
mailbox to match the condition. mailbox to match the condition.
o *inMailboxOtherThan*: "String[]" A list of mailbox ids. An email o *inMailboxOtherThan*: "String[]" A list of mailbox ids. An email
must be in at least one mailbox not in this list to match the 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 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 of the email must be o *before*: "UTCDate" The _receivedAt_ date of the email must be
before this date to match the condition. before this date to match the condition.
o *after*: "UTCDate" The _receivedAt_ date of the email must be on o *after*: "UTCDate" The _receivedAt_ date of the email must be on
or after this date to match the condition. or after this date to match the condition.
o *minSize*: "Number" The _size_ of the email in octets must be o *minSize*: "PositiveInt" 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*: "Number" The size of the email in octets must be less o *maxSize*: "PositiveInt" The size of the email in octets must be
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.
o *noneInThreadHaveKeyword*: "String" All emails (including this o *noneInThreadHaveKeyword*: "String" All emails (including this
skipping to change at page 37, line 35 skipping to change at page 39, line 39
o *cc*: "String" Looks for the text in the _Cc_ header field of the o *cc*: "String" Looks for the text in the _Cc_ header field of the
message. message.
o *bcc*: "String" Looks for the text in the _Bcc_ header field of o *bcc*: "String" Looks for the text in the _Bcc_ header field of
the message. the message.
o *subject*: "String" Looks for the text in the _subject_ property o *subject*: "String" Looks for the text in the _subject_ property
of the email. of the email.
o *body*: "String" Looks for the text in one of the "text/*" body o *body*: "String" Looks for the text in one of the body parts of
parts of the email. the email. The server MAY exclude MIME body parts with content
media types other than "text/_" and "message/_" from consideration
o *attachments*: "String" Looks for the text in the attachments of in search matching. Care should be taken to match based on the
the email. Servers MAY handle text extraction when possible for text content actually presented to an end-user by viewers for that
the different kinds of media. 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 o *header*: "String[]" The array MUST contain either one or two
elements. The first element is the name of the header field to elements. The first element is the name of the header field to
match against. The second (optional) element is the text to look match against. The second (optional) element is the text to look
for in the header field value. If not supplied, the message for in the header field value. If not supplied, the message
matches simply if it _has_ a header field of the given name. matches simply if it _has_ a header field of the given name.
If zero properties are specified on the FilterCondition, the If zero properties are specified on the FilterCondition, the
condition MUST always evaluate to "true". If multiple properties are condition MUST always evaluate to "true". If multiple properties are
specified, ALL must apply for the condition to be "true" (it is specified, ALL must apply for the condition to be "true" (it is
skipping to change at page 39, line 13 skipping to change at page 41, line 21
"null"/empty then the "email" part, of the *first* EmailAddress "null"/empty then the "email" part, of the *first* EmailAddress
object in the _to_ property. If still none, consider the value to object in the _to_ property. If still none, consider the value to
be the empty string. be the empty string.
o *subject* - This is taken to be the base subject of the email, as o *subject* - This is taken to be the base subject of the email, as
defined in section 2.1 of [RFC5256]. defined in section 2.1 of [RFC5256].
o *sentAt* - The _sentAt_ property on the Email object. o *sentAt* - The _sentAt_ property on the Email object.
o *hasKeyword* - This value MUST be considered "true" if the email o *hasKeyword* - This value MUST be considered "true" if the email
has the keyword given as the _keyword_ property on this has the keyword given as an additional _keyword_ property on the
_Comparator_ object, or "false" otherwise. _Comparator_ object, or "false" otherwise.
o *allInThreadHaveKeyword* - This value MUST be considered "true" o *allInThreadHaveKeyword* - This value MUST be considered "true"
for the email if *all* of the emails in the same thread for the email if *all* of the emails in the same thread
(regardless of mailbox) have the keyword given as the _keyword_ (regardless of mailbox) have the keyword given as an additional
property on this _Comparator_ object. _keyword_ property on the _Comparator_ object.
o *someInThreadHaveKeyword* - This value MUST be considered "true" o *someInThreadHaveKeyword* - This value MUST be considered "true"
for the email if *any* of the emails in the same thread for the email if *any* of the emails in the same thread
(regardless of mailbox) have the keyword given as the _keyword_ (regardless of mailbox) have the keyword given as an additional
property on this _Comparator_ object. _keyword_ property on the _Comparator_ object.
The server MAY support sorting based on other properties as well. A The server MAY support sorting based on other properties as well. A
client can discover which properties are supported by inspecting the client can discover which properties are supported by inspecting the
server's _capabilities_ object (see section 1). server's _capabilities_ object (see section 1).
Example sort: Example sort:
[{ [{
"property": "someInThreadHaveKeyword", "property": "someInThreadHaveKeyword",
"keyword": "$flagged", "keyword": "$flagged",
skipping to change at page 40, line 7 skipping to change at page 42, line 13
}] }]
This would sort emails in flagged threads first (the thread is This would sort emails in flagged threads first (the thread is
considered flagged if any email within it is flagged), and then in considered flagged if any email within it is flagged), and then in
subject order, then newest first for messages with the same subject. subject order, then newest first for messages with the same subject.
If two emails have both identical flagged status, subject and date, If two emails have both identical flagged status, subject and date,
the order is server-dependent but must be stable. the order is server-dependent but must be stable.
4.4.3. Thread collapsing 4.4.3. Thread collapsing
When "collapseThreads == true", then after filtering and sorting the When _collapseThreads_ is "true", then after filtering and sorting
email list, the list is further winnowed by removing any emails for a the email list, the list is further winnowed by removing any emails
thread id that has already been seen (when passing through the list for a thread id that has already been seen (when passing through the
sequentially). A thread will therefore only appear *once* in the list sequentially). A thread will therefore only appear *once* in
"threadIds" list of the result, at the position of the first email in the result, at the position of the first email in the list that
the list that belongs to the thread. belongs to the thread (given the current sort/filter).
4.4.4. Response 4.4.4. Response
The response has the following additional argument: The response has the following additional argument:
o *collapseThreads*: "Boolean" The _collapseThreads_ value that was o *collapseThreads*: "Boolean" The _collapseThreads_ value that was
used when calculating the email list for this call. used when calculating the email list for this call.
4.5. Email/queryChanges 4.5. Email/queryChanges
Standard _/queryChanges_ method, with the following additional Standard "/queryChanges" method, with the following additional
arguments: arguments:
o *collapseThreads*: "Boolean" (default: "false") The o *collapseThreads*: "Boolean" (default: false) The
_collapseThreads_ argument that was used with _Email/query_. _collapseThreads_ argument that was used with _Email/query_.
The response has the following additional argument: The response has the following additional argument:
o *collapseThreads*: "Boolean" The _collapseThreads_ value that was o *collapseThreads*: "Boolean" The _collapseThreads_ value that was
used when calculating the email list for this call. used when calculating the email list for this call.
4.6. Email/set 4.6. Email/set
Standard _/set_ method. The _Email/set_ method encompasses: Standard "/set" method. The _Email/set_ method encompasses:
o Creating a draft o Creating a draft
o Changing the keywords of an email (e.g. unread/flagged status) o Changing the keywords of an email (e.g. unread/flagged status)
o Adding/removing an email to/from mailboxes (moving a message) o Adding/removing an email to/from mailboxes (moving a message)
o Deleting emails o Deleting emails
Due to the format of the Email object, when creating an email there 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 are a number of ways to specify the same information. To ensure that
the RFC5322 email to create is unambiguous, the following constraints the RFC5322 email to create is unambiguous, the following constraints
apply to Email objects submitted for creation: apply to Email objects submitted for creation:
o The _headers_ property MUST NOT be given, on either the top-level o The _headers_ property MUST NOT be given, on either the top-level
email or an EmailBodyPart - the client must set each header field email or an EmailBodyPart - the client must set each header field
as an individual property. as an individual property.
o There MUST NOT be two properties that represent the same header o There MUST NOT be two properties that represent the same header
skipping to change at page 42, line 27 skipping to change at page 44, line 33
Destroying an email removes it from all mailboxes to which it Destroying an email removes it from all mailboxes to which it
belonged. To just delete an email to trash, simply change the belonged. To just delete an email to trash, simply change the
"mailboxIds" property so it is now in the mailbox with "role == "mailboxIds" property so it is now in the mailbox with "role ==
"trash"", and remove all other mailbox ids. "trash"", and remove all other mailbox ids.
When emptying the trash, clients SHOULD NOT destroy emails which are When emptying the trash, clients SHOULD NOT destroy emails which are
also in a mailbox other than trash. For those emails, they SHOULD also in a mailbox other than trash. For those emails, they SHOULD
just remove the Trash mailbox from the email. just remove the Trash mailbox from the email.
For successfully created Email objects, the _created_ response MUST For successfully created Email objects, the _created_ response
contain the _id_, _blobId_, _threadId_ and _size_ properties of the contains the _id_, _blobId_, _threadId_ and _size_ properties of the
object. object.
The following extra _SetError_ types are defined: The following extra _SetError_ types are defined:
For *create*: For *create*:
o "blobNotFound": At least one blob id given for an EmailBodyPart o "blobNotFound": At least one blob id given for an EmailBodyPart
doesn't exist. An extra _notFound_ property of type "String[]" doesn't exist. An extra _notFound_ property of type "String[]"
MUST be included in the error object containing every _blobId_ MUST be included in the error object containing every _blobId_
referenced by an EmailBodyPart that could not be found on the referenced by an EmailBodyPart that could not be found on the
server. server.
For *create* and *update*: For *create* and *update*:
o "tooManyKeywords": The change to the email's keywords would exceed o "tooManyKeywords": The change to the email's keywords would exceed
a server-defined maximum. a server-defined maximum.
o "tooManyMailboxes": The change to the email's mailboxes would o "tooManyMailboxes": The change to the email's mailboxes would
exceed a server-defined maximum. exceed a server-defined maximum.
4.7. Email/import 4.7. Email/copy
Standard "/copy" method, except only the _mailboxIds_, _keywords_ and
_receivedAt_ properties may be set during the copy. This method
cannot modify the RFC5322 representation of an email.
The server MAY forbid two email objects with the same exact [RFC5322]
content, or even just with the same [RFC5322] Message-ID, to coexist
within an account. If duplicates are allowed though, the "from"
account may be the same as the "to" account to copy emails within an
account.
For successfully copied Email objects, the _created_ response
contains the _id_, _blobId_, _threadId_ and _size_ properties of the
new object.
4.8. Email/import
The _Email/import_ method adds [RFC5322] messages to a user's set of The _Email/import_ method adds [RFC5322] messages to a user's set of
emails. The messages must first be uploaded as a file using the emails. The messages must first be uploaded as a file using the
standard upload mechanism. It takes the following arguments: standard upload mechanism. It takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this o *accountId*: "String|null" The id of the account to use for this
call. If "null", defaults to the "urn:ietf:params:jmap:mail" call. If "null", defaults to the "urn:ietf:params:jmap:mail"
primary account. primary account.
o *emails*: "String[EmailImport]" A map of creation id (client o *emails*: "String[EmailImport]" A map of creation id (client
specified) to EmailImport objects specified) to EmailImport objects
An *EmailImport* object has the following properties: An *EmailImport* object has the following properties:
o *blobId*: "String" The id of the blob containing the raw [RFC5322] o *blobId*: "String" The id of the blob containing the raw [RFC5322]
message. message.
o *mailboxIds* "String[Boolean]" The ids of the mailboxes to assign o *mailboxIds*: "String[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 o *keywords*: "String[Boolean]" (default: ) The keywords to apply to
apply to the email. the email.
o *receivedAt*: "UTCDate" (default: time of import on server) The o *receivedAt*: "UTCDate" (default: time of import on server) The
_receivedAt_ date to set on the email. _receivedAt_ date 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 reference 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.
The server MAY forbid two email objects with the same exact [RFC5322] The server MAY forbid two email objects with the same exact [RFC5322]
content, or even just with the same [RFC5322] Message-ID, to coexist content, or even just with the same [RFC5322] Message-ID, to coexist
within an account. In this case, it MUST reject attempts to import within an account. In this case, it MUST reject attempts to import
an email considered a duplicate with an "alreadyExists" SetError. An an email considered a duplicate with an "alreadyExists" SetError. An
_emailId_ property of type "String" MUST be included on the error _emailId_ property of type "String" MUST be included on the error
object with the id of the existing email. object with the id of the existing email.
If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid
(e.g. missing, wrong type, id not found), the server MUST reject the (e.g. missing, wrong type, id not found), the server MUST reject the
import with an "invalidProperties" SetError. import with an "invalidProperties" SetError.
If the email cannot be imported because it would take the account If the email cannot be imported because it would take the account
over quota, the import should be rejected with a "maxQuotaReached" over quota, the import should be rejected with a "overQuota"
SetError. SetError.
If the blob referenced is not a valid [RFC5322] message, the server If the blob referenced is not a valid [RFC5322] message, the server
MAY modify the message to fix errors (such as removing NUL octets or MAY modify the message to fix errors (such as removing NUL octets or
fixing invalid headers). If it does this, the _blobId_ on the fixing invalid headers). If it does this, the _blobId_ on the
response MUST represent the new representation and therefore be response MUST represent the new representation and therefore be
different to the _blobId_ on the EmailImport object. Alternatively, different to the _blobId_ on the EmailImport object. Alternatively,
the server MAY reject the import with an "invalidEmail" SetError. the server MAY reject the import with an "invalidEmail" SetError.
The response has the following arguments: The response has the following arguments:
skipping to change at page 44, line 24 skipping to change at page 46, line 41
o *accountId*: "String" The id of the account used for this call. o *accountId*: "String" The id of the account used for this call.
o *created*: "String[Email]" A map of the creation id to an object o *created*: "String[Email]" A map of the creation id to an object
containing the _id_, _blobId_, _threadId_ and _size_ properties containing the _id_, _blobId_, _threadId_ and _size_ properties
for each successfully imported Email. for each successfully imported Email.
o *notCreated*: "String[SetError]" A map of creation id to a o *notCreated*: "String[SetError]" A map of creation id to a
SetError object for each Email that failed to be created. The SetError object for each Email that failed to be created. The
possible errors are defined above. possible errors are defined above.
4.8. Email/copy
The only way to move messages *between* two different accounts is to
copy them using the _Email/copy_ method, then once the copy has
succeeded, delete the original. The _onSuccessDestroyOriginal_
argument allows you to try to do this in one method call, however
note that the two different actions are not atomic, and so it is
possible for the copy to succeed but the original not to be destroyed
for some reason.
The _Email/copy_ method takes the following arguments:
o *fromAccountId*: "String|null" The id of the account to copy
emails from. If "null", defaults to the
"urn:ietf:params:jmap:mail" primary account.
o *toAccountId*: "String|null" The id of the account to copy emails
to. If "null", defaults to the "urn:ietf:params:jmap:mail"
primary account.
o *create*: "String[EmailCopy]" A map of _creation id_ to an
EmailCopy object.
o *onSuccessDestroyOriginal*: "Boolean" (default: "false") If
"true", an attempt will be made to destroy the emails that were
successfully copied: after emitting the _Email/copy_ response, but
before processing the next method, the server MUST make a single
call to _Email/set_ to destroy the original of each successfully
copied message; the output of this is added to the responses as
normal to be returned to the client.
An *EmailCopy* object has the following properties:
o *id*: "String" The id of the email to be copied in the "from"
account.
o *mailboxIds*: "String[Boolean]" The ids of the mailboxes (in the
"to" account) to add the copied email to. At least one mailbox
MUST be given.
o *keywords*: "String[Boolean]" (default: "{}") The _keywords_
property for the copy.
o *receivedAt*: "UTCDate" (default: _receivedAt_ date of original)
The _receivedAt_ date to set on the copy.
The server MAY forbid two email objects with the same exact [RFC5322]
content, or even just with the same [RFC5322] Message-ID, to coexist
within an account. If duplicates are allowed though, the "from"
account may be the same as the "to" account to copy emails within an
account.
Each email copy is considered an atomic unit which may succeed or
fail individually. Copying successfully MUST create a new email
object, with separate ids and mutable properties (e.g. mailboxes and
keywords) to the original email.
The response has the following arguments:
o *fromAccountId*: "String" The id of the account emails were copied
from.
o *toAccountId*: "String" The id of the account emails were copied
to.
o *created*: "String[Email]|null" A map of the creation id to an
object containing the _id_, _blobId_, _threadId_ and _size_
properties for each successfully copied Email.
o *notCreated*: "String[SetError]|null" A map of creation id to a
SetError object for each Email that failed to be copied, "null" if
none.
The *SetError* may be any of the standard set errors that may be
returned for a _create_. The following extra _SetError_ type is also
defined:
"alreadyExists": The server forbids duplicates and the email already
exists in the target account. An _emailId_ property of type "String"
MUST be included on the error object with the id of the existing
email.
The following additional errors may be returned instead of the
_Email/copy_ response:
"fromAccountNotFound": A _fromAccountId_ was explicitly included with
the request, but it does not correspond to a valid account; or,
_fromAccountId_ was null but there is no primary account for
"urn:ietf:params:jmap:mail".
"toAccountNotFound": A _toAccountId_ was explicitly included with the
request, but it does not correspond to a valid account; or,
_toAccountId_ was null but there is no primary account for
"urn:ietf:params:jmap:mail".
"fromAccountNotSupportedByMethod": The _fromAccountId_ given
corresponds to a valid account, but does not contain any mail data.
"toAccountNotSupportedByMethod": The _toAccountId_ given corresponds
to a valid account, but does not contain any mail data.
4.9. Email/parse 4.9. Email/parse
This method allows you to parse blobs as [RFC5322] messages to get This method allows you to parse blobs as [RFC5322] messages to get
Email objects. The following metadata properties on the Email Email objects. This can be used to parse and display attached emails
objects will be "null" if requested: without having to import them as top-level email objects in the mail
store in their own right.
o id The following metadata properties on the Email objects will be "null"
if requested:
o id
o mailboxIds o mailboxIds
o keywords o keywords
o receivedAt o receivedAt
The _threadId_ property of the Email MAY be present if the server can 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 calculate which thread the Email would be assigned to were it to be
imported. Otherwise, this too is "null" if fetched. imported. Otherwise, this too is "null" if fetched.
skipping to change at page 47, line 12 skipping to change at page 47, line 28
o *blobIds*: "String[]" The ids of the blobs to parse. o *blobIds*: "String[]" The ids of the blobs to parse.
o *properties*: "String[]" If supplied, only the properties listed o *properties*: "String[]" If supplied, only the properties listed
in the array are returned for each Email object. If omitted, in the array are returned for each Email object. If omitted,
defaults to: [ "messageId", "inReplyTo", "references", "sender", defaults to: [ "messageId", "inReplyTo", "references", "sender",
"from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt",
"hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody",
"attachments" ] "attachments" ]
o *bodyProperties*: "String[]" (optional) A list of properties to o *bodyProperties*: "String[]" A list of properties to fetch for
fetch for each EmailBodyPart returned. If omitted, defaults to each EmailBodyPart returned. If omitted, defaults to the same
the same value as the Email/get "bodyProperties" default argument. value as the Email/get "bodyProperties" default argument.
o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the o *fetchTextBodyValues*: "Boolean" (default: false) If "true", the
_bodyValues_ property includes any "text/*" part in the "textBody" _bodyValues_ property includes any "text/*" part in the "textBody"
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*: "Number" (optional) If supplied by the o *maxBodyValueBytes*: "PositiveInt" (default: 0) If greater than
client, the value MUST be a positive integer greater than 0. If a zero, the _value_ property of any EmailBodyValue object returned
value outside of this range is given, the server MUST reject the in _bodyValues_ MUST be truncated if necessary so it does not
call with an "invalidArguments" error. When given, the _value_ exceed this number of octets in size. If "0" (the default), no
property of any EmailBodyValue object returned in _bodyValues_ truncation occurs. The server MUST ensure the truncation results
MUST be truncated if necessary so it does not exceed this number
of octets in size. 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. 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).
The response has the following arguments: The response has the following arguments:
o *accountId*: "String" The id of the account used for the call. o *accountId*: "String" The id of the account used for the call.
o *parsed*: "String[Email]|null" A map of blob id to parsed Email o *parsed*: "String[Email]|null" A map of blob id to parsed Email
representation for each successfully parsed blob, or "null" if representation for each successfully parsed blob, or "null" if
none. none.
o *notParsable*: "String[]|null" A list of ids given that o *notParsable*: "String[]|null" A list of ids given that
skipping to change at page 48, line 14 skipping to change at page 48, line 32
As specified above, parsed forms of headers may only be used on As specified above, parsed forms of headers may only be used on
appropriate header fields. Attempting to fetch a form that is appropriate header fields. Attempting to fetch a form that is
forbidden (e.g. "header:From:asDate") MUST result in the method call forbidden (e.g. "header:From:asDate") MUST result in the method call
being rejected with an "invalidArguments" error. being rejected with an "invalidArguments" error.
Where a specific header is requested as a property, the Where a specific header is requested as a property, the
capitalization of the property name in the response MUST be identical capitalization of the property name in the response MUST be identical
to that used in the request. to that used in the request.
5. Identities 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 will just load
the start and then can load in more as necessary. The client sends
this request:
[[ "Email/query",{
"accountId": "ue150411c",
"filter": {
"inMailbox": "fb666a55"
},
"sort": [{
"isAscending": false,
"property": "receivedAt"
}],
"collapseThreads": true,
"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" ]]
Let's break down the 4 method calls to see what they're doing:
1. This asks the server for the ids of the first 30 Email objects in
the inbox, sorted newest first, ignoring messages from the same
thread as a newer message in the mailbox (i.e. it is the first 30
unique threads).
2. Now we use a backreference to fetch the thread ids for each of
these email ids.
3. Another backreference fetches the Thread object for each of these
thread ids.
4. Finally, we fetch the information we need to display the mailbox
listing ( but no more!) for every message in each of these 30
threads. The client may aggregate this data for display, for
example showing the thread as "flagged" if any of the messages in
it contain the "$flagged" keyword.
The response from the server may look something like this:
[[ "Email/query", {
"accountId": "ue150411c",
"filter": {
"inMailbox": "fb666a55"
},
"sort": [{
"property": "receivedAt",
"isAscending": false
}],
"collapseThreads": true,
"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" ],
}, {
"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 the ...",
},
...
],
"notFound": []
}, "3" ]]
Now, on another device the user marks the first message 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 messages, and then a new message arrives.
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",
"filter": {
"inMailbox": "fb666a55"
},
"sort": [{
"property": "receivedAt",
"isAscending": false
}],
"collapseThreads": true,
"upToId": "Mc2781d5e856a908d8a35a564",
"added": [{
"id": "Me8de6c9f6de198239b982ea2",
"index": 0
}],
"removed": [ "M9bd17497e2a99cb345fc1d0a" ],
"total": 115,
}, "11" ],
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 backreferences).
It knows something has changed about "Ma783e5cdf5f2deffbc97930a", so
it will refetch the mailboxes and keywords (the only mutable
properties) for this email too.
The user composes a new message and saves a draft. The client sends:
[[ "Email/set", {
"accountId": "ue150411c",
"create": {
"k1546": {
"mailboxIds": {
"2ea1ca41b38e": true
},
"keywords": {
"$seen": true,
"$draft": true
},
"from": [{
"name": "Joe Bloggs",
"email": "joe@example.com"
}],
"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": "49db",
"type": "text/html"
}, {
"partId": "bd48",
"type": "text/plain"
}]
},
"bodyValues": {
"bd48": {
"value": "I have the most brilliant plan. Let me tell you all about it. What we do is, we",
"isTruncated": false
},
"49db": {
"value": "<!DOCTYPE html><html><head><title></title><style type=\"text/css\">div{font-size:16px}</style></head><body><div>I have the most brilliant plan. Let me tell you all about it. What we do is, we</div></body></html>",
"isTruncated": false
}
}
}
}
}, "0" ]]
The server creates the message and sends the success response:
[[ "Email/set", {
"accountId": "ue150411c",
"oldState": "780823",
"newState": "780839",
"created": {
"k1546": {
"id": "Md45b47b4877521042cec0938",
"blobId": "Ge8de6c9f6de198239b982ea214e0f3a704e4af74",
"threadId": "Td957e72e89f516dc",
"size": 11721
}
},
...
}, "0" ]]
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
property, since the current value will not be valid mailbox ids in
the destination account:
[[ "Email/copy", {
"fromAccountId": "ue150411c",
"toAccountId": "6c6c41ac",
"create": {
"k45": {
"id": "Md45b47b4877521042cec0938",
"mailboxIds": {
"75a4c956": true
}
}
},
"onSuccessDestroyOriginal": true
}, "0" ]]
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 client id:
[[ "Email/copy", {
"fromAccountId": "ue150411c",
"toAccountId": "6c6c41ac",
"created": {
"k45": {
"id": "M138f9954a5cd2423daeafa55",
"blobId": "G6b9fb047cba722c48c611e79233d057c6b0b74e8",
"threadId": "T2f242ea424a4079a",
"size": 11721
}
},
"notCreated": null
}, "0" ],
[ "Email/set", {
"accountId": "ue150411c",
"oldState": "780839"
"newState": "780871",
"destroyed": [ "Ma783e5cdf5f2deffbc97930a" ],
...
}, "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 instead of the beginning of the message, 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*: "String" The email id the snippet applies to.
o *subject*: "String|null" If text from the filter matches the
subject, this is the subject of the email HTML-escaped, with
matching words/phrases wrapped in "<mark></mark>" tags. If it
does not match, this is "null".
o *preview*: "String|null" If text from the filter matches the
plain-text or HTML body, this is the relevant section of the body
(converted to plain text if originally HTML), HTML-escaped, with
matching words/phrases wrapped in "<mark></mark>" tags. It MUST
NOT be bigger than 255 octets in size. If it does not match, this
is "null".
It is server-defined what is a relevant section of the body for
preview. If the server is unable to determine search snippets, it
MUST return "null" for both the _subject_ and _preview_ roperties.
Note, 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*: "String|null" The id of the account to use for this
call. If "null", defaults to the "urn:ietf:params:jmap:mail"
primary account.
o *filter*: "FilterOperator|FilterCondition|null" The same filter as
passed to Email/query; see the description of this method for
details.
o *emailIds*: "String[]" The list of ids of emails to fetch the
snippets for.
The response has the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *filter*: "FilterOperator|FilterCondition|null" Echoed back from
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*: "String[]|null" An array of email ids requested which
could not be found, or "null" if all ids were found.
Since snippets are only based on immutable properties, there is no
state string or update mechanism needed.
The following standard errors may be returned instead of the
_searchSnippets_ 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.
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",
...
]
}, "tag-0" ]
Example response:
[[ "SearchSnippet/get", {
"accountId": "ue150411c",
"filter": {
"text": "foo"
},
"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": "...mail <mark>Foo</mark>/changes results often return current-state-minus-1 rather than new..."
},
...
],
"notFound": null
}, "tag-0" ]]
6. Identities
An *Identity* object stores information about an email address (or An *Identity* object stores information about an email address (or
domain) the user may send from. It has the following properties: domain) the user may send from. It has the following properties:
o *id*: "String" (immutable; server-set) The id of the identity. o *id*: "String" (immutable; server-set) The id of the identity.
o *name*: "String" (default: """") The "From" _name_ the client o *name*: "String" (default: "") The "From" _name_ the client SHOULD
SHOULD use when creating a new message from this identity. use when creating a new message from this identity.
o *email*: "String" (immutable) The "From" email address the client o *email*: "String" (immutable) The "From" email address the client
MUST use when creating a new message from this identity. The MUST use when creating a new message from this identity. The
value MAY alternatively be of the form "*@example.com", in which value MAY alternatively be of the form "*@example.com", in which
case the client may use any valid email address ending in case the client may use any valid email address ending in
"@example.com". "@example.com".
o *replyTo*: "EmailAddress[]|null" (default: "null") The Reply-To o *replyTo*: "EmailAddress[]|null" (default: null) The Reply-To
value the client SHOULD set when creating a new message from this value the client SHOULD set when creating a new message from this
identity. identity.
o *bcc*: "EmailAddress[]|null" (default: "null") The Bcc value the o *bcc*: "EmailAddress[]|null" (default: null) The Bcc value the
client SHOULD set when creating a new message from this identity. client SHOULD set when creating a new message from this identity.
o *textSignature*: "String" (default: """") Signature the client o *textSignature*: "String" (default: "") Signature the client
SHOULD insert into new plain-text messages that will be sent from SHOULD insert into new plain-text messages that will be sent from
this identity. Clients MAY ignore this and/or combine this with a this identity. Clients MAY ignore this and/or combine this with a
client-specific signature preference. client-specific signature preference.
o *htmlSignature*: "String" (default: """") Signature the client o *htmlSignature*: "String" (default: "") Signature the client
SHOULD insert into new HTML messages that will be sent from this SHOULD insert into new HTML messages that will be sent from this
identity. This text MUST be an HTML snippet to be inserted into identity. This text MUST be an HTML snippet to be inserted into
the "<body></body>" section of the new email. Clients MAY ignore the "<body></body>" section of the new email. Clients MAY ignore
this and/or combine this with a client-specific signature this and/or combine this with a client-specific signature
preference. preference.
o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete
this identity? Servers may wish to set this to "false" for the this identity? Servers may wish to set this to "false" for the
user's username or other default address. 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 for See the "Addresses" header form description in the Email object for
the definition of _EmailAddress_. the definition of _EmailAddress_.
Multiple identities with the same email address MAY exist, to allow Multiple identities with the same email address MAY exist, to allow
for different settings the user wants to pick between (for example for different settings the user wants to pick between (for example
with different names/signatures). with different names/signatures).
The following JMAP methods are supported: The following JMAP methods are supported:
5.1. Identity/get 6.1. Identity/get
Standard _/get_ method. The _ids_ argument may be "null" to fetch Standard "/get" method. The _ids_ argument may be "null" to fetch
all at once. all at once.
5.2. Identity/changes 6.2. Identity/changes
Standard _/changes_ method. Standard "/changes" method.
5.3. Identity/set 6.3. Identity/set
Standard _/set_ method. The following extra _SetError_ types are Standard "/set" method. The following extra _SetError_ types are
defined: defined:
For *create*: For *create*:
o "maxQuotaReached": The user has reached a server-defined limit on o "forbiddenFrom": The user is not allowed to send from the address
the number of identities. given as the _email_ property of the identity.
o "emailNotPermitted": The user is not allowed to send from the
address given as the _email_ property of the identity.
For *destroy*:
o "forbidden": Returned if the identity's _mayDelete_ value is
"false".
5.4. Example 6.4. Example
Request: Request:
[ "Identity/get", {}, "0" ] [ "Identity/get", {}, "0" ]
with response: with response:
[ "Identity/get", { [ "Identity/get", {
"accountId": "acme", "accountId": "acme",
"state": "99401312ae-11-333", "state": "99401312ae-11-333",
skipping to change at page 50, line 36 skipping to change at page 61, line 36
"replyTo": null, "replyTo": null,
"bcc": null, "bcc": null,
"textSignature": "", "textSignature": "",
"htmlSignature": "", "htmlSignature": "",
"mayDelete": true "mayDelete": true
} }
], ],
"notFound": [] "notFound": []
}, "0" ] }, "0" ]
6. Email submission 7. Email submission
An *EmailSubmission* object represents the submission of an email for An *EmailSubmission* object represents the submission of an email for
delivery to one or more recipients. It has the following properties: delivery to one or more recipients. It has the following properties:
o *id*: "String" (immutable; server-set) The id of the email o *id*: "String" (immutable; server-set) The id of the email
submission. submission.
o *identityId*: "String" (immutable) The id of the identity to o *identityId*: "String" (immutable) The id of the identity to
associate with this submission. associate with this submission.
o *emailId*: "String" (immutable) The id of the email to send. The o *emailId*: "String" (immutable) The id of the email to send. The
email being sent does not have to be a draft, for example when email being sent does not have to be a draft, for example when
"redirecting" an existing email to a different address. "redirecting" an existing email to a different address.
o *threadId*: "String" (immutable; server-set) The thread id of the o *threadId*: "String" (immutable; server-set) The thread id of the
email to send. This is set by the server to the _threadId_ email to send. This is set by the server to the _threadId_
property of the email referenced by the _emailId_. property of the email referenced by the _emailId_.
o *envelope*: "Envelope|null" (immutable; default: "null") o *envelope*: "Envelope|null" (immutable; default: null) Information
Information for use when sending via SMTP. An *Envelope* object for use when sending via SMTP. An *Envelope* object has the
has the following properties: following properties:
* *mailFrom*: "Address" The email address to use as the return * *mailFrom*: "Address" The email address to use as the return
address in the SMTP submission, plus any parameters to pass address in the SMTP submission, plus any parameters to pass
with the MAIL FROM address. The JMAP server MAY allow the with the MAIL FROM address. The JMAP server MAY allow the
address to be the empty string. When a JMAP server performs an address to be the empty string. When a JMAP server performs an
SMTP message submission, it MAY use the same id string for the SMTP message submission, it MAY use the same id string for the
[RFC3461] ENVID parameter and the EmailSubmission object id. [RFC3461] ENVID parameter and the EmailSubmission object id.
Servers that do this MAY replace a client-provided value for Servers that do this MAY replace a client-provided value for
ENVID with a server-provided value. ENVID with a server-provided value.
skipping to change at page 55, line 13 skipping to change at page 66, line 13
object. object.
For efficiency, a server MAY destroy EmailSubmission objects a For efficiency, a server MAY destroy EmailSubmission objects a
certain amount of time after the email is successfully sent or it has certain amount of time after the email is successfully sent or it has
finished retrying sending the email. For very basic SMTP proxies, finished retrying sending the email. For very basic SMTP proxies,
this MAY be immediately after creation, as it has no way to assign a this MAY be immediately after creation, as it has no way to assign a
real id and return the information again if fetched later. real id and return the information again if fetched later.
The following JMAP methods are supported: The following JMAP methods are supported:
6.1. EmailSubmission/get 7.1. EmailSubmission/get
Standard _/get_ method. Standard "/get" method.
6.2. EmailSubmission/changes 7.2. EmailSubmission/changes
Standard _/changes_ method. Standard "/changes" method.
6.3. EmailSubmission/query 7.3. EmailSubmission/query
Standard _/query_ method. Standard "/query" method.
A *FilterCondition* object has the following properties, any of which A *FilterCondition* object has the following properties, any of which
may be omitted: may be omitted:
o *emailIds*: "String[]" The EmailSubmission _emailId_ property must o *emailIds*: "String[]" The EmailSubmission _emailId_ property must
be in this list to match the condition. be in this list to match the condition.
o *threadIds*: "String[]" The EmailSubmission _threadId_ property o *threadIds*: "String[]" The EmailSubmission _threadId_ property
must be in this list to match the condition. must be in this list to match the condition.
skipping to change at page 56, line 6 skipping to change at page 67, line 6
given conditions given match. If zero properties are specified, it given conditions given match. If zero properties are specified, it
is automatically "true" for all objects. 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"
6.4. EmailSubmission/queryChanges 7.4. EmailSubmission/queryChanges
Standard _/queryChanges_ method. Standard "/queryChanges" method.
6.5. EmailSubmission/set 7.5. EmailSubmission/set
Standard _/set_ method, with the following two extra arguments: Standard "/set" method, with the following two extra arguments:
o *onSuccessUpdateEmail*: "String[Email]|null" A map of o *onSuccessUpdateEmail*: "String[Email]|null" A map of
_EmailSubmission id_ to an object containing properties to update _EmailSubmission id_ to an object containing properties to update
on the Email object referenced by the EmailSubmission if the on the Email object referenced by the EmailSubmission if the
create/update/destroy succeeds. (For references to create/update/destroy succeeds. (For references to
EmailSubmission creations, this is equivalent to a back reference EmailSubmission creations, this is equivalent to a back reference
so the id will be the creation id prefixed with a "#".) so the id will be the creation id prefixed with a "#".)
o *onSuccessDestroyEmail*: "String[]|null" A list of o *onSuccessDestroyEmail*: "String[]|null" A list of
_EmailSubmission ids_ for which the email with the corresponding _EmailSubmission ids_ for which the email with the corresponding
skipping to change at page 57, line 9 skipping to change at page 68, line 9
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.
The following extra _SetError_ types are defined: The following extra _SetError_ types are defined:
For *create*: For *create*:
o "tooLarge" - The email size is larger than the server supports o "emailNotFound" - The _emailId_ is not a valid id for an email in
sending. A _maxSize_ "Number" property MUST be present on the the account.
SetError specifying the maximum size of an email that may be sent,
in octets. o "emailTooLarge" - The email size is larger than the server
supports sending. A _maxSize_ "PositiveInt" property MUST be
present on the SetError specifying the maximum size of an email
that may be sent, in octets.
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 o "tooManyRecipients" - The envelope (supplied or generated) has
more recipients than the server allows. A _maxRecipients_ more recipients than the server allows. A _maxRecipients_
"Number" property MUST be present on the SetError specifying the "PositiveInt" property MUST also be present on the SetError
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 be present on the SetError, which is a "String[]" property MUST also be present on the SetError, which is
list of the invalid addresses. a list of the invalid addresses.
o "forbiddenMailFrom" - The server does not permit the user to send o "forbiddenMailFrom" - The server does not permit the user to send
an email with the [RFC5321] envelope From. an email with the [RFC5321] envelope From.
o "forbiddenFrom" - The server does not permit the user to send an o "forbiddenFrom" - The server does not permit the user to send an
email with the [RFC5322] From header of the email to be sent. email with the [RFC5322] From header of the email to be sent.
o "forbiddenToSend" - The user does not have permission to send at o "forbiddenToSend" - The user does not have permission to send at
all right now for some reason. A _description_ "String" property all right now for some reason. A _description_ "String" property
MAY be present on the SetError object to display to the user why MAY be present on the SetError object to display to the user why
they are not permitted. The server MAY choose to localise this they are not permitted. The server MAY choose to localise this
string into the user's preferred language, if known. string into the user's preferred language, if known.
o "emailNotFound" - The _emailId_ is not a valid id for an email in
the account.
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.
For *update*: For *update*:
o "cannotUnsend": The client attempted to update the _undoStatus_ of o "cannotUnsend": The client attempted to update the _undoStatus_ of
a valid EmailSubmission object from "pending" to "canceled", but a valid EmailSubmission object from "pending" to "canceled", but
the email cannot be unsent. the email cannot be unsent.
6.5.1. Example 7.5.1. Example
The following example presumes a draft of the message to be sent has The following example presumes a draft of the message to be sent has
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",
{ "create": {
"accountId": "ue411d190", "k1490": {
"create": { "identityId": "64588216",
"k1490": { "emailId": "M7f6ed5bcfd7e2604d1753f6c",
"identityId": "64588216", "envelope": {
"emailId": "M7f6ed5bcfd7e2604d1753f6c", "mailFrom": {
"envelope": { "email": "john@example.com",
"mailFrom": { "parameters": null
"email": "john@example.com", },
"parameters": null "rcptTo": [{
}, "email": "jane@example.com",
"rcptTo": [ "parameters": null
{ },
"email": "jane@example.com", ...
"parameters": null ]
} }
] }
} },
} "onSuccessUpdateEmail": {
}, "#k1490": {
"onSuccessUpdateEmail": { "mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null,
"#k1490": { "mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true,
"mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null, "keywords/$draft": null
"mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true, }
"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
tag as they are due to the same call in the request: tag as they are due to the same call in the request:
[ [[ "EmailSubmission/set", {
"EmailSubmission/set", "accountId": "ue411d190",
{ "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21",
"accountId": "ue411d190", "newState": "355421f6-8aed-4cf4-a0c4-7377e951af36",
"oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21, "created": {
"newState": "355421f6-8aed-4cf4-a0c4-7377e951af36", "k1490": {
"created": { "id": "3bab7f9a-623e-4acf-99a5-2e67facb02a0"
"k1490": { }
"id": "3bab7f9a-623e-4acf-99a5-2e67facb02a0" },
} "notCreated": null,
}, "updated": null,
"notCreated": null, "notUpdated": null,
"updated": null, "destroyed": null,
"notUpdated": null, "notDestroyed": null
"destroyed": null, }, "0" ],
"notDestroyed": null [ "Email/set", {
}, "accountId": "neilj@fastmail.fm",
"0" "oldState": "778193",
], "newState": "778197",
[ "created": null,
"Email/set", "notCreated": null,
{ "updated": {
"accountId": "neilj@fastmail.fm", "M7f6ed5bcfd7e2604d1753f6c": null
"oldState": "778193", },
"newState": "778197", "notUpdated": null,
"created": null, "destroyed": null,
"notCreated": null, "notDestroyed": null
"updated": { }, "0" ]]
"M7f6ed5bcfd7e2604d1753f6c": null
},
"notUpdated": null,
"destroyed": null,
"notDestroyed": null
},
"0"
]
7. 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 instead of the beginning of the message, 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*: "String" The email id the snippet applies to.
o *subject*: "String|null" If text from the filter matches the
subject, this is the subject of the email HTML-escaped, with
matching words/phrases wrapped in "<mark></mark>" tags. If it
does not match, this is "null".
o *preview*: "String|null" If text from the filter matches the
plain-text or HTML body, this is the relevant section of the body
(converted to plain text if originally HTML), HTML-escaped, with
matching words/phrases wrapped in "<mark></mark>" tags. It MUST
NOT be bigger than 255 octets in size. If it does not match, this
is "null".
o *attachments*: "String|null" If text from the filter matches the
text extracted from an attachment, this is the relevant section of
the attachment (converted to plain text), with matching words/
phrases wrapped in "<mark></mark>" tags. It MUST NOT be bigger
than 255 octets in size. If it does not match, this is "null".
It is server-defined what is a relevant section of the body for
preview. If the server is unable to determine search snippets, it
MUST return "null" for both the _subject_, _preview_ and
_attachments_ properties.
Note, unlike most data types, a SearchSnippet DOES NOT have a
property called "id".
The following JMAP method is supported:
7.1. SearchSnippet/get
To fetch search snippets, make a call to "SearchSnippet/get". It
takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If "null", defaults to the "urn:ietf:params:jmap:mail"
primary account.
o *filter*: "FilterOperator|FilterCondition|null" The same filter as
passed to Email/query; see the description of this method for
details.
o *emailIds*: "String[]" The list of ids of emails to fetch the
snippets for.
The response has the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *filter*: "FilterOperator|FilterCondition|null" Echoed back from
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*: "String[]|null" An array of email ids requested which
could not be found, or "null" if all ids were found.
Since snippets are only based on immutable properties, there is no
state string or update mechanism needed.
The following additional errors may be returned instead of the
_searchSnippets_ response:
"requestTooLarge": Returned if the number of _emailIds_ requested by
the client exceeds the maximum number the server is willing to
process in a single method call.
"unsupportedFilter": Returned if the server is unable to process the
given _filter_ for any reason.
7.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",
...
]
},
"tag-0"
]
Example response: If the email submission was not accepted on the other hand, the
response may look like this:
[ [[ "EmailSubmission/set", {
"SearchSnippet/get", { "accountId": "ue411d190",
"accountId": "ue150411c", "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21",
"filter": { "newState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21",
"text": "foo" "created": null,
}, "notCreated": {
"list": [{ "k1490": {
"emailId": "M44200ec123de277c0c1ce69c" "type": "tooManyRecipients",
"subject": null, "maxRecipients": 10
"preview": null }
}, { },
"emailId": "M7bcbcb0b58d7729686e83d99", "updated": null,
"subject": "The <mark>Foo</mark>sball competition", "notUpdated": null,
"preview": "...year the <mark>foo</mark>sball competition will be held in the Stadium de ..." "destroyed": null,
}, { "notDestroyed": null
"emailId": "M28d12783a0969584b6deaac0", }, "0" ]]
"subject": null,
"preview": "...mail <mark>Foo</mark>/changes results often return current-state-minus-1 rather than new..."
},
...
],
"notFound": null
},
"0"
]
8. Vacation response 8. Vacation response
A vacation response automatically sends a reply to messages sent to a
particular account, to inform the original sender that their message
may not be processed for some time. Automated message sending can
produce undesireable behaviour. To avoid this, implementors MUST
follow the recommendations set forth in [RFC3834].
The *VacationResponse* object represents the state of vacation- The *VacationResponse* object represents the state of vacation-
response related settings for an account. It has the following response related settings for an account. It has the following
properties: properties:
o *id*: "String" (immutable) The id of the object. There is only o *id*: "String" (immutable) The id of the object. There is only
ever one vacation response object, and its id is ""singleton"". ever one vacation response object, and its id is ""singleton"".
o *isEnabled* "Boolean" Should a vacation response be sent if an o *isEnabled*: "Boolean" Should a vacation response be sent if an
email arrives between the _fromDate_ and _toDate_? email arrives between the _fromDate_ and _toDate_?
o *fromDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time o *fromDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time
in UTC after which emails that arrive should receive the user's in UTC after which emails that arrive should receive the user's
vacation response. If "null", the vacation response is effective vacation response. If "null", the vacation response is effective
immediately. immediately.
o *toDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time o *toDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time
in UTC after which emails that arrive should no longer receive the in UTC after which emails that arrive should no longer receive the
user's vacation response. If "null", the vacation response is user's vacation response. If "null", the vacation response is
skipping to change at page 63, line 26 skipping to change at page 72, line 7
o *htmlBody*: "String|null" The HTML message to send in response to o *htmlBody*: "String|null" The HTML message to send in response to
emails when the vacation response is enabled. If this is "null", emails when the vacation response is enabled. If this is "null",
when the vacation message is sent an HTML body part MAY be when the vacation message is sent an HTML body part MAY be
generated from the _textBody_, or the server MAY choose to send generated from the _textBody_, or the server MAY choose to send
the response as plain-text only. the response as plain-text only.
The following JMAP methods are supported: The following JMAP methods are supported:
8.1. VacationResponse/get 8.1. VacationResponse/get
Standard _/get_ method. Standard "/get" method.
There MUST only be exactly one VacationResponse object in an account. There MUST only be exactly one VacationResponse object in an account.
It MUST have the id ""singleton"". It MUST have the id "singleton".
8.2. VacationResponse/set 8.2. VacationResponse/set
Standard _/set_ method. Standard "/set" method.
9. Security considerations 9. Security considerations
All security considerations of JMAP {TODO: insert RFC ref} apply to All security considerations of JMAP {TODO: insert RFC ref} apply to
this specification. this specification.
9.1. EmailBodyPart value 9.1. EmailBodyPart value
Service providers typically perform security filtering on incoming Service providers typically perform security filtering on incoming
email and it's important the detection of content-type and charset email and it's important the detection of content-type and charset
skipping to change at page 66, line 37 skipping to change at page 75, line 17
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 and
other technologies. The technologies work better when they have more other technologies. The technologies work better when they have more
information about the client connection. If JMAP email submission is information about the client connection. If JMAP email submission is
implemented as a proxy to an SMTP Submission server, it is useful to implemented as a proxy to an SMTP Submission server, it is useful to
communicate this information from the JMAP proxy to the submission communicate this information from the JMAP proxy to the submission
server. The de-facto XCLIENT extension to SMTP can be used to do server. The de-facto XCLIENT extension to SMTP
(<http://www.postfix.org/XCLIENT_README.html>) can be used to do
this, but use of an authenticated channel is recommended to limit use this, but use of an authenticated channel is recommended to limit use
of that extension to explicitly authorized proxies. JMAP servers of that extension to explicitly authorized proxies.
that proxy to an SMTP Submission server SHOULD allow use of the
_submissions_ port [RFC8314] and SHOULD implement SASL PLAIN over TLS JMAP servers that proxy to an SMTP Submission server SHOULD allow use
[RFC4616] and/or TLS client certificate authentication with SASL of the _submissions_ port [RFC8314] and SHOULD implement SASL PLAIN
EXTERNAL [RFC4422] appendix A. Implementation of a mechanism similar over TLS [RFC4616] and/or TLS client certificate authentication with
to SMTP XCLIENT is strongly encouraged. SASL EXTERNAL [RFC4422] appendix A. Implementation of a mechanism
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-party
products that address security issues including anti-virus/anti-spam, products that address security issues including anti-virus/anti-spam,
reputation protection, compliance archiving, and data loss 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.
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
Intended use: common Intended use: common
Change Controller: IETF Change Controller: IETF
Security and privacy considerations: this document, section 9 Security and privacy considerations: this document, section 9
10.2. IMAP and JMAP Keywords Registry 10.2. JMAP capability registration for "submission"
IANA will register 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
10.3. JMAP capability registration for "vacationresponse"
IANA will register 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 This document makes two changes to the IMAP keywords registry as
defined in [RFC5788]. defined in [RFC5788].
First, the name of the registry is changed to the "IMAP and JMAP First, the name of the registry is changed to the "IMAP and JMAP
keywords Registry". keywords Registry".
Second, a scope column is added to the template and registry Second, a scope column is added to the template and registry
indicating whether a keyword applies to IMAP-only, JMAP-only, both, indicating whether a keyword applies to IMAP-only, JMAP-only, both,
or reserved. All keywords presently in the IMAP keyword registry or reserved. All keywords presently in the IMAP keyword registry
skipping to change at page 68, line 5 skipping to change at page 77, line 12
IMAP clients MAY silently ignore any keywords marked JMAP-only or IMAP clients MAY silently ignore any keywords marked JMAP-only or
reserved in the event they appear in protocol. JMAP clients MAY reserved in the event they appear in protocol. JMAP clients MAY
silently ignore any keywords marked IMAP-only or reserved in the silently ignore any keywords marked IMAP-only or reserved in the
event they appear in protocol. event they appear in protocol.
New JMAP-only keywords are registered in the following sub-sections. New JMAP-only keywords are registered in the following sub-sections.
These keywords correspond to IMAP system keywords and are thus not These keywords correspond to IMAP system keywords and are thus not
appropriate for use in IMAP. These keywords can not be subsequently appropriate for use in IMAP. These keywords can not be subsequently
registered for use in IMAP except via standards action. registered for use in IMAP except via standards action.
10.2.1. Registration of JMAP keyword '$draft' 10.4.1. Registration of JMAP keyword '$draft'
This registers the JMAP-only keyword '$draft' in the "IMAP and JMAP This registers the JMAP-only keyword '$draft' in the "IMAP and JMAP
keywords Registry". keywords Registry".
Keyword name: "$draft" Keyword name: "$draft"
Scope: JMAP-only Scope: JMAP-only
Purpose (description): This is set when the user wants to treat the Purpose (description): This is set when the user wants to treat the
message as a draft the user is composing. This is the JMAP message as a draft the user is composing. This is the JMAP
skipping to change at page 68, line 45 skipping to change at page 78, line 4
Related keywords: None Related keywords: None
Related IMAP/JMAP Capabilities: SPECIAL-USE [RFC6154] Related IMAP/JMAP Capabilities: SPECIAL-USE [RFC6154]
Security Considerations: A server implementing this keyword as a Security Considerations: A server implementing this keyword as a
shared keyword may disclose that a user considers the message a draft shared keyword may disclose that a user considers the message a draft
message. This information would be exposed to other users with read message. This information would be exposed to other users with read
permission for the mailbox keywords. permission for the mailbox keywords.
Published specification (recommended): this document Published specification (recommended): this document
Person & email address to contact for further information: (editor- Person & email address to contact for further information: (editor-
contact-goes-here) contact-goes-here)
Intended usage: COMMON Intended usage: COMMON
Owner/Change controller: IESG Owner/Change controller: IESG
10.2.2. Registration of JMAP keyword '$seen' 10.4.2. Registration of JMAP keyword '$seen'
This registers the JMAP-only keyword '$seen' in the "IMAP and JMAP This registers the JMAP-only keyword '$seen' in the "IMAP and JMAP
keywords Registry". keywords Registry".
Keyword name: "$seen" Keyword name: "$seen"
Scope: JMAP-only Scope: JMAP-only
Purpose (description): This is set when the user wants to treat the 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. message as read. This is the JMAP equivalent of the IMAP \Seen flag.
skipping to change at page 69, line 47 skipping to change at page 79, line 5
Published specification (recommended): this document Published specification (recommended): this document
Person & email address to contact for further information: (editor- Person & email address to contact for further information: (editor-
contact-goes-here) contact-goes-here)
Intended usage: COMMON Intended usage: COMMON
Owner/Change controller: IESG Owner/Change controller: IESG
10.2.3. Registration of JMAP keyword '$flagged' 10.4.3. Registration of JMAP keyword '$flagged'
This registers the JMAP-only keyword '$flagged' in the "IMAP and JMAP This registers the JMAP-only keyword '$flagged' in the "IMAP and JMAP
keywords Registry". keywords Registry".
Keyword name: "$flagged" Keyword name: "$flagged"
Scope: JMAP-only Scope: JMAP-only
Purpose (description): This is set when the user wants to treat the Purpose (description): This is set when the user wants to treat the
message as flagged for urgent/special attention. This is the JMAP message as flagged for urgent/special attention. This is the JMAP
equivalent of the IMAP \Flagged flag. equivalent of the IMAP \Flagged flag.
Private or Shared on a server: BOTH Private or Shared on a server: BOTH
Is it an advisory keyword or may it cause an automatic action: Is it an advisory keyword or may it cause an automatic action:
Automatic. If the account has a mailbox marked with the \Flagged Automatic. If the account has a mailbox marked with the \Flagged
skipping to change at page 70, line 40 skipping to change at page 79, line 48
Published specification (recommended): this document Published specification (recommended): this document
Person & email address to contact for further information: (editor- Person & email address to contact for further information: (editor-
contact-goes-here) contact-goes-here)
Intended usage: COMMON Intended usage: COMMON
Owner/Change controller: IESG Owner/Change controller: IESG
10.2.4. Registration of JMAP keyword '$answered' 10.4.4. Registration of JMAP keyword '$answered'
This registers the JMAP-only keyword '$answered' in the "IMAP and This registers the JMAP-only keyword '$answered' in the "IMAP and
JMAP keywords Registry". JMAP keywords Registry".
Keyword name: "$answered" Keyword name: "$answered"
Scope: JMAP-only Scope: JMAP-only
Purpose (description): This is set when the message has been Purpose (description): This is set when the message has been
answered. answered.
skipping to change at page 71, line 34 skipping to change at page 80, line 41
Published specification (recommended): this document Published specification (recommended): this document
Person & email address to contact for further information: (editor- Person & email address to contact for further information: (editor-
contact-goes-here) contact-goes-here)
Intended usage: COMMON Intended usage: COMMON
Owner/Change controller: IESG Owner/Change controller: IESG
10.2.5. Registration of '$recent' Keyword 10.4.5. Registration of '$recent' keyword
This registers the keyword '$recent' in the "IMAP and JMAP keywords This registers the keyword '$recent' in the "IMAP and JMAP keywords
Registry". Registry".
Keyword name: "$recent" Keyword name: "$recent"
Scope: reserved Scope: reserved
Purpose (description): This keyword is not used to avoid confusion Purpose (description): This keyword is not used to avoid confusion
with the IMAP \Recent system flag. with the IMAP \Recent system flag.
Published specification (recommended): this document Published specification (recommended): this document
Person & email address to contact for further information: (editor- Person & email address to contact for further information: (editor-
contact-goes-here) contact-goes-here)
Owner/Change controller: IESG Owner/Change controller: IESG
10.5. JMAP Error Codes registry
The following sub-sections register several new error codes in the
JMAP Error Codes registry, as defined in RFC XXXX.
10.5.1. mailboxHasChild
JMAP Error Code: mailboxHasChild
Intended use: common
Change controller: IETF
Reference: This document, section 2.5
10.5.2. mailboxHasEmail
JMAP Error Code: mailboxHasEmail
Intended use: common
Change controller: IETF
Reference: This document, section 2.5
10.5.3. blobNotFound
JMAP Error Code: blobNotFound
Intended use: common
Change controller: IETF
Reference: This document, section 4.6
10.5.4. tooManyKeywords
JMAP Error Code: tooManyKeywords
Intended use: common
Change controller: IETF
Reference: This document, section 4.6
10.5.5. tooManyMailboxes
JMAP Error Code: tooManyMailboxes
Intended use: common
Change controller: IETF
Reference: This document, section 4.6
10.5.6. emailNotFound
JMAP Error Code: emailNotFound
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.7. emailTooLarge
JMAP Error Code: emailTooLarge
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.8. invalidEmail
JMAP Error Code: invalidEmail
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.9. tooManyRecipients
JMAP Error Code: tooManyRecipients
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.10. noRecipients
JMAP Error Code: noRecipients
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.11. invalidRecipients
JMAP Error Code: invalidRecipients
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.12. forbiddenMailFrom
JMAP Error Code: forbiddenMailFrom
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
10.5.13. forbiddenFrom
JMAP Error Code: forbiddenFrom
Intended use: common
Change controller: IETF
Reference: This document, sections 6.3 and 7.5
10.5.14. forbiddenToSend
JMAP Error Code: forbiddenToSend
Intended use: common
Change controller: IETF
Reference: This document, section 7.5
11. References 11. References
11.1. Normative References 11.1. Normative References
[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
skipping to change at page 73, line 5 skipping to change at page 85, line 18
<https://www.rfc-editor.org/info/rfc2557>. <https://www.rfc-editor.org/info/rfc2557>.
[RFC2852] Newman, D., "Deliver By SMTP Service Extension", RFC 2852, [RFC2852] Newman, D., "Deliver By SMTP Service Extension", RFC 2852,
DOI 10.17487/RFC2852, June 2000, DOI 10.17487/RFC2852, June 2000,
<https://www.rfc-editor.org/info/rfc2852>. <https://www.rfc-editor.org/info/rfc2852>.
[RFC3282] Alvestrand, H., "Content Language Headers", RFC 3282, [RFC3282] Alvestrand, H., "Content Language Headers", RFC 3282,
DOI 10.17487/RFC3282, May 2002, DOI 10.17487/RFC3282, May 2002,
<https://www.rfc-editor.org/info/rfc3282>. <https://www.rfc-editor.org/info/rfc3282>.
[RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet:
Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002,
<https://www.rfc-editor.org/info/rfc3339>.
[RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service [RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service
Extension for Delivery Status Notifications (DSNs)", Extension for Delivery Status Notifications (DSNs)",
RFC 3461, DOI 10.17487/RFC3461, January 2003, RFC 3461, DOI 10.17487/RFC3461, January 2003,
<https://www.rfc-editor.org/info/rfc3461>. <https://www.rfc-editor.org/info/rfc3461>.
[RFC3463] Vaudreuil, G., "Enhanced Mail System Status Codes", [RFC3463] Vaudreuil, G., "Enhanced Mail System Status Codes",
RFC 3463, DOI 10.17487/RFC3463, January 2003, RFC 3463, DOI 10.17487/RFC3463, January 2003,
<https://www.rfc-editor.org/info/rfc3463>. <https://www.rfc-editor.org/info/rfc3463>.
[RFC3464] Moore, K. and G. Vaudreuil, "An Extensible Message Format [RFC3464] Moore, K. and G. Vaudreuil, "An Extensible Message Format
for Delivery Status Notifications", RFC 3464, for Delivery Status Notifications", RFC 3464,
DOI 10.17487/RFC3464, January 2003, DOI 10.17487/RFC3464, January 2003,
<https://www.rfc-editor.org/info/rfc3464>. <https://www.rfc-editor.org/info/rfc3464>.
[RFC3798] Hansen, T., Ed. and G. Vaudreuil, Ed., "Message [RFC3798] Hansen, T., Ed. and G. Vaudreuil, Ed., "Message
Disposition Notification", RFC 3798, DOI 10.17487/RFC3798, Disposition Notification", RFC 3798, DOI 10.17487/RFC3798,
May 2004, <https://www.rfc-editor.org/info/rfc3798>. May 2004, <https://www.rfc-editor.org/info/rfc3798>.
[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>.
[RFC4422] Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple [RFC4422] Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
Authentication and Security Layer (SASL)", RFC 4422, Authentication and Security Layer (SASL)", RFC 4422,
DOI 10.17487/RFC4422, June 2006, DOI 10.17487/RFC4422, June 2006,
<https://www.rfc-editor.org/info/rfc4422>. <https://www.rfc-editor.org/info/rfc4422>.
[RFC4616] Zeilenga, K., Ed., "The PLAIN Simple Authentication and [RFC4616] Zeilenga, K., Ed., "The PLAIN Simple Authentication and
Security Layer (SASL) Mechanism", RFC 4616, Security Layer (SASL) Mechanism", RFC 4616,
DOI 10.17487/RFC4616, August 2006, DOI 10.17487/RFC4616, August 2006,
<https://www.rfc-editor.org/info/rfc4616>. <https://www.rfc-editor.org/info/rfc4616>.
skipping to change at page 75, line 16 skipping to change at page 87, line 26
[1] TODO [1] TODO
[2] https://www.iana.org/assignments/imap-keywords/imap- [2] https://www.iana.org/assignments/imap-keywords/imap-
keywords.xhtml keywords.xhtml
[3] https://www.w3.org/TR/CSP3/ [3] https://www.w3.org/TR/CSP3/
[4] https://www.w3.org/TR/referrer-policy/ [4] https://www.w3.org/TR/referrer-policy/
Author's Address Authors' Addresses
Neil Jenkins Neil Jenkins
FastMail FastMail
PO Box 234, Collins St West PO Box 234, Collins St West
Melbourne VIC 8007 Melbourne VIC 8007
Australia Australia
Email: neilj@fastmailteam.com Email: neilj@fastmailteam.com
URI: https://www.fastmail.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
 End of changes. 206 change blocks. 
903 lines changed or deleted 1449 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/