draft-ietf-jmap-mail-04.txt   draft-ietf-jmap-mail-05.txt 
JMAP N. Jenkins JMAP N. Jenkins
Internet-Draft FastMail Internet-Draft FastMail
Updates: 5788 (if approved) March 5, 2018 Updates: 5788 (if approved) May 9, 2018
Intended status: Standards Track Intended status: Standards Track
Expires: September 6, 2018 Expires: November 10, 2018
JMAP for Mail JMAP for Mail
draft-ietf-jmap-mail-04 draft-ietf-jmap-mail-05
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 September 6, 2018. This Internet-Draft will expire on November 10, 2018.
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
skipping to change at page 2, line 34 skipping to change at page 2, line 34
4.1. Properties of the Email object . . . . . . . . . . . . . 12 4.1. Properties of the Email object . . . . . . . . . . . . . 12
4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 12 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 12
4.1.2. Header fields . . . . . . . . . . . . . . . . . . . . 14 4.1.2. Header fields . . . . . . . . . . . . . . . . . . . . 14
4.1.3. Body parts . . . . . . . . . . . . . . . . . . . . . 19 4.1.3. Body parts . . . . . . . . . . . . . . . . . . . . . 19
4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 26 4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 28 4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 28
4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 29 4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 29
4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 30 4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 30
4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 30 4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 30
4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 32 4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 32
4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 33 4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 34
4.4.4. Response . . . . . . . . . . . . . . . . . . . . . . 34 4.4.4. Response . . . . . . . . . . . . . . . . . . . . . . 34
4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 34 4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 34
4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 34 4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 34
4.7. Email/import . . . . . . . . . . . . . . . . . . . . . . 35 4.7. Email/import . . . . . . . . . . . . . . . . . . . . . . 37
4.8. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 37 4.8. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 38
4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 39 4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 40
5. Email submission . . . . . . . . . . . . . . . . . . . . . . 40 5. Email submission . . . . . . . . . . . . . . . . . . . . . . 42
5.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 45 5.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 46
5.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 45 5.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 46
5.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 45 5.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 46
5.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 45 5.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 47
5.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 46 5.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 47
6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 47 6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 48 6.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 50
6.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 48 6.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 50
6.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 49 6.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 50
7. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 49 7. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 51
7.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 50 7.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 51
8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 51 8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 52
8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 52 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 53
8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 52 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 53
9. Security considerations . . . . . . . . . . . . . . . . . . . 52 9. Security considerations . . . . . . . . . . . . . . . . . . . 53
9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 52 9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 53
10. References . . . . . . . . . . . . . . . . . . . . . . . . . 52 9.2. HTML email display . . . . . . . . . . . . . . . . . . . 54
10.1. Normative References . . . . . . . . . . . . . . . . . . 52 9.3. Email submission . . . . . . . . . . . . . . . . . . . . 56
10.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 55 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 57
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 55 10.1. Normative References . . . . . . . . . . . . . . . . . . 57
10.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 60
1. Introduction 1. Introduction
JMAP <https://tools.ietf.org/html/draft-ietf-jmap-core-03> is a JMAP <https://tools.ietf.org/html/draft-ietf-jmap-core-03> 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 44 skipping to change at page 4, line 48
1.3. Terminology 1.3. 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.4. Addition 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 spec. Servers supporting _this_
specification MUST add a property called "ietf:jmapmail" to the specification MUST add a property called "urn:ietf:params:jmap:mail"
capabilities object. The value of this property is an object which to the capabilities object. The value of this property is an object
MUST contain the following information on server capabilities: which MUST contain the following information on server capabilities:
o *maxMailboxesPerEmail*: "Number|null" The maximum number of o *maxMailboxesPerEmail*: "Number|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*: "Number" The maximum total size of
attachments, in octets, allowed for a single email. A server MAY attachments, in octets, allowed for a single email. A server MAY
still reject emails with a lower attachment size total (for still reject emails with a lower attachment size total (for
example, if the body includes several megabytes of text, causing example, if the body includes several megabytes of text, causing
skipping to change at page 6, line 32 skipping to change at page 6, line 34
For compatibility with IMAP, an email MUST belong to one or more For compatibility with IMAP, an email MUST belong to one or more
mailboxes. The email id does not change if the email changes mailboxes. The email id does not change if the email changes
mailboxes. mailboxes.
A *Mailbox* object has the following properties: A *Mailbox* object has the following properties:
o *id*: "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 256 octets in size. Servers character in length and maximum 255 octets in size. Servers
SHOULD forbid sibling Mailboxes with the same name. Servers MAY SHOULD forbid sibling Mailboxes with the same name. Servers MAY
reject names that violate server policy (e.g., names containing reject names that violate server policy (e.g., names containing
slash (/) or control characters). slash (/) 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
skipping to change at page 9, line 40 skipping to change at page 9, line 42
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 *hasRole*: "Boolean" If this is "true", a Mailbox matches if it
has a non-"null" value for its _role_ property. has a non-"null" value for its _role_ property. If "false", it
must has a "null" _role_ value to match.
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:
o "sortOrder" o "sortOrder"
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.
skipping to change at page 15, line 19 skipping to change at page 15, line 19
If any decodings fail, the parser SHOULD insert a unicode If any decodings fail, the parser SHOULD insert a unicode
replacement character (U+FFFD) and attempt to continue as much as replacement character (U+FFFD) and attempt to continue as much as
possible. To prevent obviously nonsense behaviour, which can lead possible. To prevent obviously nonsense behaviour, which can lead
to interoperability issues, this form may only be fetched or set to interoperability issues, this form may only be fetched or set
for the following header fields: for the following header fields:
* Subject * Subject
* Comment * Comment
* List-Id
* Any header not defined in [RFC5322] or [RFC2369] * Any header not defined in [RFC5322] or [RFC2369]
o *Addresses* ("EmailAddress[]") The header is parsed as an o *Addresses* ("EmailAddress[]") The header is parsed as an
"address-list" value, as specified in [RFC5322] section 3.4, into "address-list" value, as specified in [RFC5322] section 3.4, into
the "EmailAddress[]" type. The *EmailAddress* object has the the "EmailAddress[]" type. The *EmailAddress* object has the
following properties: following properties:
* *name*: "String|null" The _display-name_ of the [RFC5322] * *name*: "String|null" The _display-name_ of the [RFC5322]
_mailbox_ or _group_, or "null" if none. If this is a _quoted- _mailbox_ or _group_, or "null" if none. If this is a _quoted-
string_: string_:
skipping to change at page 16, line 33 skipping to change at page 16, line 37
o Resent-To o Resent-To
o Resent-Cc o Resent-Cc
o Resent-Bcc o Resent-Bcc
o Any header not defined in [RFC5322] or [RFC2369] o Any header not defined in [RFC5322] or [RFC2369]
o *MessageIds* ("String[]|null") The header is parsed as a list of o *MessageIds* ("String[]|null") The header is parsed as a list of
"msg-id" values, as specified in [RFC5322] section 3.6.4, into the "msg-id" values, as specified in [RFC5322] section 3.6.4, into the
"String[]" type. If parsing fails, the value is "null". "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 To prevent obviously nonsense behaviour, which can lead to
interoperability issues, this form may only be fetched or set for the interoperability issues, this form may only be fetched or set for the
following header fields: following header fields:
o Message-ID o Message-ID
o In-Reply-To o In-Reply-To
o References o References
skipping to change at page 17, line 15 skipping to change at page 17, line 18
To prevent obviously nonsense behaviour, which can lead to To prevent obviously nonsense behaviour, which can lead to
interoperability issues, this form may only be fetched or set for the interoperability issues, this form may only be fetched or set for the
following header fields: following header fields:
o Date o Date
o Resent-Date o Resent-Date
o Any header not defined in [RFC5322] or [RFC2369] o Any header not defined in [RFC5322] or [RFC2369]
o *URL* ("String|null") The header is parsed as a URL, as described o *URLs* ("String[]|null") The header is parsed as a list of URLs,
in [RFC2369], into the "String" type. This does not include the as described in [RFC2369], into the "String[]" type. Values do
surrounding angle brackets or any comments in the header with the not include the surrounding angle brackets or any comments in the
URL. If parsing fails, the value is "null". header with the URLs. If parsing fails, the value is "null".
To prevent obviously nonsense behaviour, which can lead to To prevent obviously nonsense behaviour, which can lead to
interoperability issues, this form may only be fetched or set for the interoperability issues, this form may only be fetched or set for the
following header fields: following header fields:
o List-Help o List-Help
o List-Unsubscribe o List-Unsubscribe
o List-Subscribe o List-Subscribe
skipping to change at page 19, line 47 skipping to change at page 19, line 50
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.3. 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" Identifies this part uniquely within the Email. o *partId*: "String|null" Identifies this part uniquely within the
This is scoped to the _emailId_ and has no meaning outside of the Email. This is scoped to the _emailId_ and has no meaning outside
JMAP Email object representation. of the JMAP Email object representation. This is "null" if, and
only if, the part is of type "multipart/*".
o *blobId*: "String" The id references 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]). Note, two parts may be Encoding_ (as defined in [RFC2045]), or "null" if, and only if,
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*: "Number" 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[]" (immutable) This is a list of all o *headers*: "EmailHeader[]" This is a list of all header fields in
header fields in the part, in the order they appear. The values the part, in the order they appear. The values are in _Raw_ form.
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 "null". CFWS is removed and any the part, if present, otherwise the implicit type as per the MIME
parameters are stripped. standard ("text/plain", or "message/rfc822" if inside a
"multipart/digest"). CFWS is removed and any parameters are
stripped.
o *charset*: "String|null" The value of the charset parameter of the o *charset*: "String|null" The value of the charset parameter of the
_Content-Type_ header field, if present. _Content-Type_ header field, if present.
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 is removed. This the part, if present, otherwise "null". CFWS and surrounding
may be used to reference the content from within an html body part angle brackets ("<>") are removed. This may be used to reference
using the "cid:" protocol. the content from within an html body part using the "cid:"
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[]" (optional) If type is "multipart/*",
this contains the body parts of each child. this contains the body parts of each child.
In addition, the client may request/send EmailBodyPart properties
representing individual header fields, following the same syntax and
semantics as for the Email object, e.g. "header:Content-Type".
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 o *bodyStructure*: "EmailBodyPart" (immutable) This is the full MIME
MIME structure of the message body, including sub parts but not structure of the message body, including sub parts but not
recursing into "message/rfc822" or "message/global" parts. recursing into "message/rfc822" or "message/global" parts.
o *bodyValues*: "String[BodyValue]" (immutable) This is a map of o *bodyValues*: "String[BodyValue]" (immutable) This is a map of
_partId_ to an *EmailBodyValue* object for none, some or all _partId_ to an *EmailBodyValue* object for none, some or all
"text/*" parts. Which parts are included and whether the value is "text/*" parts. Which parts are included and whether the value is
truncated is determined by various arguments to _Email/get_ and truncated is determined by various arguments to _Email/get_ and
_Email/parse_. An *EmailBodyValue* object has the following _Email/parse_. An *EmailBodyValue* object has the following
properties: properties:
* *value*: "String" The value of the body part after decoding * *value*: "String" The value of the body part after decoding
_Content-Transport-Encoding_ and decoding the _Content-Type_ _Content-Transport-Encoding_ and decoding the _Content-Type_
charset, if known to the server. The server MAY use heuristics charset, if known to the server, and with any CRLF replaced
to determine the charset to use for decoding if the charset is with a single LF. The server MAY use heuristics to determine
unknown, or if no charset is given, or if it believes the the charset to use for decoding if the charset is unknown, or
charset given is incorrect. Decoding is best-effort and SHOULD if no charset is given, or if it believes the charset given is
insert the unicode replacement character (U+FFFD) and continue incorrect. Decoding is best-effort and SHOULD insert the
when a malformed section is encountered. unicode replacement character (U+FFFD) and continue when a
malformed section is encountered.
* *isEncodingProblem*: "Boolean" This is "true" if malformed * *isEncodingProblem*: "Boolean" (default: "false") This is
sections were found while decoding the charset, or the charset "true" if malformed sections were found while decoding the
was unknown. charset, or the charset was unknown.
* *isTruncated*: "Boolean" This is "true" if the _value_ has been * *isTruncated*: "Boolean" (default: "false") This is "true" if
truncated. the _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" and "image/*" parts to display (sequentially) as the "text/html", "image/*", "audio/*" and/or "video/*" parts to
message body, with a preference for "text/plain" when alternative display (sequentially) as the message body, with a preference for
versions are available. "text/plain" when alternative versions are available.
o *htmlBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", o *htmlBody*: "EmailBodyPart[]" (immutable) A list of "text/plain",
"text/html" and "image/*" parts to display (sequentially) as the "text/html", "image/*", "audio/*" and/or "video/*" parts to
message body, with a preference for "text/html" when alternative display (sequentially) as the message body, with a preference for
versions are available. "text/html" when alternative versions are available.
o *attachedEmails*: "EmailBodyPart[]" (immutable) A list of all o *attachedEmails*: "EmailBodyPart[]" (immutable) A list of all
parts of type "message/rfc822" or "message/global". Note, this parts of type "message/rfc822" or "message/global". Note, this
*does not* recurse, so the parts within these are not included. *does not* recurse, so the parts within these are not included.
The attached message may be fetched using the Email/parse method The attached message may be fetched using the Email/parse method
and the blobId. and the blobId.
o *attachedFiles*: "EmailBodyPart[]" (immutable) A list of all parts o *attachedFiles*: "EmailBodyPart[]" (immutable) A list of all parts
in _bodyStructure_, traversing depth-first, which satisfy either in _bodyStructure_, traversing depth-first, which satisfy either
of the following conditions: of the following conditions:
* not of type "multipart/*" and not included in _attachedEmails_, * not of type "multipart/*" and not included in _attachedEmails_,
_textBody_ or _htmlBody_ _textBody_ or _htmlBody_
* of type "image/*" and not in both _textBody_ and _htmlBody_ * of type "image/*", "audio/*" or "video/*" and not in both
_textBody_ and _htmlBody_
Note, an HTML body part may reference image parts in attachedFiles Note, an HTML body part may reference image parts in attachedFiles
using "cid:" links to reference the _Content-Id_ or by referencing using "cid:" links to reference the _Content-Id_ or by referencing
the _Content-Location_. the _Content-Location_.
o *hasAttachment*: "Boolean" (immutable; server-set) This is "true" o *hasAttachment*: "Boolean" (immutable; server-set) This is "true"
if there are one or more parts in the message that a client UI if there are one or more parts in the message that a client UI
should offer as downloadable. A server SHOULD set hasAttachment should offer as downloadable. A server SHOULD set hasAttachment
if either: if either:
skipping to change at page 22, line 34 skipping to change at page 22, line 48
* The _attachedFiles_ list contains at least one item that does * The _attachedFiles_ list contains at least one item that does
not have "Content-Disposition: inline". The server MAY ignore not have "Content-Disposition: inline". The server MAY ignore
parts in this list that are processed automatically in some parts in this list that are processed automatically in some
way, or are referenced as embedded images in one of the "text/ way, or are referenced as embedded images in one of the "text/
html" parts of the message. html" parts of the message.
The server MAY set hasAttachment based on implementation-defined The server MAY set hasAttachment based on implementation-defined
or site configurable heuristics. or site configurable heuristics.
o *preview*: "String" (immutable; server-set) Up to 256 characters o *preview*: "String" (immutable; server-set) Up to 255 octets of
of plain text, summarising the message body. This is intended to plain text, summarising the message body. This is intended to be
be shown as a preview line on a mailbox listing, and may be shown as a preview line on a mailbox listing, and may be truncated
truncated when shown. The server may choose which part of the when shown. The server may choose which part of the message to
message to include in the preview, for example skipping quoted include in the preview, for example skipping quoted sections and
sections and salutations and collapsing white-space can result in salutations and collapsing white-space can result in a more useful
a more useful preview. preview.
MIME structures are arbitrary nested trees of documents, but the MIME structures are arbitrary nested trees of documents, but the
majority of email clients present a model of an email body (normally majority of email clients present a model of an email body (normally
plain text or HTML), with a set of attachments. Interpreting the plain text or HTML), with a set of attachments. Interpreting the
MIME structure to form this flat model represents considerable MIME structure to form this flat model represents considerable
difficulty and causes inconsistency between clients. Therefore in difficulty and causes inconsistency between clients. Therefore in
addition to the _bodyStructure_ property, which gives the full tree, addition to the _bodyStructure_ property, which gives the full tree,
the Email object contains 4 alternate properties with flat lists of the Email object contains 4 alternate properties with flat lists of
body parts: body parts:
o _textBody_/_htmlBody_: These provide a list of parts that should o _textBody_/_htmlBody_: These provide a list of parts that should
be rendered as the "body" of the message. This is a list rather be rendered as the "body" of the message. This is a list rather
than a single part as messages may have headers and/or footers than a single part as messages may have headers and/or footers
appended/prepended as separate parts as they are transmitted, and appended/prepended as separate parts as they are transmitted, and
some clients send text and images intended to be displayed inline some clients send text and images, or even videos and sound clips,
in the body as multiple parts rather than a single HTML part with intended to be displayed inline in the body as multiple parts
referenced images. rather than a single HTML part with referenced images.
Because MIME allows for multiple representations of the same data Because MIME allows for multiple representations of the same data
(using "multipart/alternative"), there is a textBody property (which (using "multipart/alternative"), there is a textBody property (which
prefers a plain text representation) and an htmlBody property (which prefers a plain text representation) and an htmlBody property (which
prefers an HTML representation) to accommodate the two most common prefers an HTML representation) to accommodate the two most common
client requirements. The same part may appear in both lists where client requirements. The same part may appear in both lists where
there is no alternative between the two. there is no alternative between the two.
o _attachedEmails_/_attachedFiles_: These provide a list of parts o _attachedEmails_/_attachedFiles_: These provide a list of parts
that should be presented as "attachments" to the message. Emails that should be presented as "attachments" to the message. Emails
skipping to change at page 23, line 45 skipping to change at page 24, line 13
bodyStructure, textBody and htmlBody. bodyStructure, textBody and htmlBody.
The exact algorithm for decomposing bodyStructure into textBody, The exact algorithm for decomposing bodyStructure into textBody,
htmlBody, attachedEmails and attachedFiles part lists is not htmlBody, attachedEmails and attachedFiles part lists is not
mandated, as this is a quality-of-service implementation issue and mandated, as this is a quality-of-service implementation issue and
likely to require workarounds for malformed content discovered over likely to require workarounds for malformed content discovered over
time. However, the following algorithm (expressed here in time. However, the following algorithm (expressed here in
JavaScript) is suggested as a starting point, based on real-world JavaScript) is suggested as a starting point, based on real-world
experience: experience:
function isInlineMediaType ( type ) {
return type.startsWith( 'image/' ) ||
type.startsWith( 'audio/' ) ||
type.startsWith( 'video/' );
}
function parseStructure ( parts, multipartType, inAlternative, function parseStructure ( parts, multipartType, inAlternative,
htmlBody, textBody, attachedEmails, attachedFiles ) { htmlBody, textBody, attachedEmails, attachedFiles ) {
// For multipartType == alternative // For multipartType == alternative
let textLength = textBody ? textBody.length : -1; let textLength = textBody ? textBody.length : -1;
let htmlLength = htmlBody ? htmlBody.length : -1; let htmlLength = htmlBody ? htmlBody.length : -1;
for ( let i = 0; i < parts.length; i += 1 ) { for ( let i = 0; i < parts.length; i += 1 ) {
let part = parts[i]; let part = parts[i];
let isMultipart = part.type.startsWith( 'multipart/' ); let isMultipart = part.type.startsWith( 'multipart/' );
// Is this a body part rather than an attachment // Is this a body part rather than an attachment
let isInline = part.disposition != "attachment" && let isInline = part.disposition != "attachment" &&
// Must be one of the allowed body types // Must be one of the allowed body types
( part.type == "text/plain" || ( part.type == "text/plain" ||
part.type == "text/html" || part.type == "text/html" ||
part.type.startsWith( 'image/' ) ) && isInlineMediaType( part.type ) &&
// If not the first part and has a filename, assume attachment
( i == 0 || !part.name ) &&
// If multipart/related, only the first part can be inline // If multipart/related, only the first part can be inline
( i > 0 || multipartType != 'related' ); // If a text part with a filename, and not the first item in the
// multipart, assume it is an attachment
( i === 0 ||
( multipartType != "related" &&
( isInlineMediaType( part.type ) || !part.name ) ) );
if ( isMultipart ) { if ( isMultipart ) {
let subMultiType = part.type.split( '/' )[1]; let subMultiType = part.type.split( '/' )[1];
parseStructure( part.subParts, subMultiType, parseStructure( part.subParts, subMultiType,
inAlternative || ( subMultiType == 'alternative' ), inAlternative || ( subMultiType == 'alternative' ),
htmlBody, textBody, attachedEmails, attachedFiles ); htmlBody, textBody, attachedEmails, attachedFiles );
} else if ( isInline ) { } else if ( isInline ) {
if ( inAlternative && part.type == 'text/plain' ) { if ( multipartType == 'alternative' ) {
htmlBody = null; switch ( part.type ) {
} case 'text/plain':
if ( inAlternative && part.type == 'text/html' ) { textBody.push( part );
textBody = null; break;
case 'text/html':
htmlBody.push( part );
break;
default:
attachedFiles.push( part );
break;
}
continue;
} else if ( inAlternative ) {
if ( part.type == 'text/plain' ) {
htmlBody = null;
}
if ( part.type == 'text/html' ) {
textBody = null;
}
} }
if ( textBody ) { if ( textBody ) {
textBody.push( part ); textBody.push( part );
} }
if ( htmlBody ) { if ( htmlBody ) {
htmlBody.push( part ); htmlBody.push( part );
} }
if ( ( !textBody || !htmlBody ) && if ( ( !textBody || !htmlBody ) &&
part.type.startsWith( 'image/' ) ) { isInlineMediaType( part.type ) {
attachedFiles.push( part ); attachedFiles.push( part );
} }
} else if ( part.type == 'message/rfc822' || } else if ( part.type == 'message/rfc822' ||
part.type == 'message/global' ) { part.type == 'message/global' ) {
attachedEmails.push( part ); attachedEmails.push( part );
} else { } else {
attachedFiles.push( part ); attachedFiles.push( part );
} }
if ( multipartType == 'alternative' ) { if ( multipartType == 'alternative' ) {
skipping to change at page 25, line 24 skipping to change at page 26, line 15
} }
} }
} }
// Usage: // Usage:
let htmlBody = []; let htmlBody = [];
let textBody = []; let textBody = [];
let attachedEmails = []; let attachedEmails = [];
let attachedFiles = []; let attachedFiles = [];
parseStructure( bodyStructure, 'mixed', false, parseStructure( [ bodyStructure ], 'mixed', false,
htmlBody, textBody, attachedEmails, attachedFiles ); htmlBody, textBody, attachedEmails, attachedFiles );
For instance, consider a message with both text and html versions For instance, consider a message with both text and html versions
that's then gone through a list software manager that attaches a that's then gone through a list software manager that attaches a
header/footer. It might have a MIME structure something like: header/footer. It might have a MIME structure something like:
multipart/mixed multipart/mixed
text/plain, content-disposition=inline - A text/plain, content-disposition=inline - A
multipart/mixed multipart/mixed
multipart/alternative multipart/alternative
skipping to change at page 26, line 40 skipping to change at page 27, line 26
o *maxBodyValueBytes*: "Number" (optional) If supplied by the o *maxBodyValueBytes*: "Number" (optional) If supplied by the
client, the value MUST be a positive integer greater than 0. If a client, the value MUST be a positive integer greater than 0. If a
value outside of this range is given, the server MUST reject the value outside of this range is given, the server MUST reject the
call with an "invalidArguments" error. When given, the _value_ call with an "invalidArguments" error. When given, the _value_
property of any EmailBodyValue object returned in _bodyValues_ property of any EmailBodyValue object returned in _bodyValues_
MUST be truncated if necessary so it does not exceed this number MUST be truncated if necessary so it does not exceed this number
of octets in size. The server MUST ensure the truncation results 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).
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:
[ "id", "blobId", "threadId", "mailboxIds", "keywords", "size", "receivedAt", "messageId", "inReplyTo", "references", "sender", "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", "attachedFiles", "attachedEmails" ] [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size", "receivedAt", "messageId", "inReplyTo", "references", "sender", "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", "attachedFiles", "attachedEmails" ]
The following properties are expected to be fast to fetch in a The following properties are expected to be fast to fetch in a
quality implementation: quality implementation:
o id o id
skipping to change at page 28, line 11 skipping to change at page 28, line 47
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:asURL" "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@bloggs.com"}],
"subject": "Dinner on Thursday?", "subject": "Dinner on Thursday?",
"receivedAt": "2013-10-13T14:12:00Z", "receivedAt": "2013-10-13T14:12:00Z",
"header:List-POST:asURL": "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",
"blobId": "319437193", "blobId": "319437193",
"size": 10343, "size": 10343,
"type": "text/plain" "type": "text/plain"
}], }],
"bodyValues": { "bodyValues": {
"1": { "1": {
"isEncodingProblem": false, "isEncodingProblem": false,
"isTruncated": true, "isTruncated": true,
"value": "<html><body><p>Hello ..." "value": "<html><body><p>Hello ..."
}, },
"2": { "2": {
"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.
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:
skipping to change at page 32, line 13 skipping to change at page 32, line 13
making them all the child of an AND filter operator). making them all the child of an AND filter operator).
The exact semantics for matching "String" fields is *deliberately not The exact semantics for matching "String" fields is *deliberately not
defined* to allow for flexibility in indexing implementation, subject defined* to allow for flexibility in indexing implementation, subject
to the following: to the following:
o Any syntactically correct [RFC2047] encoded sections of header o Any syntactically correct [RFC2047] encoded sections of header
fields with a known encoding SHOULD be decoded before attempting fields with a known encoding SHOULD be decoded before attempting
to match text. to match text.
o When searching inside a "text/html" body part, HTML tags and o When searching inside a "text/html" body part, any text considered
attributes SHOULD be ignored. markup rather than content SHOULD be ignored, including HTML tags
and most attributes, anything inside the "<head>" tag, CSS and
JavaScript. Attribute content intended for presentation to the
user such as "alt" and "title" SHOULD be considered in the search.
o Text SHOULD be matched in a case-insensitive manner. o Text SHOULD be matched in a case-insensitive manner.
o Text contained in either (but matched) single or double quotes o Text contained in either (but matched) single or double quotes
SHOULD be treated as a *phrase search*, that is a match is SHOULD be treated as a *phrase search*, that is a match is
required for that exact word or sequence of words, excluding the required for that exact word or sequence of words, excluding the
surrounding quotation marks. Use "\"", "\'" and "\\" to match a surrounding quotation marks. Use "\"", "\'" and "\\" to match a
literal """, "'" and "\" respectively in a phrase. literal """, "'" and "\" respectively in a phrase.
o Outside of a phrase, white-space SHOULD be treated as dividing o Outside of a phrase, white-space SHOULD be treated as dividing
skipping to change at page 33, line 38 skipping to change at page 33, line 40
Example sort: Example sort:
[{ [{
"property": "someInThreadHaveKeyword", "property": "someInThreadHaveKeyword",
"keyword": "$flagged", "keyword": "$flagged",
"isAscending": false, "isAscending": false,
}, { }, {
"property": "subject", "property": "subject",
"collation": "i;ascii-casemap" "collation": "i;ascii-casemap"
}, { }, {
"property": "receivedAt desc", "property": "receivedAt",
"isAscending": false, "isAscending": false,
}] }]
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
skipping to change at page 34, line 34 skipping to change at page 34, line 40
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 (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 headers. The client MUST NOT supply are a number of ways to specify the same information. To ensure that
conflicting information (for example, if a _headers_ property is the RFC5322 email to create is unambiguous, the following constraints
given, no other header field property may be given as these form a apply to Email objects submitted for creation:
complete set). Header fields MUST NOT be specified in parsed forms
that are forbidden for that field. Creation attempts that violate o The _headers_ property MUST NOT be given, on either the top-level
any of this MUST be rejected with an "invalidProperties" error. email or an EmailBodyPart - the client must set each header field
as an individual property.
o There MUST NOT be two properties that represent the same header
field (e.g. "header:from" and "from") within the Email or
particular EmailBodyPart.
o Header fields MUST NOT be specified in parsed forms that are
forbidden for that particular field.
o Header fields beginning "Content-" MUST NOT be specified on the
Email object, only on EmailBodyPart objects.
o If a bodyStructure property is given, there MUST NOT be textBody,
htmlBody, attachedFiles or attachedEmails properties.
o If given, the bodyStructure EmailBodyPart MUST NOT contain a
property representing a header field that is already defined on
the top-level Email object.
o If given, textBody MUST contain exactly one body part, of type
"text/plain".
o If given, htmlBody MUST contain exactly one body part, of type
"text/html".
o Within an EmailBodyPart:
* The client may specify a partId OR a blobId but not both. If a
partId is given, this partId MUST be present in the bodyValues
property.
* The charset property MUST be omitted if a partId is given (the
part's content is included in bodyValues and the server may
choose any appropriate encoding).
* The size property MUST be omitted if a partId is given. If a
blobId is given, it may be omitted, but otherwise MUST match
the size of the blob.
* A "Content-Transfer-Encoding" header field MUST NOT be given.
o Within an EmailBodyValue object, isEncodingProblem and isTruncated
MUST be either "false" or omitted.
Creation attempts that violate any of this SHOULD be rejected with an
"invalidProperties" error, however a server MAY choose to modify the
Email (e.g. choose between conflicting headers, use a different
content-encoding etc.) to comply with its requirements instead.
The server MAY also choose to set additional headers. If not The server MAY also choose to set additional headers. If not
included, the server MUST generate and set a "Message-ID" header included, the server MUST generate and set a "Message-ID" header
field in conformance with [RFC5322] section 3.6.4, and a "Date" field in conformance with [RFC5322] section 3.6.4, and a "Date"
header field in conformance with section 3.6.1. header field in conformance with section 3.6.1.
Other than making sure it conforms to the correct type, the server The final RFC5322 email generated may be invalid. For example, if it
MUST NOT attempt to validate _from_/_to_/_cc_/_bcc_ (e.g. checking if is a half-finished draft, the "To" field may data that does not
an email address is valid) when creating an email. This is to ensure currently conform to the required syntax for this header field. The
drafts can be saved at any point. message will be checked for strict conformance when submitted for
sending (see the EmailSubmission object description).
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
contain the _id_, _blobId_, _threadId_ and _size_ properties of the
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.
skipping to change at page 39, line 8 skipping to change at page 40, line 23
"fromAccountNotSupportedByMethod": The _fromAccountId_ given "fromAccountNotSupportedByMethod": The _fromAccountId_ given
corresponds to a valid account, but does not contain any mail data. corresponds to a valid account, but does not contain any mail data.
"toAccountNotSupportedByMethod": The _toAccountId_ given corresponds "toAccountNotSupportedByMethod": The _toAccountId_ given corresponds
to a valid account, but does not contain any mail data. 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 (excluding the metadata properties). Email objects. The following metadata properties on the Email
objects will be "null" if requested:
o id
o mailboxIds
o keywords
o receivedAt
The _threadId_ property of the Email MAY be present if the server can
calculate which thread the Email would be assigned to were it to be
imported. Otherwise, this too is "null" if fetched.
The _Email/parse_ method takes the following arguments: The _Email/parse_ method takes the following arguments:
o *accountId*: "String|null" The id of the Account to use. If o *accountId*: "String|null" The id of the Account to use. If
"null", the primary account is used. "null", the primary account is used.
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 the same value as the Email/get "properties" default defaults to: [ "messageId", "inReplyTo", "references", "sender",
argument. "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt",
"hasAttachment", "preview", "bodyValues", "textBody", "htmlBody",
"attachedFiles", "attachedEmails" ]
o *bodyProperties*: "String[]" (optional) A list of properties to o *bodyProperties*: "String[]" (optional) A list of properties to
fetch for each EmailBodyPart returned. If omitted, defaults to fetch for each EmailBodyPart returned. If omitted, defaults to
the same value as the Email/get "bodyProperties" default argument. the same 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
skipping to change at page 48, line 8 skipping to change at page 49, line 35
6. Identities 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 use when creating a new message from this identity. SHOULD use when creating a new message from this identity.
o *email*: "String" The "From" email address the client MUST use o *email*: "String" (immutable) The "From" email address the client
when creating a new message from this identity. This property is MUST use when creating a new message from this identity. The
immutable. The "email" property MAY alternatively be of the form value MAY alternatively be of the form "*@example.com", in which
"*@example.com", in which case the client may use any valid email case the client may use any valid email address ending in
address ending in "@example.com". "@example.com".
o *replyTo*: "Emailer[]|null" (default: "null") The Reply-To value o *replyTo*: "EmailAddress[]|null" (default: "null") The Reply-To
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*: "Emailer[]|null" (default: "null") The Bcc value the client o *bcc*: "EmailAddress[]|null" (default: "null") The Bcc value the
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.
See the "Addresses" header form description in the Email object for
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:
6.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.
skipping to change at page 49, line 43 skipping to change at page 51, line 25
o *emailId*: "String" The email id the snippet applies to. o *emailId*: "String" The email id the snippet applies to.
o *subject*: "String|null" If text from the filter matches the o *subject*: "String|null" If text from the filter matches the
subject, this is the subject of the email HTML-escaped, with subject, this is the subject of the email HTML-escaped, with
matching words/phrases wrapped in "<mark></mark>" tags. If it matching words/phrases wrapped in "<mark></mark>" tags. If it
does not match, this is "null". does not match, this is "null".
o *preview*: "String|null" If text from the filter matches the o *preview*: "String|null" If text from the filter matches the
plain-text or HTML body, this is the relevant section of the body plain-text or HTML body, this is the relevant section of the body
(converted to plain text if originally HTML), HTML-escaped, with (converted to plain text if originally HTML), HTML-escaped, with
matching words/phrases wrapped in "<mark></mark>" tags, up to 256 matching words/phrases wrapped in "<mark></mark>" tags. It MUST
characters long. If it does not match, this is "null". 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 o *attachments*: "String|null" If text from the filter matches the
text extracted from an attachment, this is the relevant section of text extracted from an attachment, this is the relevant section of
the attachment (converted to plain text), with matching words/ the attachment (converted to plain text), with matching words/
phrases wrapped in "<mark></mark>" tags, up to 256 characters phrases wrapped in "<mark></mark>" tags. It MUST NOT be bigger
long. If it does not match, this is "null". 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 It is server-defined what is a relevant section of the body for
preview. If the server is unable to determine search snippets, it preview. If the server is unable to determine search snippets, it
MUST return "null" for both the _subject_, _preview_ and MUST return "null" for both the _subject_, _preview_ and
_attachments_ properties. _attachments_ properties.
Note, unlike most data types, a SearchSnippet DOES NOT have a Note, unlike most data types, a SearchSnippet DOES NOT have a
property called "id". property called "id".
The following JMAP method is supported: The following JMAP method is supported:
skipping to change at page 52, line 45 skipping to change at page 54, line 23
To allow the client to restrict the volume of data it can receive in To allow the client to restrict the volume of data it can receive in
response to a request, a maximum length may be requested for the data response to a request, a maximum length may be requested for the data
returned for a textual body part. However, truncating the data may returned for a textual body part. However, truncating the data may
change the semantic meaning, for example truncating a URL changes its change the semantic meaning, for example truncating a URL changes its
location. Servers that scan for links to malicious sites should take location. Servers that scan for links to malicious sites should take
care to either ensure truncation is not at a semantically significant care to either ensure truncation is not at a semantically significant
point, or to rescan the truncated value for malicious content before point, or to rescan the truncated value for malicious content before
returning it. returning it.
9.2. HTML email display
HTML message bodies provide richer formatting for emails but present
a number of security challenges, especially when embedded in a
webmail context in combination with interface HTML. Clients that
render HTML email should make careful consideration of the potential
risks, including:
o Embedded JavaScript can rewrite the email to change its content on
subsequent opening, allowing users to be mislead. In webmail
systems, if run in the same origin as the interface it can access
and exfiltrate all private data accessible to the user, including
all other emails and potentially contacts, calendar events,
settings, and credentials. It can also rewrite the interface to
undetectably phish passwords. A compromise is likely to be
persistent, not just for the duration of page load, due to
exfiltration of session credentials or installation of a service
worker that can intercept all subsequent network requests (this
however would only be possible if blob downloads are also
available on the same origin, and the service worker script is
attached to the message).
o HTML documents may load content directly from the internet, rather
than just referencing attached resources. For example you may
have an "<img>" tag with an external "src" attribute. This may
leak to the sender when a message is opened, as well as the IP
address of the recipient. Cookies may also be sent and set by the
server, allowing tracking between different emails and even
website visits and advertising profiles.
o In webmail systems, CSS can break the layout or create phishing
vulnerabilities. For example, the use of "position:fixed" can
allow an email to draw content outside of its normal bounds,
potentially clickjacking a real interface element.
o If in a webmail context and not inside a separate frame, any
styles defined in CSS rules will apply to interface elements as
well if the selector matches, allowing the interface to be
modified. Similarly, any interface styles that match elements in
the email will alter their appearance, potentially breaking the
layout of the email.
o The link text in HTML has no neccessary correlation with the
actual target of the link, which can be used to make phishing
attacks more convincing.
o Links opened from an email or embedded external content may leak
private info in the "Referer" header sent by default in most
systems.
o Forms can be used to mimic login boxes, providing a potent
phishing vector if allowed to submit directly from the email
display.
There are a number of ways clients can mitigate these issues, and a
defence-in-depth approach that uses a combination of techniques will
provide the strongest security.
o HTML can be filtered before rendering, stripping potentially
malicious content. Sanitizing HTML correctly is tricky, and
implementors are strongly recommended to use a well-tested library
with a carefully vetted whitelist-only approach. New features
with unexpected security characteristics may be added to HTML
rendering engines in the future; a blacklist approach is likely to
result in security issues.
Subtle differences in parsing of HTML can introduce security flaws:
to filter with 100% accurately you need to use the same parser when
sanitizing that the HTML rendering engine will use.
o Encapsulating the message in an "<iframe sandbox>" can help
mitigate a number of risks. This will:
* Disable JavaScript.
* Disable form submission.
* Prevent drawing outside of its bounds, or conflict with
interface CSS.
* Establish a unique anonymous origin, separate to the containing
origin.
o A strong Content Security Policy [4] can, among other things,
block JavaScript and loading of external content should it manage
to evade the filter.
o The leakage of information in the Referer header can be mitigated
with the use of a referrer policy [5].
o A "crossorigin=anonymous" attribute on tags that load remote
content can prevent cookies from being sent.
o If adding "target=_blank" to open links in new tabs, also add
"rel=noopener" to ensure the page that opens cannot change the URL
in the original tab to redirect the user to a phishing site.
As highly complex software components, HTML rendering engines
increase the attack surface of a client considerably, especially when
being used to process untrusted, potentially malicious content.
Serious bugs have been found in image decoders, JavaScript engines
and HTML parsers in the past, which could lead to full system
compromise. Clients using an engine should ensure they get the
latest version and continue to incorporate any security patches
released by the vendor.
9.3. Email submission
SMTP submission servers [RFC6409] use a number of mechanisms to
mitigate damage caused by compromised user accounts and end-user
systems including rate limiting, anti-virus/anti-spam milters and
other technologies. The technologies work better when they have more
information about the client connection. If JMAP email submission is
implemented as a proxy to an SMTP Submission server, it is useful to
communicate this information from the JMAP proxy to the submission
server. The de-facto XCLIENT extension to SMTP can be used to do
this, but use of an authenticated channel is recommended to limit use
of that extension to explicitly authorized proxies. JMAP servers
that proxy to an SMTP Submission server SHOULD allow use of the
_submissions_ port [RFC8314] and SHOULD implement SASL PLAIN over TLS
[RFC4616] and/or TLS client certificate authentication with 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
other administrative domains, then implementation of the de-facto
milter protocol is strongly encouranged to integrate with third-party
products that address security issues including anti-virus/anti-spam,
reputation protection, compliance archiving, and data loss
prevention. Proxying to a local SMTP Submission server may be a
simpler way to provide such security services.
10. References 10. References
10.1. Normative References 10.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 54, line 18 skipping to change at page 58, line 35
[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>.
[RFC4422] Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
Authentication and Security Layer (SASL)", RFC 4422,
DOI 10.17487/RFC4422, June 2006,
<https://www.rfc-editor.org/info/rfc4422>.
[RFC4616] Zeilenga, K., Ed., "The PLAIN Simple Authentication and
Security Layer (SASL) Mechanism", RFC 4616,
DOI 10.17487/RFC4616, August 2006,
<https://www.rfc-editor.org/info/rfc4616>.
[RFC4865] White, G. and G. Vaudreuil, "SMTP Submission Service [RFC4865] White, G. and G. Vaudreuil, "SMTP Submission Service
Extension for Future Message Release", RFC 4865, Extension for Future Message Release", RFC 4865,
DOI 10.17487/RFC4865, May 2007, DOI 10.17487/RFC4865, May 2007,
<https://www.rfc-editor.org/info/rfc4865>. <https://www.rfc-editor.org/info/rfc4865>.
[RFC5198] Klensin, J. and M. Padlipsky, "Unicode Format for Network [RFC5198] Klensin, J. and M. Padlipsky, "Unicode Format for Network
Interchange", RFC 5198, DOI 10.17487/RFC5198, March 2008, Interchange", RFC 5198, DOI 10.17487/RFC5198, March 2008,
<https://www.rfc-editor.org/info/rfc5198>. <https://www.rfc-editor.org/info/rfc5198>.
[RFC5248] Hansen, T. and J. Klensin, "A Registry for SMTP Enhanced [RFC5248] Hansen, T. and J. Klensin, "A Registry for SMTP Enhanced
skipping to change at page 55, line 31 skipping to change at page 60, line 9
<https://www.rfc-editor.org/info/rfc6710>. <https://www.rfc-editor.org/info/rfc6710>.
[RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data [RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March
2014, <https://www.rfc-editor.org/info/rfc7159>. 2014, <https://www.rfc-editor.org/info/rfc7159>.
[RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493,
DOI 10.17487/RFC7493, March 2015, DOI 10.17487/RFC7493, March 2015,
<https://www.rfc-editor.org/info/rfc7493>. <https://www.rfc-editor.org/info/rfc7493>.
[RFC8314] Moore, K. and C. Newman, "Cleartext Considered Obsolete:
Use of Transport Layer Security (TLS) for Email Submission
and Access", RFC 8314, DOI 10.17487/RFC8314, January 2018,
<https://www.rfc-editor.org/info/rfc8314>.
10.2. URIs 10.2. URIs
[1] TODO [1] TODO
[2] server.html [2] server.html
[3] https://www.iana.org/assignments/imap-keywords/imap- [3] https://www.iana.org/assignments/imap-keywords/imap-
keywords.xhtml keywords.xhtml
[4] https://www.w3.org/TR/CSP3/
[5] https://www.w3.org/TR/referrer-policy/
Author's Address Author's Address
Neil Jenkins Neil Jenkins
FastMail FastMail
Level 2, 114 William St Level 2, 114 William St
Melbourne VIC 3000 Melbourne VIC 3000
Australia Australia
Email: neilj@fastmailteam.com Email: neilj@fastmailteam.com
URI: https://www.fastmail.com URI: https://www.fastmail.com
 End of changes. 60 change blocks. 
168 lines changed or deleted 437 lines changed or added

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