draft-ietf-jmap-mail-01.txt   draft-ietf-jmap-mail-02.txt 
JMAP N. Jenkins JMAP N. Jenkins
Internet-Draft FastMail Internet-Draft FastMail
Updates: 5788 (if approved) July 16, 2017 Updates: 5788 (if approved) October 30, 2017
Intended status: Standards Track Intended status: Standards Track
Expires: January 17, 2018 Expires: May 3, 2018
JMAP for Mail JMAP for Mail
draft-ietf-jmap-mail-01 draft-ietf-jmap-mail-02
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.
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 http://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 17, 2018. This Internet-Draft will expire on May 3, 2018.
Copyright Notice Copyright Notice
Copyright (c) 2017 IETF Trust and the persons identified as the Copyright (c) 2017 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
(http://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 . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1. Notational Conventions . . . . . . . . . . . . . . . . . 3 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 3
1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4
1.3. Addition to the capabilities object . . . . . . . . . . . 4 1.3. Addition to the capabilities object . . . . . . . . . . . 4
2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.1. getMailboxes . . . . . . . . . . . . . . . . . . . . . . 7 2.1. getMailboxes . . . . . . . . . . . . . . . . . . . . . . 8
2.2. getMailboxUpdates . . . . . . . . . . . . . . . . . . . . 8 2.2. getMailboxUpdates . . . . . . . . . . . . . . . . . . . . 8
2.3. setMailboxes . . . . . . . . . . . . . . . . . . . . . . 10 2.3. getMailboxList . . . . . . . . . . . . . . . . . . . . . 8
2.3.1. Ordering of changes . . . . . . . . . . . . . . . . . 11 2.4. getMailboxListUpdates . . . . . . . . . . . . . . . . . . 9
2.3.2. Creating mailboxes . . . . . . . . . . . . . . . . . 11 2.5. setMailboxes . . . . . . . . . . . . . . . . . . . . . . 9
2.3.3. Updating mailboxes . . . . . . . . . . . . . . . . . 12 3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3.4. Destroying mailboxes . . . . . . . . . . . . . . . . 13 3.1. getThreads . . . . . . . . . . . . . . . . . . . . . . . 10
2.3.5. Response . . . . . . . . . . . . . . . . . . . . . . 13 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 11
3. MessageLists . . . . . . . . . . . . . . . . . . . . . . . . 15 3.2. getThreadUpdates . . . . . . . . . . . . . . . . . . . . 11
3.1. getMessageList . . . . . . . . . . . . . . . . . . . . . 16 4. Messages . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 17 4.1. getMessages . . . . . . . . . . . . . . . . . . . . . . . 16
3.1.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 20 4.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 17
3.1.3. Thread collapsing . . . . . . . . . . . . . . . . . . 21 4.2. getMessageUpdates . . . . . . . . . . . . . . . . . . . . 17
3.1.4. Windowing . . . . . . . . . . . . . . . . . . . . . . 22 4.3. getMessageList . . . . . . . . . . . . . . . . . . . . . 17
3.1.5. Response . . . . . . . . . . . . . . . . . . . . . . 22 4.3.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 17
3.2. getMessageListUpdates . . . . . . . . . . . . . . . . . . 24 4.3.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 20
4. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 4.3.3. Thread collapsing . . . . . . . . . . . . . . . . . . 21
4.1. getThreads . . . . . . . . . . . . . . . . . . . . . . . 27 4.3.4. Response . . . . . . . . . . . . . . . . . . . . . . 21
4.2. getThreadUpdates . . . . . . . . . . . . . . . . . . . . 29 4.4. getMessageListUpdates . . . . . . . . . . . . . . . . . . 22
5. Messages . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.5. setMessages . . . . . . . . . . . . . . . . . . . . . . . 22
5.1. getMessages . . . . . . . . . . . . . . . . . . . . . . . 36 4.6. importMessages . . . . . . . . . . . . . . . . . . . . . 23
5.2. getMessageUpdates . . . . . . . . . . . . . . . . . . . . 38 4.7. copyMessages . . . . . . . . . . . . . . . . . . . . . . 25
5.3. setMessages . . . . . . . . . . . . . . . . . . . . . . . 40 5. MessageSubmission . . . . . . . . . . . . . . . . . . . . . . 27
5.3.1. Saving a draft . . . . . . . . . . . . . . . . . . . 41 5.1. getMessageSubmissions . . . . . . . . . . . . . . . . . . 31
5.3.2. Updating messages . . . . . . . . . . . . . . . . . . 43 5.2. getMessageSubmissionUpdates . . . . . . . . . . . . . . . 31
5.3.3. Sending messages . . . . . . . . . . . . . . . . . . 44 5.3. getMessageSubmissionList . . . . . . . . . . . . . . . . 31
5.3.4. Cancelling a send . . . . . . . . . . . . . . . . . . 45 5.4. getMessageSubmissionListUpdates . . . . . . . . . . . . . 32
5.3.5. Destroying messages . . . . . . . . . . . . . . . . . 45 5.5. setMessageSubmissions . . . . . . . . . . . . . . . . . . 32
5.3.6. Response . . . . . . . . . . . . . . . . . . . . . . 45 6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 34
5.4. importMessages . . . . . . . . . . . . . . . . . . . . . 47 6.1. getIdentities . . . . . . . . . . . . . . . . . . . . . . 35
5.5. copyMessages . . . . . . . . . . . . . . . . . . . . . . 48 6.2. getIdentityUpdates . . . . . . . . . . . . . . . . . . . 35
6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 50 6.3. setIdentities . . . . . . . . . . . . . . . . . . . . . . 35
6.1. getIdentities . . . . . . . . . . . . . . . . . . . . . . 50 7. SearchSnippets . . . . . . . . . . . . . . . . . . . . . . . 36
6.2. getIdentityUpdates . . . . . . . . . . . . . . . . . . . 51 7.1. getSearchSnippets . . . . . . . . . . . . . . . . . . . . 36
6.3. setIdentities . . . . . . . . . . . . . . . . . . . . . . 53 8. Vacation Response . . . . . . . . . . . . . . . . . . . . . . 38
7. SearchSnippets . . . . . . . . . . . . . . . . . . . . . . . 56 8.1. getVacationResponse . . . . . . . . . . . . . . . . . . . 39
7.1. getSearchSnippets . . . . . . . . . . . . . . . . . . . . 57 8.2. setVacationResponse . . . . . . . . . . . . . . . . . . . 39
8. Vacation Response . . . . . . . . . . . . . . . . . . . . . . 58 9. Security considerations . . . . . . . . . . . . . . . . . . . 39
8.1. getVacationResponse . . . . . . . . . . . . . . . . . . . 59 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 39
8.2. setVacationResponse . . . . . . . . . . . . . . . . . . . 59 10.1. Normative References . . . . . . . . . . . . . . . . . . 39
9. References . . . . . . . . . . . . . . . . . . . . . . . . . 61 10.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 41
9.1. Normative References . . . . . . . . . . . . . . . . . . 61
9.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 41
Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 61
1. Introduction 1. Introduction
JMAP is a generic protocol for synchronising data, such as mail, JMAP is a generic protocol for synchronising data, such as mail,
calendars or contacts, between a client and a server. It is calendars or contacts, between a client and a server. It is
optimised for mobile and web environments, and aims to provide a optimised for mobile and web environments, and aims to provide a
consistent interface to different data types. consistent interface to different data types.
This specification defines a data model for synchronising mail This specification defines a data model for synchronising mail
between a client and a server using JMAP. between a client and a server using JMAP.
1.1. Notational Conventions 1.1. Notational Conventions
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in [RFC2119]. document are to be interpreted as described in [RFC2119].
The underlying format used for this specification is JSON. The underlying format used for this specification is I-JSON
Consequently, the terms "object" and "array" as well as the four ([RFC7493]). Consequently, the terms "object" and "array" as well as
primitive types (strings, numbers, booleans, and null) are to be the four primitive types (strings, numbers, booleans, and null) are
interpreted as described in Section 1 of [RFC7159]. to be interpreted as described in Section 1 of [RFC7159]. Unless
otherwise noted, all the property names and values are case
sensitive.
Some examples in this document contain "partial" JSON documents used Some examples in this document contain "partial" JSON documents used
for illustrative purposes. In these examples, three periods "..." for illustrative purposes. In these examples, three periods "..."
are used to indicate a portion of the document that has been removed are used to indicate a portion of the document that has been removed
for compactness. for compactness.
Types signatures are given for all JSON objects in this document. Types signatures are given for all JSON objects in this document.
The following conventions are used: The following conventions are used:
o "Boolean|String" - The value is either a JSON "Boolean" value, or o "Boolean|String" - The value is either a JSON "Boolean" value, or
skipping to change at page 4, line 5 skipping to change at page 3, line 50
o "Foo" - Any name that is not a native JSON type means an object o "Foo" - Any name that is not a native JSON type means an object
for which the properties (and their types) are defined elsewhere for which the properties (and their types) are defined elsewhere
within this document. within this document.
o "Foo[]" - An array of objects of type "Foo". o "Foo[]" - An array of objects of type "Foo".
o "String[Foo]" - A JSON "Object" being used as a map (associative o "String[Foo]" - A JSON "Object" being used as a map (associative
array), where all the values are of type "Foo". array), where all the values are of type "Foo".
Object properties may also have a set of attributes defined along
with the type signature. These have the following meanings:
o *sever-set*: Only the server can set the value for this property.
The client MUST NOT send this property when creating a new object
of this type.
o *immutable*: The value MUST NOT change after the object is
created.
o *default*: (This is followed by a JSON value). The value that
will be used for this property if it is omitted when creating a
new object of this type.
1.2. Terminology 1.2. Terminology
The same terminology is used in this document as in the core JMAP The same terminology is used in this document as in the core JMAP
specification. specification.
1.3. Addition to the capabilities object 1.3. 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
authentication response; see the JMAP spec. Servers supporting session object; see the JMAP spec. Servers supporting _this_
_this_ specification MUST add a property called "{TODO: URI for this specification MUST add a property called "{TODO: URI for this spec}"
spec}" to the capabilities object. The value of this property is an to the capabilities object. The value of this property is an object
object which SHOULD contain the following information on server which SHOULD contain the following information on server
capabilities: capabilities:
o *maxMailboxesPerMessage*: "Number|null" The maximum number of
mailboxes that can be can assigned to a single message. This MUST
be an integer >= 1, or "null" for no limit (or rather, the limit
is always the number of mailboxes in the account).
o *maxSizeMessageAttachments*: "Number" The maximum total size of o *maxSizeMessageAttachments*: "Number" The maximum total size of
attachments, in bytes, allowed for messages. A server MAY still attachments, in bytes, allowed for messages. A server MAY still
reject messages with a lower attachment size total (for example, reject messages with a lower attachment size total (for example,
if the body includes several megabytes of text, causing the size if the body includes several megabytes of text, causing the size
of the encoded MIME structure to be over some server-defined of the encoded MIME structure to be over some server-defined
limit). limit).
o *canDelaySend*: "Boolean" Does the server support inserting a o *maxDelayedSend*: "Number" The number in seconds of the maximum
message into the outbox to be sent later at a user-specified time? delay the server supports in sending (see the MessageSubmission
object). This is "0" if the server does not support delayed send.
o *messageListSortOptions*: "String[]" A list of all the message o *messageListSortOptions*: "String[]" A list of all the message
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.
o *submissionExtensions*: "String[String[]]" A JMAP implementation
that talks to a Submission [RFC6409] server SHOULD have a
configuration setting that allows an administrator to expose a new
submission EHLO capability in this field. This allows a JMAP
server to gain access to a new submission extension without code
changes. By default, the JMAP server should show only known safe-
to-expose EHLO capabilities in this field, and hide EHLO
capabilites that are only relevant to the JMAP server. Each key
in the object is the _ehlo-name_, and the value is a list of
_ehlo-args_. Examples of safe-to-expose Submission extensions
include:
* FUTURERELEASE ([RFC4865])
* SIZE ([RFC1870])
* DSN ([RFC3461])
* DELIVERYBY ([RFC2852])
* MT-PRIORITY ([RFC6710])
A JMAP server MAY advertise an extension and implement the
semantics of that extension locally on the JMAP server even if a
submission server used by JMAP doesn't implement it. The full
IANA registry of submission extensions can be found at
<https://www.iana.org/assignments/mail-parameters/mail-
parameters.xhtml#mail-parameters-2>
2. Mailboxes 2. Mailboxes
A mailbox represents a named set of emails. This is the primary A mailbox represents a named set of emails. This is the primary
mechanism for organising messages within an account. It is analogous mechanism for organising messages within an account. It is analogous
to a folder or a label in other systems. A mailbox may perform a to a folder or a label in other systems. A mailbox may perform a
certain role in the system; see below for more details. certain role in the system; see below for more details.
For compatibility with IMAP, a message MUST belong to one or more For compatibility with IMAP, a message MUST belong to one or more
mailboxes. The message id does not change if the message changes mailboxes. The message id does not change if the message changes
mailboxes. mailboxes.
A *Mailbox* object has the following properties: A *Mailbox* object has the following properties:
o *id*: "String" The id of the mailbox. This property is immutable. 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 UTF-8 string ([RFC3629]) of at least 1 character This may be any UTF-8 string ([RFC3629]) of at least 1 character
in length and maximum 256 bytes in size. Servers SHOULD forbid in length and maximum 256 bytes in size. Servers SHOULD forbid
sibling Mailboxes with the same name. sibling Mailboxes with the same name.
o *parentId*: "String|null" The mailbox id for the parent of this o *parentId*: "String|null" (default: "null") The mailbox id for the
mailbox, or "null" if this mailbox is at the top level. Mailboxes parent of this mailbox, or "null" if this mailbox is at the top
form acyclic graphs (forests) directed by the child-to-parent level. Mailboxes form acyclic graphs (forests) directed by the
relationship. There MUST NOT be a loop. child-to-parent relationship. There MUST NOT be a loop.
o *role*: "String|null" Identifies system mailboxes. This property o *role*: "String|null" (default: "null") Identifies system
can only be set on create. After the record has been created, mailboxes. This property can only be set on create. After the
this property is immutable. The following values MUST be used for record has been created, this property is immutable. The
the relevant mailboxes: following values MUST be used for the relevant mailboxes:
* "inbox" - the mailbox to which new mail is delivered by * "inbox" - the mailbox to which new mail is delivered by
default, unless diverted by a rule or spam filter etc. default, unless diverted by a rule or spam filter etc.
* "archive" - messages the user does not need right now, but does * "archive" - messages the user does not need right now, but does
not wish to delete. not wish to delete.
* "drafts" - messages the user is currently writing and are not * "drafts" - messages the user is currently writing and are not
yet sent. yet sent.
* "outbox" - messages the user has finished writing and wishes to
send (see the "setMessages" method description for more
information). A mailbox with this role MUST be present if the
user is allowed to send mail through an account. If not
present, the user cannot send mail with that account.
* "sent" - messages the user has sent. * "sent" - messages the user has sent.
* "trash" - messages the user has deleted. * "trash" - messages the user has deleted.
* "spam" - messages considered spam by the server. * "spam" - messages considered spam by the server.
* "templates" - drafts which should be used as templates (i.e. * "templates" - drafts which should be used as templates (i.e.
used as the basis for creating new drafts). used as the basis for creating new drafts).
No two mailboxes may have the same role. Mailboxes without a No two mailboxes may have the same role. Mailboxes without a
known purpose MUST have a role of "null". An account is not known purpose MUST have a role of "null". An account is not
required to have mailboxes with any of the above roles. A client required to have mailboxes with any of the above roles. A client
MAY create new mailboxes with a role property to help them keep MAY create new mailboxes with a role property to help them keep
track of a use-case not covered by the above list. To avoid track of a use-case not covered by the above list. To avoid
potential conflict with any special behaviour a server might apply potential conflict with any special behaviour a server might apply
to mailboxes with certain roles in the future, any roles not in to mailboxes with certain roles in the future, any roles not in
the above list created by the client must begin with ""x-"". The the above list created by the client must begin with ""x-"". The
client MAY attempt to create mailboxes with the standard roles if client MAY attempt to create mailboxes with the standard roles if
not already present, but the server MAY reject these. not already present, but the server MAY reject these.
o *sortOrder*: "Number" Defines the sort order of mailboxes when o *sortOrder*: "Number" (default: "0") Defines the sort order of
presented in the client's UI, so it is consistent between devices. mailboxes when presented in the client's UI, so it is consistent
The number MUST be an integer in the range 0 <= sortOrder < 2^31. between devices. The number MUST be an integer in the range 0 <=
A mailbox with a lower order should be displayed before a mailbox sortOrder < 2^31. A mailbox with a lower order should be
with a higher order (that has the same parent) in any mailbox displayed before a mailbox with a higher order (that has the same
listing in the client's UI. Mailboxes with equal order SHOULD be parent) in any mailbox listing in the client's UI. Mailboxes with
sorted in alphabetical order by name. The sorting SHOULD take equal order SHOULD be sorted in alphabetical order by name. The
into account locale-specific character order convention. sorting SHOULD take into account locale-specific character order
convention.
o *mustBeOnlyMailbox*: "Boolean" If "true", messages in this mailbox
may not also be in any other mailbox that also has
"mustBeOnlyMailbox: true". If "false", messages may be added to
this mailbox in addition to any other mailbox (i.e. it's a label).
This property is immutable.
o *mayReadItems*: "Boolean" If true, may use this mailbox as part of o *mayReadItems*: "Boolean" (server-set) If true, may use this
a filter in a _getMessageList_ call. If a submailbox is shared mailbox as part of a filter in a _getMessageList_ call. If a
but not the parent mailbox, this may be "false". submailbox is shared but not the parent mailbox, this may be
"false".
o *mayAddItems*: "Boolean" The user may add messages to this mailbox o *mayAddItems*: "Boolean" (server-set) The user may add messages to
(by either creating a new message or moving an existing one). this mailbox (by either creating a new message or moving an
existing one).
o *mayRemoveItems*: "Boolean" The user may remove messages from this o *mayRemoveItems*: "Boolean" (server-set) The user may remove
mailbox (by either changing the mailboxes of a message or deleting messages from this mailbox (by either changing the mailboxes of a
it). message or deleting it).
o *mayCreateChild*: "Boolean" The user may create a mailbox with o *mayCreateChild*: "Boolean" (server-set) The user may create a
this mailbox as its parent. mailbox with this mailbox as its parent.
o *mayRename*: "Boolean" The user may rename the mailbox or make it o *mayRename*: "Boolean" (server-set) The user may rename the
a child of another mailbox. mailbox or make it a child of another mailbox.
o *mayDelete*: "Boolean" The user may delete the mailbox itself. o *mayDelete*: "Boolean" (server-set) The user may delete the
mailbox itself.
o *totalMessages*: "Number" The number of messages in this mailbox. o *totalMessages*: "Number" (server-set) The number of messages in
this mailbox.
o *unreadMessages*: "Number" The number of messages in this mailbox o *unreadMessages*: "Number" (server-set) The number of messages in
that have neither the "$Seen" keyword nor the "$Draft" keyword. this mailbox that have neither the "$Seen" keyword nor the
"$Draft" keyword.
o *totalThreads*: "Number" The number of threads where at least one o *totalThreads*: "Number" (server-set) The number of threads where
message in the thread is in this mailbox. at least one message in the thread is in this mailbox.
o *unreadThreads*: "Number" The number of threads where at least one o *unreadThreads*: "Number" (server-set) The number of threads where
message in the thread has neither the "$Seen" keyword nor the at least one message in the thread has neither the "$Seen" keyword
"$Draft" keyword AND at least one message in the thread is in this nor the "$Draft" keyword AND at least one message in the thread is
mailbox (but see below for special case handling of Trash). Note, in this mailbox (but see below for special case handling of
the unread message does not need to be the one in this mailbox. Trash). Note, the unread message does not need to be the one in
this mailbox.
The Trash mailbox (that is a mailbox with "role == "trash"") MUST be The Trash mailbox (that is a mailbox with "role == "trash"") MUST be
treated specially for the purpose of unread counts: treated specially for the purpose of unread counts:
1. Messages that are *only* in the Trash (and no other mailbox) are 1. Messages that are *only* in the Trash (and no other mailbox) are
ignored when calculating the "unreadThreads" count of other ignored when calculating the "unreadThreads" count of other
mailboxes. mailboxes.
2. Messages that are *not* in the Trash are ignored when calculating 2. Messages that are *not* in the Trash are ignored when calculating
the "unreadThreads" count for the Trash mailbox. the "unreadThreads" count for the Trash mailbox.
skipping to change at page 7, line 31 skipping to change at page 8, line 21
So for example, suppose you have an account where the entire contents So for example, suppose you have an account where the entire contents
is a single conversation with 2 messages: an unread message in the is a single conversation with 2 messages: an unread message in the
Trash and a read message in the Inbox. The "unreadThreads" count Trash and a read message in the Inbox. The "unreadThreads" count
would be "1" for the Trash and "0" for the Inbox. would be "1" for the Trash and "0" for the Inbox.
For IMAP compatibility, a message in both the Trash and another For IMAP compatibility, a message 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).
2.1. getMailboxes The following JMAP methods are supported:
Mailboxes can either be fetched explicitly by id, or all of them at
once. To fetch mailboxes, make a call to "getMailboxes". It takes
the following arguments:
o *accountId*: "String|null" The Account to fetch the mailboxes for.
If "null", the primary account is used.
o *ids*: "String[]|null" The ids of the mailboxes to fetch. If
"null", all mailboxes in the account are returned.
o *properties*: "String[]|null" The properties of each mailbox to
fetch. If "null", all properties are returned. The id of the
mailbox will *always* be returned, even if not explicitly
requested.
The response to _getMailboxes_ is called _mailboxes_. It has the
following arguments:
o *accountId*: "String" The id of the account used for the call.
o *state*: "String" A string representing the state on the server
for *all* mailboxes. If the state of a mailbox changes, or a new
mailbox is created, or a mailbox is destroyed, this string will
change. It is used to get delta updates.
o *list*: "Mailbox[]" An array of the Mailbox objects requested.
This will be the *empty array* if the _ids_ argument was the empty
array, or contained only ids for mailboxes that could not be
found.
o *notFound*: "String[]|null" This array contains the ids passed to
the method for mailboxes that do not exist, or "null" if all
requested ids were found. It MUST be "null" if the _ids_ argument
in the call was "null".
The following errors may be returned instead of the _mailboxes_
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
"requestTooLarge": Returned if the number of _ids_ requested by the 2.1. getMailboxes
client exceeds the maximum number the server is willing to process in
a single method call.
"invalidArguments": Returned if the request does not include one of Standard _getFoos_ method. The _ids_ argument may be "null" to fetch
the required arguments, or one of the arguments is of the wrong type, all at once.
or otherwise invalid. A "description" property MAY be present on the
response object to help debug with an explanation of what the problem
was.
2.2. getMailboxUpdates 2.2. getMailboxUpdates
The _getMailboxUpdates_ call allows a client to efficiently update Standard _getFooUpdates_ method, but with one extra argument to the
the state of its cached mailboxes to match the new state on the _mailboxUpdates_ response:
server. It takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If "null", the primary account will be used.
o *sinceState*: "String" The current state of the client. This is
the string that was returned as the _state_ argument in the
_mailboxes_ response. The server will return the changes made
since this state.
o *fetchRecords*: "Boolean|null" If "true", immediately after
outputting a _mailboxUpdates_ response, an implicit call will be
made to _getMailboxes_ with the _changed_ property of the response
as the _ids_ argument, and the _fetchRecordProperties_ argument as
the _properties_ argument. If "false" or "null", no implicit call
will be made.
o *fetchRecordProperties*: "String[]|null" If "null", all Mailbox
properties will be fetched unless _onlyCountsChanged_ in the
_mailboxUpdates_ response is "true", in which case only the 4
counts properties will be returned (_totalMessages_,
_unreadMessages_, _totalThreads_ and _unreadThreads_). If not
"null", this value will be passed through to the _getMailboxes_
call regardless of the _onlyCountsChanged_ value in the
_mailboxUpdates_ response.
The response to _getMailboxUpdates_ is called _mailboxUpdates_. It
has the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *oldState*: "String" This is the _sinceState_ argument echoed
back; the state from which the server is returning changes.
o *newState*: "String" This is the state the client will be in after
applying the set of changes to the old state.
o *changed*: "String[]" An array of Mailbox ids where a property of
the mailbox has changed between the old state and the new state,
or the mailbox has been created, and the mailbox has not been
destroyed.
o *removed*: "String[]" An array of Mailbox ids for mailboxes which
have been destroyed since the old state.
o *onlyCountsChanged*: "Boolean" Indicates that only the mailbox
counts (unread/total messages/threads) have changed since the old
state. The client can then use this to optimise its data transfer
and only fetch the counts. If the server is unable to tell if
only counts have changed, it should just always return "false".
If a mailbox has been modified AND deleted since the oldState, the
server should just return the id in the _removed_ array, but MAY
return it in the _changed_ array as well. If a mailbox has been
created AND deleted since the oldState, the server SHOULD remove the
mailbox id from the response entirely, but MAY include it in the
_removed_ array.
The following errors may be returned instead of the "mailboxUpdates"
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
"invalidArguments": Returned if the request does not include one of
the required arguments, or one of the arguments is of the wrong type,
or otherwise invalid. A "description" property MAY be present on the
response object to help debug with an explanation of what the problem
was.
"cannotCalculateChanges": Returned if the server cannot calculate the
changes from the state string given by the client. Usually due to
the client's state being too old. The client MUST invalidate its
Mailbox cache.
2.3. setMailboxes
Mailboxes can be created, updated and destroyed using the
_setMailboxes_ method. The method takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If "null", defaults to the primary account.
o *ifInState*: "String|null" This is a state string as returned by
the _getMailboxes_ method. If supplied, the string must match the
current state, otherwise the method will be aborted and a
"stateMismatch" error returned. If "null", any changes will be
applied to the current state.
o *create*: "String[Mailbox]|null" A map of _creation id_ (an
arbitrary string set by the client) to Mailbox objects. If
"null", no objects will be created.
o *update*: "String[Mailbox]|null" A map of mailbox id to objects
containing the properties to update for that Mailbox. If "null",
no objects will be updated.
o *destroy*: "String[]|null" A list of ids for Mailboxes to
permanently delete. If "null", no objects will be deleted.
If a create, update or destroy is rejected, the appropriate error
MUST be added to the notCreated/notUpdated/notDestroyed property of
the response and the server MUST continue to the next create/update/
destroy. It does not terminate the method.
2.3.1. Ordering of changes
Each create, update or destroy is considered an atomic unit. The
server MAY commit some of the changes but not others, however MUST
NOT only commit part of an update to a single record (e.g. update the
_name_ field but not the _parentId_ field, if both are supplied in
the update object).
The final state MUST be valid after the setMailboxes is finished,
however the server MAY have to transition through invalid
intermediate states (not exposed to the client) while processing the
individual create/update/destroy requests. For example, a single
method call could rename Mailbox A => B, and simultaneously rename
Mailbox B => A. The final state is valid, so this is allowed,
however if processed sequentially there will be an internal state
where temporarily both mailboxes have the same name.
A Mailbox may reference another Mailbox object as a parent. When a
Mailbox is created or modified, it may reference another Mailbox
being created _in the same API request_ by using the creation id
prefixed with a "#". The order of the method calls in the request by
the client MUST be such that the mailbox being referenced is created
in *either the same or an earlier method call*. If within the same
method call, the server MUST process the parent create first, as if
this fails the create/update that references it will also fail.
Creation ids sent by the client SHOULD be unique within the single
API request for a particular data type. If a creation id is reused,
the server MUST map the creation id to the most recently created item
with that id.
2.3.2. Creating mailboxes
The properties of the Mailbox object submitted for creation MUST
conform to the following conditions:
o The _id_ property MUST NOT be present.
o The _parentId_ property MUST be either "null" or be a valid id for
a mailbox for which the "mayCreateChild" property is "true".
o The _role_ property MUST be either "null", a valid role as listed
in the Mailbox object specification, or prefixed by ""x-"".
o The _mustBeOnlyMailbox_ property MUST NOT be present. This is
server dependent and will be set by the server.
o The _mayXXX_ properties MUST NOT be present. Restrictions may
only be set by the server for system mailboxes, or when sharing
mailboxes with other users (setting sharing is not defined yet in
this spec).
o The _totalMessages_, _unreadMessages_, _totalThreads_ and
_unreadThreads_ properties MUST NOT be present.
If any of the properties are invalid, the server MUST reject the
create with an "invalidProperties" error. The Error object SHOULD
contain a property called _properties_ of type "String[]" that lists
*all* the properties that were invalid. The object MAY also contain
a _description_ property of type "String" with a user-friendly
description of the problems.
There may be a maximum number of mailboxes allowed on the server. If
this is reached, any attempt at creation will be rejected with a
"maxQuotaReached" error.
2.3.3. Updating mailboxes
If the _id_ given does not correspond to a Mailbox in the given
account, the update MUST be rejected with a "notFound" error.
All properties being updated must be of the correct type, not
immutable or server-set-only, and the new value must obey all
conditions of the property. In particular, note the following
conditions:
o The _name_ property MUST be a valid UTF-8 string of at least 1
character in length and maximum 256 bytes in size.
o The _parentId_ property MUST be either "null" or be a valid id for
_another_ mailbox that is *not a descendant* of this mailbox, and
for which the "mayCreateChild" property is "true".
o These properties are immutable or may only be set by the server:
* id
* role
* mustBeOnlyMailbox
* mayReadItems
* mayAddItems
* mayRemoveItems
* mayCreateChild
* mayRename
* mayDelete
* totalMessages
* unreadMessages
* totalThreads
* unreadThreads
If any of the properties are invalid, the server MUST reject the
update with an "invalidProperties" error. The Error object SHOULD
contain a property called _properties_ of type "String[]" that lists
*all* the properties that were invalid. The object MAY also contain
a _description_ property of type "String" with a user-friendly
description of the problems.
2.3.4. Destroying mailboxes
If the _id_ given does not correspond to a Mailbox in the given
account, the destruction MUST be rejected with a "notFound" error.
If the mailbox has "mayDeleteMailbox == false", the destruction MUST
be rejected with a "forbidden" error.
A mailbox MUST NOT be destroyed if it still has any child mailboxes.
Attempts to do so MUST be rejected with a "mailboxHasChild" error.
A mailbox MUST NOT be destroyed if it has any messages assigned to
it. Attempts to do so MUST be rejected with a "mailboxHasMessage"
error.
2.3.5. Response
The response to _setMailboxes_ is called _mailboxesSet_. It has the
following arguments:
o *accountId*: "String" The id of the account used for the call.
o *oldState*: "String|null" The state string that would have been
returned by "getMailboxes" before making the requested changes, or
"null" if the server doesn't know what the previous state string
was.
o *newState*: "String" The state string that will now be returned by
"getMailboxes".
o *created*: "String[Mailbox]" A map of the creation id to an object
containing all server-set properties for each successfully created
Mailbox: _id_, _mustBeOnlyMailbox_, all _mayXXX_ properties,
_totalMessages_, _unreadMessages_, _totalThreads_ and
_unreadThreads_.
o *updated*: "String[Mailbox|null]" The _keys_ in this map are the
ids of all mailboxes that were successfully updated. If the
server made any other changes to the record beyond those
explicitly requested by the client, the _value_ for the
corresponding id in the map is an object containing the updated
value of each property the *server changed*. Otherwise (if no
properties changed on the server other than those explicitly
updated by the client), the value is "null".
o *destroyed*: "String[]" A list of ids for Mailboxes that were
successfully destroyed.
o *notCreated*: "String[SetError]" A map of creation id to a
SetError object for each Mailbox that failed to be created. The
possible errors are defined above.
o *notUpdated*: "String[SetError]" A map of Mailbox id to a SetError
object for each Mailbox that failed to be updated. The possible
errors are defined above.
o *notDestroyed*: "String[SetError]" A map of Mailbox id to a
SetError object for each Mailbox that failed to be destroyed. The
possible errors are defined above.
The following errors may be returned instead of the _mailboxesSet_
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
"accountReadOnly": Returned if the account has "isReadOnly == true".
"requestTooLarge": Returned if the total number of objects to create,
update or destroy exceeds the maximum number the server is willing to
process in a single method call.
"invalidArguments": Returned if one of the arguments is of the wrong
type, or otherwise invalid. A _description_ property MAY be present
on the response object to help debug with an explanation of what the
problem was.
"stateMismatch": Returned if an "ifInState" argument was supplied and
it does not match the current state.
Example request:
[ "setMailboxes", {
"ifInState": "ms4123",
"update": {
"f3": {
"name": "The new name"
}
},
"destroy": [ "f5" ]
}, "#0" ]
3. MessageLists
A *MessageList* is a sorted query on the set of messages in a user's
account. Since it can be very long, the client must specify what
section of the list to return. The client can optionally also fetch
the threads and/or messages for this part of the list.
The same message may appear in multiple messages lists. For example,
it may belong to multiple mailboxes, and of course it can appear in
searches. Since messages have an immutable id, a client can easily
tell if it already has a message cached and only fetch the ones it
needs.
When the state changes on the server, a delta update can be requested
to efficiently update the client's cache of this list to the new
state. If the server doesn't support this, the client still only
needs to fetch the message list again, not the messages themselves.
3.1. getMessageList
To fetch a message list, make a call to _getMessageList_. It takes
the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If "null", the primary account will be used.
o *filter*: "FilterCondition|FilterOperator|null" Determines the set
of messages returned in the results. See the "Filtering" section
below for allowed values and semantics.
o *sort*: "String[]|null" A list of Message property names to sort
by. See the "Sorting" section below for allowed values and
semantics.
o *collapseThreads*: "Boolean|null" If true, each thread will only
be returned once in the resulting list, at the position of the
first message in the list (given the filter and sort order)
belonging to the thread. If "false" or "null", threads may be
returned multiple times.
o *position*: "Number|null" The 0-based index of the first result in
the list to return. If a negative value is given, the call MUST
be rejected with an "invalidArguments" error. If "null", 0 is
used.
o *anchor*: "String|null" A Message id. The index of this message
id will be used in combination with the "anchorOffset" argument to
determine the index of the first result to return (see the
"Windowing" section below for more details).
o *anchorOffset*: "Number|null" The index of the anchor message
relative to the index of the first result to return. This MAY be
negative. For example, "-1" means the first message after the
anchor message should be the first result in the results returned
(see the "Windowing" section below for more details).
o *limit*: "Number|null" The maximum number of results to return.
If "null", no limit is presumed. The server MAY choose to enforce
a maximum "limit" argument. In this case, if a greater value is
given, the limit should be clamped to the maximum; since the total
number of results in the list is returned, the client should not
be relying on how many results are returned to determine if it has
reached the end of the list. If a negative value is given, the
call MUST be rejected with an "invalidArguments" error.
o *fetchThreads*: "Boolean|null" If "true", after outputting a
_messageList_ response, an implicit call will be made to
_getThreads_ with the _threadIds_ array in the response as the
_ids_ argument, and the _fetchMessages_ and
_fetchMessageProperties_ arguments passed straight through from
the call to _getMessageList_. If "false" or "null", no implicit
call will be made.
o *fetchMessages*: "Boolean|null" If "true" and "fetchThreads ==
false", then after outputting a _messageList_ response, an
implicit call will be made to _getMessages_ with the "messageIds"
array in the response as the _ids_ argument, and the
_fetchMessageProperties_ argument as the _properties_ argument.
If "false" or "null", no implicit call will be made.
o *fetchMessageProperties*: "String[]|null" The list of properties
to fetch on any fetched messages. See _getMessages_ for a full
description.
o *fetchSearchSnippets*: "Boolean|null" If "true", then after
outputting a _messageList_ and making any other implicit calls, an
implicit call will be made to _getSearchSnippets_. The
_messageIds_ array from the response will be used as the
_messageIds_ argument, and the _filter_ argument will be passed
straight through. If "false" or "null", no implicit call will be
made.
3.1.1. Filtering
A *FilterOperator* object has the following properties:
o *operator*: "String" This MUST be one of the following strings:
"AND"/"OR"/"NOT":
* *AND*: all of the conditions must match for the filter to
match.
* *OR*: at least one of the conditions must match for the filter
to match.
* *NOT*: none of the conditions must match for the filter to
match.
o *conditions*: "(FilterCondition|FilterOperator)[]" The conditions
to evaluate against each message.
A *FilterCondition* object has the following properties:
o *inMailbox*: "String|null" A mailbox id. A message must be in
this mailbox to match the condition.
o *inMailboxOtherThan*: "String|null" A mailbox id. A message be in
any mailbox other than this one to match the condition. This is
to allow messages solely in trash/spam to be easily excluded from
a search.
o *before*: "Date|null" The date of the message (as returned on the
Message object) must be before this date to match the condition.
o *after*: "Date|null" The date of the message (as returned on the
Message object) must be on or after this date to match the
condition.
o *minSize*: "Number|null" The size of the message in bytes (as
returned on the Message object) must be equal to or greater than
this number to match the condition.
o *maxSize*: "Number|null" The size of the message in bytes (as
returned on the Message object) must be less than this number to
match the condition.
o *allInThreadHaveKeyword*: "String" All messages (including this
one) in the same thread as this message must have the given
keyword to match the condition.
o *someInThreadHaveKeyword*: "String" At least one message (possibly
this one) in the same thread as this message must have the given
keyword to match the condition.
o *noneInThreadHaveKeyword*: "String" All messages (including this
one) in the same thread as this message must *not* have the given
keyword to match the condition.
o *hasKeyword*: "String" This message must have the given keyword to
match the condition.
o *notKeyword*: "String" This message must not have the given
keyword to match the condition.
o *hasAttachment*: "Boolean|null" The "hasAttachment" property of
the message must be identical to the value given to match the
condition.
o *text*: "String|null" Looks for the text in the _from_, _to_,
_cc_, _bcc_, _subject_, _textBody_ or _htmlBody_ properties of the
message.
o *from*: "String|null" Looks for the text in the _from_ property of
the message.
o *to*: "String|null" Looks for the text in the _to_ property of the
message.
o *cc*: "String|null" Looks for the text in the _cc_ property of the
message.
o *bcc*: "String|null" Looks for the text in the _bcc_ property of
the message.
o *subject*: "String|null" Looks for the text in the _subject_
property of the message.
o *body*: "String|null" Looks for the text in the _textBody_ or
_htmlBody_ property of the message.
o *header*: "String[]|null" The array MUST contain either one or two
elements. The first element is the name of the header to match
against. The second (optional) element is the text to look for in
the header. If not supplied, the message matches simply if it
_has_ a header of the given name.
If zero properties are specified on the FilterCondition, the
condition MUST always evaluate to "true". If multiple properties are
specified, ALL must apply for the condition to be "true" (it is
equivalent to splitting the object into one-property conditions and
making them all the child of an AND filter operator).
The exact semantics for matching "String" fields is *deliberately not
defined* to allow for flexibility in indexing implementation, subject
to the following:
o Text SHOULD be matched in a case-insensitive manner. o *changedProperties*: "String[]|null" If only the mailbox counts
(unread/total messages/threads) have changed since the old state,
this will be the list of properties that may have changed, i.e.
"["totalMessages", "unreadMessages", "totalThreads",
"unreadThreads"]". If the server is unable to tell if only counts
have changed, it MUST just be "null".
o Text contained in either (but matched) single or double quotes Since counts frequently change but the rest of the mailboxes state
SHOULD be treated as a *phrase search*, that is a match is for most use cases changes rarely, the server can help the client
required for that exact word or sequence of words, excluding the optimise data transfer by keeping track of changes to message counts
surrounding quotation marks. Use "\"", "\'" and "\\" to match a separately to other state changes. The _changedProperties_ array may
literal """, "'" and "\" respectively in a phrase. be used directly via a result reference in a subsequent getMailboxes
call in a single request.
o Outside of a phrase, white-space SHOULD be treated as dividing 2.3. getMailboxList
separate tokens that may be searched for separately in the
message, but MUST all be present for the message to match the
filter.
o Tokens MAY be matched on a whole-word basis using stemming (so for Standard _getFooList_ method.
example a text search for "bus" would match "buses" but not
"business").
o When searching inside the _htmlBody_ property, HTML tags and The *FilterCondition* object (optionally passed as the _filter_
attributes SHOULD be ignored. argument) has the following properties, any of which may be omitted:
3.1.2. Sorting o *parentId*: "String|null" The Mailbox _parentId_ property must
match the given value exactly.
The "sort" argument lists the properties to compare between two o *hasRole*: "Boolean" If this is "true", a Mailbox matches if it
messages to determine which comes first in the sort. If two messages has a non-"null" value for its _role_ property.
have an identical value for the first property, the next property
will be considered and so on. If all properties are the same (this
includes the case where an empty array or "null" is given as the
argument), the sort order is server-dependent, but MUST be stable
between calls to "getMessageList".
Following the property name there MUST be a space and then either the A Mailbox object matches the filter if and only if all of the given
string "asc" or "desc" to specify ascending or descending sort for conditions given match. If zero properties are specified, it is
that property. automatically "true" for all objects.
The following properties MUST be supported for sorting: The following properties MUST be supported for sorting:
o *id* - The id as returned in the Message object. o "sortOrder"
o *date* - The date as returned in the Message object.
The following properties SHOULD be supported for sorting:
o *size* - The size as returned in the Message object.
o *from* - This is taken to be either the "name" part of the Emailer
object, or if none then the "email" part of the Emailer object
(see the definition of the from property in the Message object).
If still none, consider the value to be the empty string.
o *to* - This is taken to be either the "name" part of the *first*
Emailer object, or if none then the "email" part of the *first*
Emailer object (see the definition of the to property in the
Message object). If still none, consider the value to be the
empty string.
o *subject* - This is taken to be the subject of the Message with
any ignoring any leading "Fwd:"s or "Re:"s (case-insensitive
match).
o *keyword:*"$keyword" - This value MUST be considered "true" if the
message has the keyword, or "false" otherwise.
o *allThreadKeyword:*"$keyword" - This value MUST be considered
"true" for the message if *all* of the messages in the same thread
(regardless of mailbox) have the keyword.
o *someThreadKeyword:*"$keyword" - This value MUST be considered
"true" for the message if *any* of the messages in the same thread
(regardless of mailbox) have the keyword.
The server MAY support sorting based on other properties as well. A
client can discover which properties are supported by inspecting the
server's _capabilities_ object (see section 1).
The method of comparison depends on the type of the property:
o "String": Comparison function is server-dependent. It SHOULD be
case-insensitive and SHOULD take into account locale-specific
conventions if known for the user. However, the server MAY choose
to just sort based on unicode code point, after best-effort
translation to lower-case.
o "Date": If sorting in ascending order, the earlier date MUST come
first.
o "Boolean": If sorting in ascending order, a "false" value MUST
come before a "true" value.
Example sort:
`[ "someThreadKeyword:$Flagged desc", "date desc" ]
This would sort messages in flagged threads first (the thread is
considered flagged if any message within it is flagged), and then in
date order, newest first. If two messages have both identical
flagged status and date, the order is server-dependent but must be
stable.
3.1.3. Thread collapsing
When "collapseThreads == true", then after filtering and sorting the
message list, the list is further winnowed by removing any messages
for a thread id that has already been seen (when passing through the
list sequentially). A thread will therefore only appear *once* in
the "threadIds" list of the result, at the position of the first
message in the list that belongs to the thread.
3.1.4. Windowing
If a _position_ offset is supplied, then this is the 0-based index of
the first result to return in the list of messages after filtering,
sorting and collapsing threads. If the index is greater than or
equal to the total number of messages in the list, then there are no
results to return, but this DOES NOT generate an error. If
_position_ is "null" (or, equivalently, omitted) this MUST be
interpreted as "position: 0".
Alternatively, a message id, called the *anchor* may be given. In
this case, after filtering, sorting and collapsing threads, the
anchor is searched for in the message list. If found, the *anchor
offset* is then subtracted from this index. If the resulting index
is now negative, it is clamped to 0. This index is now used exactly
as though it were supplied as the "position" argument. If the anchor
is not found, the call is rejected with an "anchorNotFound" error.
If an _anchor_ is specified, any position argument supplied by the
client MUST be ignored. If _anchorOffset_ is "null", it defaults to
"0". If no _anchor_ is supplied, any anchor offset argument MUST be
ignored.
3.1.5. Response
The response to a call to _getMessageList_ is called _messageList_.
It has the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *filter*: "FilterCondition|FilterOperator|null" The filter of the
message list. Echoed back from the call.
o *sort*: "String[]|null" A list of Message property names used to
sort by. Echoed back from the call.
o *collapseThreads*: "Boolean|null" Echoed back from the call.
o *state*: "String" A string encoding the current state on the
server. This string will change if the results of the message
list MAY have changed (for example, there has been a change to the
state of the set of Messages; it does not guarantee that anything
in the list has changed). It may be passed to
_getMessageListUpdates_ to efficiently get the set of changes from
the previous state. Should a client receive back a response with
a different state string to a previous call, it MUST either throw
away the currently cached list and fetch it again (note, this does
not require fetching the messages again, just the list of ids) or,
if the server supports it, call _getMessageListUpdates_ to get the
delta difference.
o *canCalculateUpdates*: "Boolean" This is "true" if the server
supports calling "getMessageListUpdates" with these
"filter"/"sort"/"collapseThreads" parameters. Note, this does not
guarantee that the getMessageListUpdates call will succeed, as it
may only be possible for a limited time afterwards due to server
internal implementation details.
o *position*: "Number" The 0-based index of the first result in the
"threadIds" array within the complete list.
o *total*: "Number" The total number of messages in the message list
(given the _filter_ and _collapseThreads_ arguments).
o *threadIds*: "String[]" The list of Thread ids for each message in
the list after filtering, sorting and collapsing threads, starting
at the index given by the _position_ argument of this response,
and continuing until it hits the end of the list or reaches the
"limit" number of ids.
o *messageIds*: "String[]" The list of Message ids for each message
in the list after filtering, sorting and collapsing threads,
starting at the index given by the _position_ argument of this
response, and continuing until it hits the end of the list or
reaches the "limit" number of ids.
The following errors may be returned instead of the "messageList"
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
"unsupportedSort": Returned if the _sort_ includes a property the
server does not support sorting on.
"cannotDoFilter": Returned if the server is unable to process the
given _filter_ for any reason.
"invalidArguments": Returned if the request does not include one of
the required arguments, or one of the arguments is of the wrong type,
or otherwise invalid. A "description" property MAY be present on the
response object to help debug with an explanation of what the problem
was.
"anchorNotFound": Returned if an anchor argument was supplied, but it
cannot be found in the message list.
3.2. getMessageListUpdates
The "getMessageListUpdates" call allows a client to efficiently
update the state of any cached message list to match the new state on
the server. It takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If "null", the primary account will be used.
o *filter*: "FilterCondition|FilterOperator|null" The filter
argument that was used with _getMessageList_.
o *sort*: "String[]|null" The sort argument that was used with
_getMessageList_.
o *collapseThreads*: "Boolean|null" The _collapseThreads_ argument
that was used with _getMessageList_.
o *sinceState*: "String" The current state of the client. This is
the string that was returned as the _state_ argument in the
_messageList_ response. The server will return the changes made
since this state.
o *uptoMessageId*: "String|null" The message id of the last message
in the list that the client knows about. In the common case of
the client only having the first X ids cached, this allows the
server to ignore changes further down the list the client doesn't
care about.
o *maxChanges*: "Number|null" The maximum number of changes to
return in the response. See below for a more detailed
description.
The response to _getMessageListUpdates_ is called
_messageListUpdates_ It has the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *filter*: "FilterCondition|FilterOperator|null" The filter of the
message list. Echoed back from the call.
o *sort*: "String[]|null" A list of Message property names used to
sort by. Echoed back from the call.
o *collapseThreads*: "Boolean|null" Echoed back from the call.
o *oldState*: "String" This is the "sinceState" argument echoed
back; the state from which the server is returning changes.
o *newState*: "String" This is the state the client will be in after
applying the set of changes to the old state.
o *uptoMessageId*: "String|null" Echoed back from the call.
o *total*: "Number" The total number of messages in the message list
(given the filter and collapseThreads arguments).
o *removed*: "RemovedItem[]" The _messageId_ and _threadId_ for
every message that was in the list in the old state and is not in
the list in the new state. If the server cannot calculate this
exactly, the server MAY return extra messages in addition that MAY
have been in the old list but are not in the new list. If an
_uptoMessageId_ was given AND this id was found in the list, only
messages positioned before this message that were removed need be
returned. In addition, if the sort includes a keyword, the server
MUST include all messages in the current list for which this
keyword MAY have changed. If the sort includes a "some/all-in-
thread-keyword", then the server MUST include all messages in the
current list for which this keyword MAY have changed *on any of
the messages in the thread*.
o *added*: "AddedItem[]" The messageId and threadId and index in the
list (in the new state) for every message that has been added to
the list since the old state AND every message in the current list
that was included in the _removed_ array (due to a filter or sort
based upon a mutable property). The array MUST be sorted in order
of index, lowest index first. If an _uptoMessageId_ was given AND
this id was found in the list, only messages positioned before
this message that have been added need be returned.
A *RemovedItem* object has the following properties:
o *messageId*: "String"
o *threadId*: "String"
An *AddedItem* object has the following properties:
o *messageId*: "String"
o *threadId*: "String"
o *index*: "Number"
The result of this should be that if the client has a cached sparse o "name"
array of message ids in the list in the old state:
messageIds = [ "id1", "id2", null, null, "id3", "id4", null, null, null ] 2.4. getMailboxListUpdates
then if it *splices out* all messages in the removed array: Standard _getFooListUpdates_ method.
removed = [{ messageId: "id2", ... }]; 2.5. setMailboxes
messageIds => [ "id1", null, null, "id3", "id4", null, null, null ]
and *splices in* (in order) all of the messages in the added array: Standard _setFoos_ method. The following extra _SetError_ types are
defined:
added = [{ messageId: "id5", index: 0, ... }]; For *create*:
messageIds => [ "id5", "id1", null, null, "id3", "id4", null, null, null ]
then the message list will now be in the new state. o "maxQuotaReached": The user has reached a server-defined limit on
the number of mailboxes.
The following errors may be returned instead of the For *update*:
"messageListUpdates" response:
"accountNotFound": Returned if an _accountId_ was explicitly included o "forbidden": The update would violate a mayXXX property.
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given For *destroy*:
corresponds to a valid account, but the account does not support this
data type.
"invalidArguments": Returned if the request does not include one of o "forbidden": The update would violate a mayXXX property.
the required arguments, or one of the arguments is of the wrong type,
or otherwise invalid. A _description_ property MAY be present on the
response object to help debug with an explanation of what the problem
was.
"tooManyChanges": Returned if there are more changes the the client's o "mailboxHasChild": The mailbox still has at least one child
_maxChanges_ argument. Each item in the removed or added array is mailbox. The client MUST remove these before it can delete the
considered as one change. The client may retry with a higher max parent mailbox.
changes or invalidate its cache of the message list.
"cannotCalculateChanges": Returned if the server cannot calculate the o "mailboxHasMessage": The mailbox has at least one message assigned
changes from the state string given by the client. Usually due to to it. The client MUST remove these before it can delete the
the client's state being too old. The client MUST invalidate its mailbox.
cache of the message list.
4. 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 messages, ordered thread. In JMAP, a thread is simply a flat list of messages, ordered
by date. Every message MUST belong to a thread, even if it is the by date. Every message MUST belong to a thread, even if it is the
only message in the thread. only message in the thread.
The JMAP spec does not require the server to use any particular The JMAP spec does not require the server to use any particular
algorithm for determining whether two messages belong to the same algorithm for determining whether two messages belong to the same
thread, however there is a recommended algorithm in the thread, however there is a recommended algorithm in the
implementation guide [1]. implementation guide [1].
skipping to change at page 27, line 28 skipping to change at page 10, line 28
receive two messages in the same thread but without headers that receive two messages in the same thread but without headers that
associate them with each other. The arrival of a third message in associate them with each other. The arrival of a third message in
the thread may provide the missing references to join them all the thread may provide the missing references to join them all
together into a single thread. Since the "threadId" of a message is together into a single thread. Since the "threadId" of a message is
immutable, if the server wishes to merge the threads, it MUST handle immutable, if the server wishes to merge the threads, it MUST handle
this by deleting and reinserting (with a new message id) the messages this by deleting and reinserting (with a new message id) the messages
that change threadId. that change threadId.
A *Thread* object has the following properties: A *Thread* object has the following properties:
o *id*: "String" The id of the thread. This property is immutable. o *id*: "String" (immutable) The id of the thread.
o *messageIds*: "String[]" The ids of the messages in the thread, o *messageIds*: "String[]" The ids of the messages in the thread,
sorted such that: sorted such that:
* Any message with the "$Draft" keyword that has an "In-Reply-To" * Any message with the "$Draft" keyword that has an "In-Reply-To"
header is sorted after the _first_ non-draft message in the header is sorted after the _first_ non-draft message in the
thread with the corresponding "Message-Id" header, but before thread with the corresponding "Message-Id" header, but before
any subsequent non-draft messages. any subsequent non-draft messages.
* Other than that, everything is sorted in _date_ order (as * Other than that, everything is sorted in _date_ order (as
determined by the date property on the _Message_ object), determined by the date property on the _Message_ object),
oldest first. oldest first.
* If two messages are identical under the above two conditions, * If two messages are identical under the above two conditions,
the sort is server-dependent but MUST be stable (sorting by id the sort is server-dependent but MUST be stable (sorting by id
is recommended). is recommended).
4.1. getThreads The following JMAP methods are supported:
Threads can only be fetched explicitly by id. To fetch threads, make
a call to _getThreads_. It takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If not given, defaults to the primary account.
o *ids*: "String[]" An array of ids for the threads to fetch.
o *fetchMessages*: "Boolean|null" If true, after outputting a
_threads_ response, an implicit call will be made to _getMessages_
with a list of all message ids in the returned threads as the
_ids_ argument, and the _fetchMessageProperties_ argument as the
_properties_ argument. If "false" or "null", no implicit call
will be made.
o *fetchMessageProperties*: "String[]|null" The list of properties
to fetch on any fetched messages. See _getMessages_ for a full
description.
The response to _getThreads_ is called _threads_. It has the
following arguments:
o *accountId*: "String" The id of the account used for the call.
o *state*: "String" A string encoding the current state on the
server. This string will change if any threads change (that is,
new messages arrive, or messages are deleted, as these are the
only two events that change thread membership). It can be passed
to _getThreadUpdates_ to efficiently get the list of changes from
the previous state.
o *list*: "Thread[]" An array of Thread objects for the requested
thread ids. This may not be in the same order as the ids were in
the request.
o *notFound*: "String[]|null" An array of thread ids requested which
could not be found, or "null" if all ids were found.
The following errors may be returned instead of the "threads"
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given 3.1. getThreads
corresponds to a valid account, but the account does not support this
data type.
"requestTooLarge": Returned if the number of _ids_ requested by the Standard _getFoos_ method.
client exceeds the maximum number the server is willing to process in
a single method call.
"invalidArguments": Returned if the request does not include one of 3.1.1. Example
the required arguments, or one of the arguments is of the wrong type,
or otherwise invalid. A _description_ property MAY be present on the
response object to help debug with an explanation of what the problem
was.
Example of a successful request: Request:
[ "getThreads", { [ "getThreads", {
"ids": ["f123u4", "f41u44"], "ids": ["f123u4", "f41u44"],
"fetchMessages": false, }, "#1" ]
"fetchMessageProperties": null
}, "#1" ]
and response: with response:
[ "threads", { [ "threads", {
"accountId": "acme",
"state": "f6a7e214", "state": "f6a7e214",
"list": [ "list": [
{ {
"id": "f123u4", "id": "f123u4",
"messageIds": [ "eaa623", "f782cbb"] "messageIds": [ "eaa623", "f782cbb"]
}, },
{ {
"id": "f41u44", "id": "f41u44",
"messageIds": [ "82cf7bb" ] "messageIds": [ "82cf7bb" ]
} }
], ],
"notFound": null "notFound": null
}, "#1" ] }, "#1" ]
4.2. getThreadUpdates 3.2. getThreadUpdates
When messages are created or deleted, new threads may be created, or
the set of messages belonging to an existing thread may change. If a
call to _getThreads_ returns with a different _state_ string in the
response to a previous call, the state of the threads has changed on
the server and the client needs to work out which part of its cache
is now invalid.
The _getThreadUpdates_ call allows a client to efficiently update the
state of any cached threads to match the new state on the server. It
takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If not given, defaults to the primary account.
o *sinceState*: "String" The current state of the client. This is
the string that was returned as the _state_ argument in the
_threads_ response. The server will return the changes made since
this state.
o *maxChanges*: "Number|null" The maximum number of Thread ids to
return in the response. The server MAY choose to clamp this value
to a particular maximum or set a maximum if none is given by the
client. If supplied by the 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 call with an "invalidArguments"
error.
o *fetchRecords*: "Boolean|null" If "true", immediately after
outputting a _threadUpdates_ response, an implicit call will be
made to _getThreads_ with the _changed_ property of the response
as the _ids_ argument, and _fetchMessages_ equal to "false".
The response to _getThreadUpdates_ is called _threadUpdates_. It has
the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *oldState*: "String" This is the _sinceState_ argument echoed
back; the state from which the server is returning changes.
o *newState*: "String" This is the state the client will be in after
applying the set of changes to the old state.
o *hasMoreUpdates*: "Boolean" If "true", the client may call
_getThreadUpdates_ again with the _newState_ returned to get
further updates. If "false", _newState_ is the current server
state.
o *changed*: "String[]" An array of thread ids where the list of
messages within the thread has changed between the old state and
the new state, and the thread currently has at least one message
in it.
o *removed*: "String[]" An array of thread ids where the list of
messages within the thread has changed since the old state, and
there are now no messages in the thread.
If a _maxChanges_ is supplied, or set automatically by the server,
the server MUST ensure the number of ids returned across _changed_
and _removed_ does not exceed this limit. If there are more changes
than this between the client's state and the current server state,
the update returned SHOULD generate an update to take the client to
an intermediate state, from which the client can continue to call
_getThreadUpdates_ until it is fully up to date. If it is unable to
calculate an intermediate state, it MUST return a
"cannotCalculateChanges" error response instead.
If a thread has been modified AND deleted since the oldState, the
server SHOULD just return the id in the _removed_ response, but MAY
return it in the changed response as well. If a thread has been
created AND deleted since the oldState, the server SHOULD remove the
thread id from the response entirely, but MAY include it in the
_removed_ response.
The following errors may be returned instead of the _threadUpdates_
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
"invalidArguments": Returned if the request does not include one of
the required arguments, or one of the arguments is of the wrong type,
or otherwise invalid. A _description_ property MAY be present on the
response object to help debug with an explanation of what the problem
was.
"cannotCalculateChanges": Returned if the server cannot calculate the
changes from the state string given by the client. Usually due to
the client's state being too old, or the server being unable to
produce an update to an intermediate state when there are too many
updates. The client MUST invalidate its Thread cache.
5. Messages
Just like in IMAP, a message is *immutable* except for the boolean Standard _getFooUpdates_ method.
"isXXX" status properties and the set of mailboxes it is in. This
allows for more efficient caching of messages, and gives easier
backwards compatibility for servers implementing an IMAP interface to
the same data.
JMAP completely hides the complexities of MIME. All special 4. Messages
encodings of either headers or textual body parts, such as base64
[2], or RFC 2047 [3] encoding of non-ASCII characters, MUST be fully
decoded into UTF-8.
A *Message* object has the following properties: A *Message* object is a JSON representation of an [RFC5322] message
that hides the complexities of MIME. All special encodings of either
headers or textual body parts, such as Base64 ([RFC4648]), or
[RFC2047] encoding of non-ASCII characters, MUST be fully decoded
into UTF-8. It has the following properties:
o *id*: "String" The id of the message. o *id*: "String" (immutable; server-set) The id of the message.
This is the JMAP id, NOT the [RFC5322] Message-Id header.
o *blobId*: "String" The id representing the raw [RFC5322] message. o *blobId*: "String" (immutable; server-set) The id representing the
This may be used to download the original message or to attach it raw [RFC5322] message. This may be used to download the original
directly to another message etc. message or to attach it directly to another message etc.
o *threadId*: "String" The id of the thread to which this message o *threadId*: "String" (immutable; server-set) The id of the thread
belongs. to which this message belongs.
o *mailboxIds*: "String[]" (Mutable) The ids of the mailboxes the o *mailboxIds*: "String[Boolean]" The set of mailbox ids this
message is in. A message MUST belong to one or more mailboxes at message is in. A message MUST belong to one or more mailboxes at
all times (until it is deleted). all 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 object MUST be "true".
o *keywords*: "String[Boolean]" (Mutable) A set of keywords that o *keywords*: "String[Boolean]" (default: "{}") A set of keywords
apply to the message. The set is represented as an object, with that apply to the message. The set is represented as an object,
the keys being the _keywords_. The value for each key in the with the keys being the _keywords_. The value for each key in the
object MUST be "true". Keywords are shared with IMAP. The six object MUST be "true". Keywords are shared with IMAP. The six
system keywords from IMAP are treated specially. The following system keywords from IMAP are treated specially. The following
four keywords have their first character changed from "\" in IMAP four keywords have their first character changed from "\" in IMAP
to "$" in JMAP and have particular semantic meaning: to "$" in JMAP and have particular semantic meaning:
* "$Draft": The message is a draft the user is composing. * "$Draft": The message is a draft the user is composing.
* "$Seen": The message has been read. * "$Seen": The message has been read.
* "$Flagged": The message has been flagged for urgent/special * "$Flagged": The message has been flagged for urgent/special
attention. attention.
* "$Answered": The message has been replied to. * "$Answered": The message has been replied to.
The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP
"\Deleted" keyword is also not present: IMAP uses a delete+expunge "\Deleted" keyword is also not present: IMAP uses a delete+expunge
model, which JMAP does not. Any message with the "\Deleted" model, which JMAP does not. Any message with the "\Deleted"
keyword MUST NOT be visible via JMAP. Users may add arbitrary keyword MUST NOT be visible via JMAP. Users may add arbitrary
keywords to a message. For compatibility with IMAP, a keyword is keywords to a message. For compatibility with IMAP, a keyword is
a (case-sensitive) string of 1-255 characters in the ASCII subset a (case-sensitive) string of 1-255 characters in the ASCII subset
%x21-%x127 (excludes control chars and space), and MUST NOT %x21-%x7e (excludes control chars and space), and MUST NOT include
include any of these characters: "()]{%*"\" The IANA Keyword any of these characters: "( ) { ] % * " \" The IANA Keyword
Registry [4] as established in [RFC5788] assigns semantic meaning Registry [2] as established in [RFC5788] assigns semantic meaning
to some other keywords in common use. New keywords may be to some other keywords in common use. New keywords may be
established here in the future. In particular, note: established here in the future. In particular, note:
* "$Forwarded": The message has been forwarded. * "$Forwarded": The message has been forwarded.
* "$Phishing": The message is highly likely to be phishing. * "$Phishing": The message is highly likely to be phishing.
Clients SHOULD warn users to take care when viewing this Clients SHOULD warn users to take care when viewing this
message and disable links and attachments. message and disable links and attachments.
* "$Junk": The message is definitely spam. Clients SHOULD set * "$Junk": The message is definitely spam. Clients SHOULD set
this flag when users report spam to help train automated spam- this flag when users report spam to help train automated spam-
detection systems. detection systems.
* "$NotJunk": The message is definitely not spam. Clients SHOULD * "$NotJunk": The message is definitely not spam. Clients SHOULD
set this flag when users indicate a message is legitimate, to set this flag when users indicate a message is legitimate, to
help train automated spam-detection systems. help train automated spam-detection systems.
o *hasAttachment*: "Boolean" Does the message have any attachments? o *hasAttachment*: "Boolean" (immutable; server-set) This is "true"
if and only if the _attachments_ property for the Message contains
at least one entry where _isInline_ is "false".
o *headers*: "String[String]" A map of lower-cased header name to o *headers*: "String[String]" (immutable; default: "{}") A map of
(decoded) header value for all headers in the message. For lower-cased header name to (decoded) header value for all headers
headers that occur multiple times (e.g. "Received"), the values in the message. For headers that occur multiple times (e.g.
are concatenated with a single new line ("\n") character in "Received"), the values are concatenated with a single new line
between each one. ("\n") character in between each one.
o *sender*: "Emailer|null" An Emailer object (see below) containing o *sender*: "Emailer|null" (immutable; default: "null") An Emailer
the name/email from the parsed "Sender" header of the email. If object (see below) containing the name/email from the parsed
the email doesn't have a "Sender" header, this is "null". "Sender" header of the email. If the email doesn't have a
"Sender" header, this is "null".
o *from*: "Emailer[]|null" An array of name/email objects (see o *from*: "Emailer[]|null" (immutable; default: "null") An array of
below) representing the parsed "From" header of the email, in the name/email objects (see below) representing the parsed "From"
same order as they appear in the header. If the email doesn't header of the email, in the same order as they appear in the
have a "From" header, this is "null". If the header exists but header. If the email doesn't have a "From" header, this is
does not have any content, the response is an array of zero "null". If the header exists but does not have any content, the
length. response is an array of zero length.
o *to*: "Emailer[]|null" An array of name/email objects (see below) o *to*: "Emailer[]|null" (immutable; default: "null") An array of
representing the parsed "To" header of the email, in the same name/email objects (see below) representing the parsed "To" header
order as they appear in the header. If the email doesn't have a of the email, in the same order as they appear in the header. If
"To" header, this is "null". If the header exists but does not the email doesn't have a "To" header, this is "null". If the
have any content, the response is an array of zero length. header exists but does not have any content, the response is an
array of zero length.
o *cc*: "Emailer[]|null" An array of name/email objects (see below) o *cc*: "Emailer[]|null" (immutable; default: "null") An array of
representing the parsed "Cc" header of the email, in the same name/email objects (see below) representing the parsed "Cc" header
order as they appear in the header. If the email doesn't have a of the email, in the same order as they appear in the header. If
"Cc" header, this is "null". If the header exists but does not the email doesn't have a "Cc" header, this is "null". If the
have any content, the response is an array of zero length. header exists but does not have any content, the response is an
array of zero length.
o *bcc*: "Emailer[]|null" An array of name/email objects (see below) o *bcc*: "Emailer[]|null" (immutable; default: "null") An array of
representing the parsed "Bcc" header of the email. If the email name/email objects (see below) representing the parsed "Bcc"
doesn't have a "Bcc" header (which will be true for most emails header of the email. If the email doesn't have a "Bcc" header
outside of the Sent mailbox), this is "null". If the header (which will be true for most emails outside of the Sent mailbox),
exists but does not have any content, the response is an array of this is "null". If the header exists but does not have any
zero length. content, the response is an array of zero length.
o *replyTo*: "Emailer[]|null" An array of name/email objects (see o *replyTo*: "Emailer[]|null" (immutable; default: "null") An array
below) representing the parsed "Reply-To" header of the email, in of name/email objects (see below) representing the parsed "Reply-
the same order as they appear in the header. If the email doesn't To" header of the email, in the same order as they appear in the
have a "Reply-To" header, this is "null". If the header exists header. If the email doesn't have a "Reply-To" header, this is
but does not have any content, the response is an array of zero "null". If the header exists but does not have any content, the
length. response is an array of zero length.
o *subject*: "String" The subject of the message. o *subject*: "String" (immutable; default: """") The subject of the
message. If none, defaults to the empty string, not "null".
o *date*: "Date" The date the message was sent (or saved, if the o *date*: "Date" (immutable; default: time of creation on server)
message is a draft). The date the message was sent (or saved, if the message is a
draft).
o *size*: "Number" The size in bytes of the whole message as counted o *size*: "Number" (immutable; server-set) The size in bytes of the
by the server towards the user's quota. whole message as counted by the server towards the user's quota.
o *preview*: "String" Up to 256 characters of the beginning of a o *preview*: "String" (immutable; server-set) Up to 256 characters
plain text version of the message body. This is intended to be of the beginning of a plain text version of the message body.
shown as a preview line on a mailbox listing, and the server may This is intended to be shown as a preview line on a mailbox
choose to skip quoted sections or salutations to return a more listing, and the server may choose to skip quoted sections or
useful preview. salutations to return a more useful preview.
o *textBody*: "String" The plain text body part for the message. If o *textBody*: "String" (immutable; default: """") The plain text
there is only an HTML version of the body, a plain text version body part for the message. If there is only an HTML version of
MUST be generated from this; the exact method of conversion in the body, a plain text version MUST be generated from this; the
this case is not defined and is server-specific. If there is exact method of conversion in this case is not defined and is
neither a "text/plain" nor a "text/html" body part, this MUST be server-specific. If there is neither a "text/plain" nor a "text/
the empty string. html" body part, this MUST be the empty string.
o *htmlBody*: "String|null" The HTML body part for the message if o *htmlBody*: "String|null" (immutable; default: "null") The HTML
present. body part for the message if present.
o *attachments*: "Attachment[]|null" An array of attachment objects o *attachments*: "Attachment[]|null" (default: "null") An array of
(see below) detailing all the attachments to the message. attachment objects (see below) detailing all the attachments to
the message.
o *attachedMessages*: "String[Message]|null" An object mapping o *attachedMessages*: "String[Message]|null" (immutable; server-set)
attachment id (as found in the "attachments" property) to a An object mapping attachment id (as found in the "attachments"
*Message* object with the following properties, for each [RFC5322] property) to a *Message* object with the following properties, for
message attached to this one: each [RFC5322] message attached to this one:
* headers * headers
* from * from
* to * to
* cc * cc
* bcc * bcc
skipping to change at page 35, line 16 skipping to change at page 15, line 18
* date * date
* textBody * textBody
* htmlBody * htmlBody
* attachments * attachments
* attachedMessages * attachedMessages
This property is set by the server based on the _attachments_
property.
An *Emailer* object has the following properties: An *Emailer* object has the following properties:
o *name*: "String" The name of the sender/recipient. If a name o *name*: "String" The name of the sender/recipient. If a name
cannot be extracted for an email, this property SHOULD be the cannot be extracted for an email, this property SHOULD be the
empty string. empty string.
o *email*: "String" The email address of the sender/recipient. This o *email*: "String" The email address of the sender/recipient. This
MUST be of the form ""<mailbox>@<host>"" If a "host" or even MUST be of the form ""<mailbox>@<host>"" If a "host" or even
"mailbox" cannot be extracted for an email, the empty string "mailbox" cannot be extracted for an email, the empty string
SHOULD be used for this part (so the result MUST always still SHOULD be used for this part (so the result MUST always still
skipping to change at page 36, line 20 skipping to change at page 16, line 24
"cid:" link from within the HTML body of the message. "cid:" link from within the HTML body of the message.
o *width*: "Number|null" (optional, server MAY omit if not o *width*: "Number|null" (optional, server MAY omit if not
supported) The width (in px) of the image, if the attachment is an supported) The width (in px) of the image, if the attachment is an
image. image.
o *height*: "Number|null" (optional, server MAY omit if not o *height*: "Number|null" (optional, server MAY omit if not
supported) The height (in px) of the image, if the attachment is supported) The height (in px) of the image, if the attachment is
an image. an image.
5.1. getMessages To add an attachment, the file must first be uploaded using the
standard upload mechanism; this will give the client a blobId that
Messages can only be fetched explicitly by id. To fetch messages, may be used to identify the file. The "cid" property may be assigned
make a call to "getMessages". It takes the following arguments: by the client, and is solely used for matching up with "cid:<id>"
links inside the "htmlBody".
o *accountId*: "String|null" The id of the account to use for this
call. If not given, defaults to the primary account.
o *ids*: "String[]" An array of ids for the messages to fetch. The following JMAP methods are supported:
o *properties*: "String[]|null" A list of properties to fetch for 4.1. getMessages
each message. If "null", all properties will be fetched.
The "id" property is always returned, regardless of whether it is in Standard _getFoos_ method, except the client may use the following
the list of requested properties. The possible values for pseudo values in the _properties_ argument:
"properties" can be found above in the description of the Message
object. In addition to this, the client may request the following
special values:
o *body*: If ""body"" is included in the list of requested o *body*: If ""body"" is included in the list of requested
properties, it will be interpreted by the server as a request for properties, it MUST be interpreted by the server as a request for
""htmlBody"" if the message has an HTML part, or ""textBody"" ""htmlBody"" if the message has an HTML part, or ""textBody""
otherwise. otherwise.
o *headers.property*: Instead of requesting all the headers (by o *headers.property*: Instead of requesting all the headers (by
requesting the ""headers"" property, the client may specify the requesting the ""headers"" property, the client may specify the
particular headers it wants using the "headers.property-name" particular headers it wants using the "headers.property-name"
syntax, e.g. ""headers.x-spam-score", "headers.x-spam-hits""). syntax, e.g. ""headers.x-spam-score", "headers.x-spam-hits"").
The server will return a _headers_ property but with just the The server MUST return a _headers_ property but with just the
requested headers in the object rather than all headers. If requested headers in the object rather than all headers. If
""headers"" is requested, the server MUST ignore the individual ""headers"" is requested, the server MUST ignore the individual
header requests and just return all headers. If a requested header requests and just return all headers. If a requested
header is not present in the message, it MUST not be present in header is not present in the message, it MUST NOT be present in
the _headers_ object. Header names are case-insensitive. the _headers_ object. Header names are case-insensitive.
The response to _getMessages_ is called _messages_. It has the 4.1.1. Example
following arguments:
o *accountId*: "String" The id of the account used for the call.
o *state*: "String" A string encoding the current state on the
server. This string will change if any messages change (that is,
a new message arrives, a change is made to one of the mutable
properties, or a message is deleted). It can be passed to
_getMessageUpdates_ to efficiently get the list of changes from
the previous state.
o *list*: "Message[]" An array of Message objects for the requested
message ids. This may not be in the same order as the ids were in
the request.
o *notFound*: "String[]|null" An array of message ids requested
which could not be found, or "null" if all ids were found.
The following errors may be returned instead of the _messages_
response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
"requestTooLarge": Returned if the number of _ids_ requested by the
client exceeds the maximum number the server is willing to process in
a single method call.
"invalidArguments": Returned if the request does not include one of
the required arguments, or one of the arguments is of the wrong type,
or otherwise invalid. A _description_ property MAY be present on the
response object to help debug with an explanation of what the problem
was.
Example request: Request:
["getMessages", { ["getMessages", {
"ids": [ "f123u456", "f123u457" ], "ids": [ "f123u456", "f123u457" ],
"properties": [ "threadId", "mailboxIds", "from", "subject", "date" ] "properties": [ "threadId", "mailboxIds", "from", "subject", "date" ]
}, "#1"] }, "#1"]
and response: and response:
["messages", { ["messages", {
"accountId": "abc",
"state": "41234123231", "state": "41234123231",
"list": [ "list": [
{ {
messageId: "f123u457", id: "f123u457",
threadId: "ef1314a", threadId: "ef1314a",
mailboxIds: [ "f123" ], 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?",
date: "2013-10-13T14:12:00Z" date: "2013-10-13T14:12:00Z"
} }
], ],
notFound: [ "f123u456" ] notFound: [ "f123u456" ]
}, "#1"] }, "#1"]
5.2. getMessageUpdates 4.2. getMessageUpdates
If a call to _getMessages_ returns with a different _state_ string in
the response to a previous call, the state of the messages has
changed on the server. For example, a new message may have been
delivered, or an existing message may have changed mailboxes.
The _getMessageUpdates_ call allows a client to efficiently update
the state of any cached messages to match the new state on the
server. It takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this
call. If not given, defaults to the primary account.
o *sinceState*: "String" The current state of the client. This is
the string that was returned as the _state_ argument in the
_messages_ response. The server will return the changes made
since this state.
o *maxChanges*: "Number|null" The maximum number of changed messages
to return in the response. The server MAY choose to clamp this
value to a particular maximum or set a maximum if none is given by
the client. If supplied by the 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 call with an
"invalidArguments" error.
o *fetchRecords*: "Boolean|null" If true, immediately after
outputting a _messageUpdates_ response, an implicit call will be
made to _getMessages_ with a list of all message ids in the
_changed_ argument of the response as the _ids_ argument, and the
_fetchRecordProperties_ argument as the _properties_ argument.
o *fetchRecordProperties*: "String[]|null" The list of properties to
fetch on any fetched messages. See _getMessages_ for a full
description.
The response to _getMessageUpdates_ is called _messageUpdates_. It
has the following arguments:
o *accountId*: "String" The id of the account used for the call. Standard _getFooUpdates_ method.
o *oldState*: "String" This is the _sinceState_ argument echoed 4.3. getMessageList
back; the state from which the server is returning changes.
o *newState*: "String" This is the state the client will be in after Standard _getFooList_ method, but with the following additional
applying the set of changes to the old state. arguments:
o *hasMoreUpdates*: "Boolean" If "true", the client may call o *collapseThreads*: "Boolean" (default: "false") If "true",
_getMessageUpdates_ again with the _newState_ returned to get messages in the same thread as a previous message in the list
further updates. If "false", _newState_ is the current server (given the filter and sort order) will be removed from the list.
state. This means at most only one message will be included in the list
for any given thread.
o *changed*: "String[]" An array of message ids for messages that 4.3.1. Filtering
have either been created or had their state change, and are not
currently deleted.
o *removed*: "String[]" An array of message ids for messages that A *FilterOperator* object has the following properties:
have been deleted since the oldState.
If a _maxChanges_ is supplied, or set automatically by the server, o *operator*: "String" This MUST be one of the following strings:
the server MUST ensure the number of ids returned across _changed_ "AND"/"OR"/"NOT":
and _removed_ does not exceed this limit. If there are more changes
than this between the client's state and the current server state,
the update returned SHOULD generate an update to take the client to
an intermediate state, from which the client can continue to call
_getMessageUpdates_ until it is fully up to date. If it is unable to
calculate an intermediate state, it MUST return a
"cannotCalculateChanges" error response instead.
If a message has been modified AND deleted since the oldState, the * *AND*: all of the conditions must match for the filter to
server SHOULD just return the id in the _removed_ response, but MAY match.
return it in the changed response as well. If a message has been
created AND deleted since the oldState, the server SHOULD remove the
message id from the response entirely, but MAY include it in the
_removed_ response, and (if in the _removed_ response) MAY included
it in the _changed_ response as well.
The following errors may be returned instead of the _messageUpdates_ * *OR*: at least one of the conditions must match for the filter
response: to match.
"accountNotFound": Returned if an _accountId_ was explicitly included * *NOT*: none of the conditions must match for the filter to
with the request, but it does not correspond to a valid account. match.
"accountNotSupportedByMethod": Returned if the _accountId_ given o *conditions*: "(FilterCondition|FilterOperator)[]" The conditions
corresponds to a valid account, but the account does not support this to evaluate against each message.
data type.
"invalidArguments": Returned if the request does not include one of A *FilterCondition* object has the following properties, any of which
the required arguments, or one of the arguments is of the wrong type, may be omitted:
or otherwise invalid. A _description_ property MAY be present on the
response object to help debug with an explanation of what the problem
was.
"cannotCalculateChanges": Returned if the server cannot calculate the o *inMailbox*: "String" A mailbox id. A message must be in this
changes from the state string given by the client. Usually due to mailbox to match the condition.
the client's state being too old, or the server being unable to
produce an update to an intermediate state when there are too many
updates. The client MUST invalidate its Message cache.
5.3. setMessages o *inMailboxOtherThan*: "String" A mailbox id. A message be in any
mailbox other than this one to match the condition. This is to
allow messages solely in trash/spam to be easily excluded from a
search.
The _setMessages_ method encompasses: o *before*: "Date" The date of the message (as returned on the
Message object) must be before this date to match the condition.
o Creating a draft message o *after*: "Date" The date of the message (as returned on the
Message object) must be on or after this date to match the
condition.
o Sending a message o *minSize*: "Number" The size of the message in bytes (as returned
on the Message object) must be equal to or greater than this
number to match the condition.
o Changing the flags of a message (unread/flagged status) o *maxSize*: "Number" The size of the message in bytes (as returned
on the Message object) must be less than this number to match the
condition.
o Adding/removing a message to/from mailboxes (moving a message) o *allInThreadHaveKeyword*: "String" All messages (including this
one) in the same thread as this message must have the given
keyword to match the condition.
o Deleting messages o *someInThreadHaveKeyword*: "String" At least one message (possibly
this one) in the same thread as this message must have the given
keyword to match the condition.
It takes the following arguments: o *noneInThreadHaveKeyword*: "String" All messages (including this
one) in the same thread as this message must *not* have the given
keyword to match the condition.
o *accountId*: "String|null" The id of the account to use for this o *hasKeyword*: "String" This message must have the given keyword to
call. If not given, defaults to the primary account. match the condition.
o *ifInState*: "String|null" This is a state string as returned by o *notKeyword*: "String" This message must not have the given
the _getMessages_ method. If supplied, the string must match the keyword to match the condition.
current state, otherwise the method will be aborted and a
"stateMismatch" error returned. If "null", any changes will be
applied to the current state.
o *create*: "String[Message]|null" A map of _creation id_ (an o *hasAttachment*: "Boolean" The "hasAttachment" property of the
arbitrary string set by the client) to Message objects (see below message must be identical to the value given to match the
for a detailed description). condition.
o *update*: "String[Message]|null" A map of message id to objects o *text*: "String" Looks for the text in messages. The server
containing the properties to update for that Message. SHOULD look up text in the _from_, _to_, _cc_, _bcc_, _subject_,
_textBody_, _htmlBody_ or _attachments_ properties of the message.
The server MAY extend the search to any additional textual
property.
o *destroy*: "String[]|null" A list of ids for Message objects to o *from*: "String" Looks for the text in the _from_ property of the
permanently delete. message.
Each create, update or destroy is considered an atomic unit. It is o *to*: "String" Looks for the text in the _to_ property of the
permissible for the server to commit some of the changes but not message.
others, however it is not permissible to only commit part of an
update to a single record (e.g. update the _keywords_ field but not
the _mailboxIds_ field, if both are supplied in the update object for
a message).
If a create, update or destroy is rejected, the appropriate error o *cc*: "String" Looks for the text in the _cc_ property of the
MUST be added to the notCreated/notUpdated/notDestroyed property of message.
the response and the server MUST continue to the next create/update/
destroy. It does not terminate the method.
If an id given cannot be found, the update or destroy MUST be o *bcc*: "String" Looks for the text in the _bcc_ property of the
rejected with a "notFound" set error. message.
5.3.1. Saving a draft o *subject*: "String" Looks for the text in the _subject_ property
of the message.
Creating messages via the _setMessages_ method is only for creating o *body*: "String" Looks for the text in the _textBody_ or
draft messages and sending them. For delivering/importing a complete _htmlBody_ property of the message.
[RFC5322] message, use the "importMessages" method.
The properties of the Message object submitted for creation MUST o *attachments*: "String" Looks for the text in the attachments of
conform to the following conditions: the message. Server MAY handle text extraction when possible for
the different kinds of media.
o *id*: This property MUST NOT be included. It is set by the server o *header*: "String[]" The array MUST contain either one or two
upon creation. elements. The first element is the name of the header to match
against. The second (optional) element is the text to look for in
the header. If not supplied, the message matches simply if it
_has_ a header of the given name.
o *blobId*: This property MUST NOT be included. It is set by the If zero properties are specified on the FilterCondition, the
server upon creation. condition MUST always evaluate to "true". If multiple properties are
specified, ALL must apply for the condition to be "true" (it is
equivalent to splitting the object into one-property conditions and
making them all the child of an AND filter operator).
o *threadId*: This property MUST NOT be included. It is set by the The exact semantics for matching "String" fields is *deliberately not
server upon creation. defined* to allow for flexibility in indexing implementation, subject
to the following:
o *mailboxIds*: This property MUST be included. The value MUST o Text SHOULD be matched in a case-insensitive manner.
include the id of either the mailbox with "role == "drafts"" (to
save a draft) or the mailbox with "role == "outbox"" (to send the
message). If this mailbox does not have "mustBeOnlyMailbox ==
true", others may be included too.
o *keywords*: This property MUST be included. It MUST include the o Text contained in either (but matched) single or double quotes
"$Draft" keyword and SHOULD also include "$Seen". SHOULD be treated as a *phrase search*, that is a match is
required for that exact word or sequence of words, excluding the
surrounding quotation marks. Use "\"", "\'" and "\\" to match a
literal """, "'" and "\" respectively in a phrase.
o *hasAttachment*: This property MUST NOT be included. It is set by o Outside of a phrase, white-space SHOULD be treated as dividing
the server upon creation based on the attachments property. separate tokens that may be searched for separately in the
message, but MUST all be present for the message to match the
filter.
o *headers*: Optional. The keys MUST only contain the characters o Tokens MAY be matched on a whole-word basis using stemming (so for
a-z (lower-case only), 0-9 and hyphens. example a text search for "bus" would match "buses" but not
"business").
o *from*: Optional. Overrides a "From" in the _headers_. o When searching inside the _htmlBody_ property, HTML tags and
attributes SHOULD be ignored.
o *to*: Optional. Overrides a "To" in the _headers_. 4.3.2. Sorting
o *cc*: Optional. Overrides a "Cc" in the _headers_. The following properties MUST be supported for sorting:
o *bcc*: Optional. Overrides a "Bcc" in the _headers_. o *date* - The date as returned in the Message object.
o *replyTo*: Optional. Overrides a "Reply-To" in the _headers_. The following properties SHOULD be supported for sorting:
o *subject*: Optional. Defaults to the empty string (""""). o *size* - The size as returned in the Message object.
o *date*: Optional. If included, the server SHOULD wait until this o *from* - This is taken to be either the "name" part of the Emailer
time to send the message (once moved to the outbox mailbox). object, or if none then the "email" part of the Emailer object
Until it is sent, the send may be cancelled by moving the message (see the definition of the from property in the Message object).
back out of the outbox mailbox. If the date is in the past, the If still none, consider the value to be the empty string.
message must be sent immediately. A client may find out if the
server supports delayed sending by querying the server's
_capabilities_ object (see section 1).
o *size*: This MUST NOT be included. It is set by the server upon o *to* - This is taken to be either the "name" part of the *first*
creation. Emailer object, or if none then the "email" part of the *first*
Emailer object (see the definition of the to property in the
Message object). If still none, consider the value to be the
empty string.
o *preview*: This MUST NOT be included. It is set by the server o *subject* - This is taken to be the subject of the Message with
upon creation. any ignoring any leading "Fwd:"s or "Re:"s (case-insensitive
match).
o *textBody*: Optional. If not supplied and an htmlBody is, the o *keyword:*"$keyword" - This value MUST be considered "true" if the
server SHOULD generate a text version for the message from the message has the keyword, or "false" otherwise.
HTML body.
o *htmlBody*: Optional. o *allThreadKeyword:*"$keyword" - This value MUST be considered
"true" for the message if *all* of the messages in the same thread
(regardless of mailbox) have the keyword.
o *attachments*: Optional. An array of Attachment objects detailing o *someThreadKeyword:*"$keyword" - This value MUST be considered
all the attachments to the message. To add an attachment, the "true" for the message if *any* of the messages in the same thread
file must first be uploaded using the standard upload mechanism; (regardless of mailbox) have the keyword.
this will give the client a blobId that may be used to identify
the file. The "cid" property may be assigned by the client, and
is solely used for matching up with "cid:<id>" links inside the
"htmlBody". The server MAY change the cids upon sending.
If any of the files specified in _attachments_ cannot be found, the The server MAY support sorting based on other properties as well. A
creation MUST be rejected with an "invalidProperties" error. An client can discover which properties are supported by inspecting the
extra property SHOULD be included in the error object called server's _capabilities_ object (see section 1).
"attachmentsNotFound", of type "String[]", which SHOULD be an array
of the _blobId_ of every attachment that could not be found on the
server. - *attachedMessages*: This MUST NOT be included.
All optional properties default to "null" unless otherwise stated. Example sort:
Where included, properties MUST conform to the type given in the
Message object definition.
If any of the properties are invalid, the server MUST reject the `[ "someThreadKeyword:$Flagged desc", "date desc" ]
create with an "invalidProperties" error. The Error object SHOULD
contain a property called _properties_ of type "String[]" that lists
*all* the properties that were invalid. The object MAY also contain
a _description_ property of type "String" with a user-friendly
description of the problems.
Other than making sure it conforms to the correct type, the server This would sort messages in flagged threads first (the thread is
MUST NOT attempt to validate from/to/cc/bcc when saved as a draft. considered flagged if any message within it is flagged), and then in
This is to ensure messages can be saved at any point. Validation date order, newest first. If two messages have both identical
occurs when the user tries to send a message. flagged status and date, the order is server-dependent but must be
stable.
If a draft cannot be saved due to the user reaching their maximum 4.3.3. Thread collapsing
mail storage quota, the creation MUST be rejected with a
"maxQuotaReached" error.
5.3.2. Updating messages When "collapseThreads == true", then after filtering and sorting the
message list, the list is further winnowed by removing any messages
for a thread id that has already been seen (when passing through the
list sequentially). A thread will therefore only appear *once* in
the "threadIds" list of the result, at the position of the first
message in the list that belongs to the thread.
Messages are mainly immutable, so to update a draft the client must 4.3.4. Response
create a new message and delete the old one. This ensures that if
the draft is also being edited elsewhere, the two will split into two
different drafts to avoid data loss.
Only the _mailboxIds_ and _keywords_ properties may be modified, and The _messageList_ response has the following additional argument:
they are subject to the following constraints:
o *mailboxIds*: The server MUST reject any attempt to add a message o *collapseThreads*: "Boolean" The _collapseThreads_ value that was
to the outbox that does not have the "$Draft" keyword with an used when calculating the message list for this call.
"invalidProperties" error.
o *keywords*: The server MUST reject any attempt to add or remove 4.4. getMessageListUpdates
the "$Draft" flag in an update with an "invalidProperties" error.
The server MAY have a maximum number of keywords it supports; if
the change would exceed this, it MUST be rejected with a
"tooManyKeywords" error.
Note, a mailbox id may be a _creation id_ (see "setFoos" for a Standard _getFooListUpdates_ method, with the following additional
description of how this works). arguments:
If any of the properties in the update are invalid (immutable and o *collapseThreads*: "Boolean" (default: "false") The
different to the current server value, wrong type, invalid value for _collapseThreads_ argument that was used with _getMessageList_.
the property - like a mailbox id for non-existent mailbox), the
server MUST reject the update with an "invalidProperties" error. The
Error object SHOULD contain a property called _properties_ of type
"String[]" that lists *all* the properties that were invalid. The
object MAY also contain a _description_ property of type "String"
with a user-friendly description of the problems.
If the _id_ given does not correspond to a Message in the given The _messageListUpdates_ response has the following additional
account, reject the update with a "notFound" error. arguments:
To *delete a message* to trash, simply change the "mailboxIds" o *collapseThreads*: "Boolean" The _collapseThreads_ value that was
property so it is now in the mailbox with "role == "trash"", and used when calculating the message list for this call.
remove all other mailbox ids.
5.3.3. Sending messages 4.5. setMessages
To send a message, either create a new message directly into the Standard _setFoos_ method. The _setMessages_ method encompasses:
mailbox with "role == "outbox"" or move an existing draft into this
mailbox. At this point the server will check that it has everything
it needs for a valid message. In particular, that it has a valid
"From" address (and the user has permission to use this From
address), it has at least one address to send to, and all addresses
in To/Cc/Bcc are valid email addresses. If it cannot send, it will
reject the creation/update with an "invalidProperties" error. The
Error object SHOULD contain a property called _properties_ of type
"String[]" that lists *all* the properties that were invalid. The
object SHOULD also contain a _description_ property of type "String"
with a user-friendly description of the problems to present to the
user.
If the message is accepted, the server SHOULD *asynchronously* o Creating a draft message
schedule the message to be sent *after* this method call is complete
(note, this MAY occur before the next method in the same API request
or after the whole API request is complete). This means that the
"newState" string in the response represents a state where the
message is still in the outbox.
When the message is sent, the server MUST remove the message from the o Changing the flags of a message (unread/flagged status)
*outbox* and add it to the *sent* mailbox, unless the user has
indicated another preference. The version added to the sent mailbox
MAY be different (for example have extra headers added by the
server), and so have a different id to the version that was in the
outbox. If the message has an "In-Reply-To" header, the server
SHOULD add the "$Answered" keyword to all messages with the
coresponding "Message-Id" header at this point. If the message has
an "X-Forwarded-Message-Id" header, the server SHOULD add the
"$Forwarded" keyword to all messages with the coresponding "Message-
Id" header at this point.
The server is responsible for either reporting an error (normally a o Adding/removing a message to/from mailboxes (moving a message)
"bounce" email), or ensuring delivery of the message to the next hop.
5.3.4. Cancelling a send o Deleting messages
A message may be moved out of the *outbox* and back to the *drafts* When creating a message, the _headers_ property specifies extra
mailbox using the standard update message mechanism, if it has not headers to add in addition to any based off the parsed properties
yet been sent at the time the method is called. This MUST cancel the (like _from_/_to_/_subject_). The keys MUST only contain the
queued send. If the message has already been sent then it will have characters a-z (lower-case only), 0-9 and hyphens. If a header is
been deleted from the outbox, so the update will fail with a standard included that conflicts with one of the other properties on the
"notFound" error. Message object (e.g. _from_, _date_), the value in the _headers_
object MUST be ignored.
5.3.5. Destroying messages The server MAY also choose to set additional headers. If not
included, the server MUST generate and set a "Message-Id" header in
conformance with [RFC5322] section 3.6.4.
If the _id_ given does not correspond to a Message in the given Other than making sure it conforms to the correct type, the server
account, the server MUST reject the destruction with a "notFound" MUST NOT attempt to validate _from_/_to_/_cc_/_bcc_ (e.g. checking if
error. an email address is valid) when creating a message. This is to
ensure draft messages can be saved at any point.
Destroying a message removes it from all mailboxes to which it Destroying a message removes it from all mailboxes to which it
belonged. belonged. To just delete a message to trash, simply change the
"mailboxIds" property so it is now in the mailbox with "role ==
"trash"", and remove all other mailbox ids.
When emptying the trash, clients SHOULD NOT destroy messages which When emptying the trash, clients SHOULD NOT destroy messages which
are also in a mailbox other than trash. For those messages, they are also in a mailbox other than trash. For those messages, they
should just remove the Trash mailbox from the message. SHOULD just remove the Trash mailbox from the message.
5.3.6. Response
The response to _setMessages_ is called _messagesSet_. It has the
following arguments:
o *accountId*: "String" The id of the account used for the call.
o *oldState*: "String|null" The state string that would have been
returned by _getMessages_ before making the requested changes, or
"null" if the server doesn't know what the previous state string
was.
o *newState*: "String" The state string that will now be returned by
_getMessages_.
o *created*: "String[Message]" A map of the creation id to an object
containing the _id_, _blobId_, _threadId_, and _size_ properties
for each successfully created Message.
o *updated*: "String[Message|null]" The _keys_ in this map are the
ids of all messages that were successfully updated. If the server
made any other changes to the record beyond those explicitly
requested by the client, the _value_ for the corresponding id in
the map is an object containing the updated value of each property
the *server changed*. Otherwise (if no properties changed on the
server other than those explicitly updated by the client), the
value is "null".
o *destroyed*: "String[]" A list of Message ids for Messages that
were successfully destroyed.
o *notCreated*: "String[SetError]" A map of creation id to a
SetError object for each Message that failed to be created. The
possible errors are defined above.
o *notUpdated*: "String[SetError]" A map of Message id to a SetError
object for each Message that failed to be updated. The possible
errors are defined above.
o *notDestroyed*: "String[SetError]" A map of Message id to a
SetError object for each Message that failed to be destroyed. The
possible errors are defined above.
The following errors may be returned instead of the _messagesSet_ The following extra _SetError_ types are defined:
response:
"accountNotFound": Returned if an _accountId_ was explicitly included For *create*:
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given o "attachmentNotFound": At least one blob id given in an attachment
corresponds to a valid account, but the account does not support this doesn't exist. An extra _notFound_ property of type "String[]"
data type. MUST be included in the error object containing every _blobId_
referenced in _attachments_ that could not be found on the server.
"accountReadOnly": Returned if the account has "isReadOnly == true". o "maxQuotaReached": The user has reached a server-defined limit on
their message storage quota.
"invalidArguments": Returned if one of the arguments is of the wrong For *update*:
type, or otherwise invalid. A _description_ property MAY be present
on the response object to help debug with an explanation of what the
problem was.
"stateMismatch": Returned if an _ifInState_ argument was supplied and o "tooManyKeywords": The change to the message's keywords would
it does not match the current state. exceed a server-defined maximum.
5.4. importMessages 4.6. importMessages
The _importMessages_ method adds [RFC5322] messages to a user's set The _importMessages_ method adds [RFC5322] messages to a user's set
of messages. The messages must first be uploaded as a file using the of messages. 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 primary account. call. If "null", defaults to the primary account.
o *messages*: "String[MessageImport]" A map of creation id (client o *messages*: "String[MessageImport]" A map of creation id (client
specified) to MessageImport objects specified) to MessageImport objects
An *MessageImport* object has the following properties: A *MessageImport* object has the following properties:
o *blobId*: "String" The id representing the raw [RFC5322] message o *blobId*: "String" The id representing the raw [RFC5322] message
(see the file upload section). (see the file upload section).
o *mailboxIds* "String[]" The ids of the mailbox(es) to assign this o *mailboxIds* "String[Boolean]" The ids of the mailbox(es) to
message to. assign this message to. At least one mailbox MUST be given.
o *keywords*: "String[Boolean]" o *keywords*: "String[Boolean]" (default: "{}") The keywords to
apply to the message.
Adding to the outbox will send the message, as described in the Each message to import is considered an atomic unit which may succeed
_setMessages_ section. The "$Draft" keyword MUST also be included if or fail individually. Importing successfully creates a new message
the message is being imported to the outbox. object from the data reference by the blobId and applies the given
mailboxes and keywords.
The server MAY forbid two messages with the same exact [RFC5322]
content, or even just with the same [RFC5322] Message-Id, to coexist
within an account. In this case, it should reject attempts to import
a message considered a duplicate with an "alreadyExists" SetError. A
_messageId_ property of type "String" MUST be included on the error
object with the id of the existing message.
If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid
(e.g. missing, wrong type, id not found), the server MUST reject the
import with an "invalidProperties" SetError.
If the message cannot be imported because it would take the account
over quota, the import should be rejected with a "maxQuotaReached"
SetError.
If the blob referenced cannot be parsed as an [RFC5322] message, the
server MUST reject the import with an "invalidMessage" SetError.
The response to _importMessages_ is called _messagesImported_. It has The response to _importMessages_ is called _messagesImported_. It has
the following arguments: the following arguments:
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[Message]" A map of the creation id to an object o *created*: "String[Message]" 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 Message. for each successfully imported Message.
skipping to change at page 48, line 12 skipping to change at page 25, line 5
corresponds to a valid account, but the account does not support this corresponds to a valid account, but the account does not support this
data type. data type.
"accountReadOnly": Returned if the account has "isReadOnly == true". "accountReadOnly": Returned if the account has "isReadOnly == true".
"invalidArguments": Returned if one of the arguments is of the wrong "invalidArguments": Returned if one of the arguments is of the wrong
type, or otherwise invalid. A "description" property MAY be present type, or otherwise invalid. A "description" property MAY be present
on the response object to help debug with an explanation of what the on the response object to help debug with an explanation of what the
problem was. problem was.
"notFound": Returned if the URL given in the "file" argument does not 4.7. copyMessages
correspond to an internal file.
"invalidMailboxes": Returned if one of the mailbox ids cannot be
found, or an invalid combination of mailbox ids is specified.
"maxQuotaReached": Returned if the user has reached their mail quota
so the message cannot be imported.
5.5. copyMessages
The only way to move messages *between* two different accounts is to The only way to move messages *between* two different accounts is to
copy them using the _copyMessages_ method, then once the copy has copy them using the _copyMessages_ method, then once the copy has
succeeded, delete the original. It takes the following arguments: succeeded, delete the original. It takes the following arguments:
o *fromAccountId*: "String|null" The id of the account to copy o *fromAccountId*: "String|null" The id of the account to copy
messages from. If "null", defaults to the primary account. messages from. If "null", defaults to the primary account.
o *toAccountId*: "String|null" The id of the account to copy o *toAccountId*: "String|null" The id of the account to copy
messages to. If "null", defaults to the primary account. messages to. If "null", defaults to the primary account.
o *messages*: "String[MessageCopy]" A map of _creation id_ to a o *messages*: "String[MessageCopy]" A map of _creation id_ to a
MessageCopy object. MessageCopy object.
A *MessageCopy* object has the following properties: A *MessageCopy* object has the following properties:
o *messageId*: "String" The id of the message to be copied in the o *messageId*: "String" The id of the message to be copied in the
"from" account. "from" account.
o *mailboxIds*: "String[]" The ids of the mailboxes (in the "to" o *mailboxIds*: "String[Boolean]" The ids of the mailboxes (in the
account) to add the copied message to. "to" account) to add the copied message to. At least one mailbox
MUST be given.
o *keywords*: "String[Boolean]" The _keywords_ property for the o *keywords*: "String[Boolean]" (default: "{}") The _keywords_
copy. property for the copy.
The "from" account may be the same as the "to" account to copy The server MAY forbid two messages with the same exact [RFC5322]
messages within an account. 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 messages within
an account.
Each message copy is considered an atomic unit which may succeed or
fail individually. Copying successfully MUST create a new message
object, with separate ids and mutable properties (e.g. mailboxes and
keywords) to the original message.
The response to _copyMessages_ is called _messagesCopied_. It has the The response to _copyMessages_ is called _messagesCopied_. It has the
following arguments: following arguments:
o *fromAccountId*: "String" The id of the account messages were o *fromAccountId*: "String" The id of the account messages were
copied from. copied from.
o *toAccountId*: "String" The id of the account messages were copied o *toAccountId*: "String" The id of the account messages were copied
to. to.
o *created*: "String[Message]|null" A map of the creation id to an o *created*: "String[Message]|null" A map of the creation id to an
object containing the _id_, _blobId_, _threadId_ and _size_ object containing the _id_, _blobId_, _threadId_ and _size_
properties for each successfully copied Message. properties for each successfully copied Message.
o *notCreated*: "String[SetError]|null" A map of creation id to a o *notCreated*: "String[SetError]|null" A map of creation id to a
SetError object for each Message that failed to be copied, "null" SetError object for each Message that failed to be copied, "null"
if none. if none.
The *SetError* may be one of the following types: The *SetError* may be one of the following types:
"notFound": Returned if the messageId given can't be found. "alreadyExists": Returned if the server forbids duplicates and the
message already exists in the target account. A _messageId_ property
of type "String" MUST be included on the error object with the id of
the existing message.
"invalidMailboxes": Returned if one of the mailbox ids cannot be "notFound": Returned if the _messageId_ given can't be found.
found, or an invalid combination of mailbox ids is specified.
"invalidProperties": Returned if the _mailboxIds_ or _keywords_
properties are invalid (e.g. missing, wrong type, id not found).
"maxQuotaReached": Returned if the user has reached their mail quota "maxQuotaReached": Returned if the user has reached their mail quota
so the message cannot be copied. so the message cannot be copied.
The following errors may be returned instead of the _messagesCopied_ The following errors may be returned instead of the _messagesCopied_
response: response:
"fromAccountNotFound": Returned if a _fromAccountId_ was explicitly "fromAccountNotFound": Returned if a _fromAccountId_ was explicitly
included with the request, but it does not correspond to a valid included with the request, but it does not correspond to a valid
account. account.
skipping to change at page 50, line 5 skipping to change at page 27, line 5
a valid account, but does not contain any mail data. a valid account, but does not contain any mail data.
"accountReadOnly": Returned if the "to" account has "isReadOnly == "accountReadOnly": Returned if the "to" account has "isReadOnly ==
true". true".
"invalidArguments": Returned if one of the arguments is of the wrong "invalidArguments": Returned if one of the arguments is of the wrong
type, or otherwise invalid. A "description" property MAY be present type, or otherwise invalid. A "description" property MAY be present
on the response object to help debug with an explanation of what the on the response object to help debug with an explanation of what the
problem was. problem was.
6. Identities 5. MessageSubmission
A *Identity* object stores information about an email address (or The MessageSubmission object represents the submission of a message
domain) the user may send from. It has the following properties: for delivery to one or more recipients. A *MessageSubmission* object
has the following properties:
o *id*: "String" The id of the identity. This property is o *id*: "String" (immutable; server-set) The id of the message
immutable. submission.
o *name*: "String" The "From" _name_ the client SHOULD use when o *identityId*: "String" (immutable) The id of the identity to
creating a new message from this identity. associate with this submission.
o *email*: "String" The "From" email address the client MUST use o *messageId*: "String" (immutable) The id of the message to send.
when creating a new message from this identity. This property is The message being sent does not have to be a draft, for example
immutable. The "email" property MAY alternatively be of the form when "redirecting" an existing message to a different email
"*@example.com", in which case the client may use any valid email address.
address ending in "@example.com".
o *replyTo*: "String" The Reply-To value the client SHOULD set when o *threadId*: "String" (immutable; server-set) The thread id of the
creating a new message from this identity. message to send. This is set by the server to the _threadId_
property of the message referenced by the _messageId_.
o *bcc*: "String" The Bcc value the client SHOULD set when creating o *envelope*: "Envelope|null" (immutable; default: "null")
a new message from this identity. Information for use when sending via SMTP. An *Envelope* object
has the following properties:
o *textSignature*: "String" Signature the client SHOULD insert into * *mailFrom*: "Address" The email address to use as the return
new rich-text messages that will be sending from this identity. address in the SMTP submission, plus any parameters to pass
Clients MAY ignore this and/or combine this with a client-specific with the MAIL FROM address. The JMAP server MAY allow the
signature preference. email to be the empty string. When a JMAP server performs a
message submission, it MAY use the same id string for the
[RFC3461] ENVID parameter and the MessageSubmission object id.
Servers that do this MAY replace a client-provided value for
ENVID with a server-provided value.
o *htmlSignature*: "String" Signature the client SHOULD insert into * *rcptTo*: "Address[]" The email addresses to send the message
new HTML messages that will be sending from this identity. This to, and any RCPT TO parameters to pass with the recipient.
text MUST be an HTML snippet to be inserted into the
"<body></body>" section of the new email. Clients MAY ignore this
and/or combine this with a client-specific signature preference.
o *mayDeleteIdentity*: "Boolean" Is the user allowed to delete this An *Address* object has the following properties:
identity? Servers may wish to set this to false for the user's
username or other default address.
Multiple identities with the same email address MAY exist, to allow * *email*: "String" The email address being represented by the
for different settings the user wants to pick between (for example object. This as a "Mailbox" as used in the Reverse-path or
with different names/signatures). Foward-path of the MAIL FROM or RCPT TO command in [@!RFC5321
6.1. getIdentities * *parameters*: "Object|null" Any parameters to send with the
email (either mail-parameter or rcpt-parameter as appropriate,
as specified in [RFC5321]). If supplied, each key in the
object is a parameter name, and the value either the parameter
value (type "String") or if the parameter does not take a value
then "null". For both name and value, any xtext or unitext
encodings are removed ([RFC3461], [RFC6533]) and JSON string
encoding applied.
Identities can either be fetched explicitly by id, or all of them at If the _envelope_ property is "null" or omitted on creation, the
once. To fetch identities, make a call to "getIdentities". It takes server MUST generate this from the referenced message as follows:
the following arguments:
o *accountId*: "String|null" The Account to fetch the identities * *mailFrom*: The email in the _Sender_ header, if present,
for. If "null", the primary account is used. otherwise the _From_ header, if present, and no parameters. If
multiple addresses are present in one of these headers, or
there is more than one _Sender_/_From_ header, the server
SHOULD reject the message as invalid but otherwise MUST take
the first email address in the last _Sender_/_From_ header in
the [RFC5322] version of the message. If the address found
from this is not allowed by the identity associated with this
submission, the _email_ property from the identity MUST be used
instead.
o *ids*: "String[]|null" The ids of the identities to fetch. If * *rcptTo*: The deduplicated set of email addresses from the
"null", all identities in the account are be fetched. _To_, _Cc_ and _Bcc_ headers, if present, with no parameters
for any of them.
The response to _getIdentities_ is called _identities_. It has the o *sendAt*: "Date" (immutable; server-set) The date the message was/
following arguments: will be released for delivery. If the client successfully used
[RFC4865] FUTURERELEASE with the message, this MUST be the time
when the server will release the message; otherwise it MUST be the
time the MessageSubmission was created.
o *accountId*: "String" The id of the account used for the call. o *undoStatus*: "String" (server-set) This represents whether the
submission may be canceled. This is server set and MUST be one of
the following values:
o *state*: "String" A string encoding the current state on the * "pending": It MAY be possible to cancel this submission.
server. This string will change if any identities change (that
is, a new identity is created, a change is made to an existing
identity, or an identity is deleted). It can be passed to
_getIdentityUpdates_ to efficiently get the list of changes from
the previous state.
o *list*: "Identity[]" An array of the Identity objects requested. * "final": The message has been relayed to at least one recipient
This will be the *empty array* if the _ids_ argument was the empty in a manner that cannot be recalled. It is no longer possible
array, or contained only ids for identities that could not be to cancel this submission.
found.
o *notFound*: "String[]|null" This array contains the ids passed to * "canceled": The message submission was canceled and will not be
the method for identities that do not exist, or "null" if all delivered to any recipient.
requested ids were found. It MUST be "null" if the _ids_ argument
in the call was "null".
The following errors may be returned instead of the _identities_ On systems that do not support unsending, the value of this
response: property will always be "final". On systems that do support
canceling submission, it will start as "pending", and MAY
transition to "final" when the server knows it definitely cannot
recall the message, but MAY just remain "pending". If in pending
state, a client can attempt to cancel the submission by setting
this property to "canceled"; if the update succeeds, the
submission was successfully canceled and the message has not been
delivered to any of the original recipients.
"accountNotFound": Returned if an _accountId_ was explicitly included o *deliveryStatus*: "String[DeliveryStatus]|null" (server-set) This
with the request, but it does not correspond to a valid account. represents the delivery status for each of the message recipients,
if known. This property MAY not be supported by all servers, in
which case it will remain "null". Servers that support it SHOULD
update the MessageSubmission object each time the status of any of
the recipients changes, even if some recipients are still being
retried. This value is a map from the email address of each
recipient to a _DeliveryStatus_ object. A *DeliveryStatus* object
has the following properties:
"accountNotSupportedByMethod": Returned if the _accountId_ given * *smtpReply*: "String" The SMTP reply string returned for this
corresponds to a valid account, but the account does not support this recipient when the server last tried to relay the message, or
data type. in a later DSN response for the message. This SHOULD be the
response to the RCPT TO stage, unless this was accepted and the
message as a whole rejected at the end of the DATA stage, in
which case the DATA stage reply SHOULD be used instead. Multi-
line SMTP responses should be concatenated to a single string
as follows:
"invalidArguments": Returned if one of the arguments is of the wrong + The hyphen following the SMTP code on all but the last line
type, or otherwise invalid. A "description" property MAY be present is replaced with a space.
on the response object to help debug with an explanation of what the
problem was.
6.2. getIdentityUpdates + Any prefix in common with the first line is stripped from
lines after the first.
The _getIdentityUpdates_ call allows a client to efficiently update + CRLF is replaced by a space.
the state of its cached identities to match the new state on the
server. It takes the following arguments:
o *accountId*: "String|null" The id of the account to use for this For example:
call. If "null", the primary account will be used.
o *sinceState*: "String" The current state of the client. This is 550-5.7.1 Our system has detected that this message is
the string that was returned as the _state_ argument in the 550 5.7.1 likely spam, sorry.
_identities_ response. The server will return the changes made
since this state.
o *maxChanges*: "Number|null" The maximum number of Identity ids to would become:
return in the response. The server MAY choose to clamp this value
to a particular maximum or set a maximum if none is given by the
client. If supplied by the 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 call with an "invalidArguments"
error.
o *fetchRecords*: "Boolean|null" If "true", immediately after 550 5.7.1 Our system has detected that this message is likely spam, sorry.
outputting an _identityUpdates_ response, an implicit call will be
made to _getidentities_ with the _changed_ property of the
response as the _ids_ argument, and the _fetchRecordProperties_
argument as the _properties_ argument. If "false" or "null", no
implicit call is made.
The response to _getIdentityUpdates_ is called _identityUpdates_. It For messages relayed via an alternative to SMTP, the server MAY
has the following arguments: generate a synthetic string representing the status instead.
If it does this, the string MUST be of the following form:
o *accountId*: "String" The id of the account used for the call. + A 3-digit SMTP reply code, as defined in [RFC5321], section
4.2.3.
o *oldState*: "String" This is the _sinceState_ argument echoed + Then a single space character.
back; the state from which the server is returning changes.
o *newState*: "String" This is the state the client will be in after + Then an SMTP Enhanced Mail System Status Code as defined in
applying the set of changes to the old state. [RFC3463], with a registry defined in [RFC5248].
o *hasMoreUpdates*: "Boolean" If "true", the client may call + Then a single space character.
_getIdentityUpdates_ again with the _newState_ returned to get
further updates. If "false", _newState_ is the current server
state.
o *changed*: "String[]" An array of Identity ids where a property of + Then an implementation-specific information string with a
the identity has changed between the old state and the new state, human readable explanation of the response.
or the identity has been created, and the identity has not been
destroyed.
o *removed*: "String[]" An array of Identity ids for identities * *delivered*: "String" Represents whether the message has been
which have been destroyed since the old state. successfully delivered to the recipient. This MUST be one of
the following values:
If a _maxChanges_ is supplied, or set automatically by the server, + "queued": The message is in a local mail queue and status
the server must try to limit the number of ids across _changed_ and will change once it exits the local mail queues. The
_removed_ to the number given. If there are more changes than this _smtpReply_ property may still change.
between the client's state and the current server state, the update
returned MUST take the client to an intermediate state, from which
the client can continue to call _getIdentityUpdates_ until it is
fully up to date. The server MAY return more ids than the
_maxChanges_ total if this is required for it to be able to produce
an update to an intermediate state, but it SHOULD try to keep it
close to the maximum requested.
If an identity has been modified AND deleted since the oldState, the + "yes": The message was successfully delivered to the mailbox
server should just return the id in the _removed_ array, but MAY of the recipient. The _smtpReply_ property is final.
return it in the _changed_ array as well. If an identity has been
created AND deleted since the oldState, the server SHOULD remove the
identity id from the response entirely, but MAY include it in the
_removed_ array.
The following errors may be returned instead of the "identityUpdates" + "no": Message delivery to the recipient permanently failed.
response: The _smtpReply_ property is final.
"accountNotFound": Returned if an _accountId_ was explicitly included + "unknown": The final delivery status is unknown, (e.g. it
with the request, but it does not correspond to a valid account. was relayed to an external machine and no further
information is available). The _smtpReply_ property may
still change if a DSN arrives.
"accountNotSupportedByMethod": Returned if the _accountId_ given Note, successful relaying to an external SMTP server SHOULD NOT
corresponds to a valid account, but the account does not support this be taken as an indication that the message has successfully
data type. reached the final mailbox. In this case though, the server MAY
receive a DSN response, if requested. If a DSN is received for
the recipient with Action equal to "delivered", as per
[RFC3464] section 2.3.3, then the _delivered_ property SHOULD
be set to "yes"; if the Action equals "failed", the property
SHOULD be set to "no". Receipt of any other DSN SHOULD NOT
affect this property. The server MAY also set this property
based on other feedback channels.
"invalidArguments": Returned if the request does not include one of * *displayed*: "String" Represents whether the message has been
the required arguments, or one of the arguments is of the wrong type, displayed to the recipient. This MUST be one of the following
or otherwise invalid. A "description" property MAY be present on the values:
response object to help debug with an explanation of what the problem
was.
"cannotCalculateChanges": Returned if the server cannot calculate the + "unknown": The display status is unknown. This is the
changes from the state string given by the client. Usually due to initial value.
the client's state being too old, or the server being unable to
produce an update to an intermediate state when there are too many
updates. The client MUST invalidate its Identity cache.
6.3. setIdentities + "yes": The receipient's system claims the message content
has been displayed to the recipient. Note, there is no
guarantee that the recipient has noticed, read, or
understood the content.
Modifying the state of Identity objects on the server is done via the If an MDN is received for this recipient with Disposition-Type
_setIdentities_ method. This encompasses creating, updating and (as per [RFC3798] section 3.2.6.2) equal to "displayed", this
destroying Identity records. property SHOULD be set to "yes". The server MAY also set this
property based on other feedback channels.
The _setIdentities_ method takes the following arguments: o *dsnBlobIds*: "String[]" (server-set) A list of blob ids for DSNs
received for this submission, in order of receipt, oldest first.
o *accountId*: "String|null" The id of the account to use for this o *mdnBlobIds*: "String[]" (server-set) A list of blob ids for MDNs
call. If "null", the primary account will be used. received for this submission, in order of receipt, oldest first.
o *ifInState*: "String|null" This is a state string as returned by JMAP servers MAY choose not to expose DSN and MDN responses as
the _getIdentities_ method. If supplied, the string must match Message objects if they correlate to a MessageSubmission object. It
the current state, otherwise the method MUST be aborted and a SHOULD only do this if it exposes them in the _dsnBlobIds_ and
"stateMismatch" error returned. If "null", any changes will be _mdnblobIds_ fields instead, and expects the user to be using clients
applied to the current state. capable of fetching and displaying delivery status via the
MessageSubmission object.
o *create*: "String[Identity]|null" A map of _creation id_ (an For efficiency, a server MAY destroy MessageSubmission objects a
arbitrary string set by the client) to Identity objects certain amount of time after the message is successfully sent or it
(containing all properties except the id). has finished retrying sending the message. For very basic SMTP
proxies, this MAY be immediately after creation, as it has no way to
assign a real id and return the information again if fetched later.
o *update*: "String[Identity]|null" A map of id to Identity objects. The following JMAP methods are supported:
The object may omit any property; only properties that have
changed need be included.
o *destroy*: "String[]|null" A list of ids for Identity objects to 5.1. getMessageSubmissions
permanently delete.
Each create, update or destroy is considered an atomic unit. It is Standard _getFoos_ method.
permissible for the server to commit some of the changes but not
others, however it is not permissible to only commit part of an
update to a single identity.
If a create, update or destroy is rejected, the appropriate error 5.2. getMessageSubmissionUpdates
MUST be added to the notCreated/notUpdated/notDestroyed property of
the response and the server MUST continue to the next create/update/
destroy. It does not terminate the method.
A *create* MAY be rejected with one of the following errors: Standard _getFooUpdates_ method.
o "maxQuotaReached": Returned if the user has reached a server- 5.3. getMessageSubmissionList
defined limit on the number of identities.
o "emailNotPermitted": Returned if the user tries to create an Standard _getFooList_ method.
identity with an email address the user does not allow them to
send from.
If the identity has "mayDeleteIdentity == false", any attempt to The *FilterCondition* object (optionally passed as the _filter_
destroy it MUST be rejected with a "forbidden" error. argument) has the following properties, any of which may be omitted:
If an id given cannot be found, the update or destroy MUST be o *messageIds*: "String[]" The MessageSubmission _messageId_
rejected with a "notFound" set error. property must be in this list to match the condition.
The response to _setIdentities_ is called _identitiesSet_. It has the o *threadIds*: "String[]" The MessageSubmission _threadId_ property
following arguments: must be in this list to match the condition.
o *accountId*: "String" The id of the account used for the call. o *undoStatus*: "String" The MessageSubmission _undoStatus_ property
must be identical to the value given to match the condition.
o *oldState*: "String|null" The state string that would have been o *before*: "Date" The _sendAt_ property of the MessageSubmission
returned by _getIdentities_ before making the requested changes, object must be before this date to match the condition.
or "null" if the server doesn't know what the previous state
string was.
o *newState*: "String" The state string that will now be returned by o *after*: "Date" The _sendAt_ property of the MessageSubmission
_getIdentities_. object must be after this date to match the condition.
o *created*: "String[Identity]" A map of the creation id to an A MessageSubmission object matches the filter if and only if all of
object containing the *id* property for all successfully created the given conditions given match. If zero properties are specified,
identities. it is automatically "true" for all objects.
o *updated*: "String[Identity|null]" The _keys_ in this map are the The following properties MUST be supported for sorting:
ids of all identities that were successfully updated. If the
server made any other changes to the record beyond those
explicitly requested by the client, the _value_ for the
corresponding id in the map is an object containing the updated
value of each property the *server changed*. Otherwise (if no
properties changed on the server other than those explicitly
updated by the client), the value is "null".
o *destroyed*: "String[]" A list of ids for identities that were o "messageId"
successfully destroyed.
o *notCreated*: "String[SetError]" A map of creation id to a o "threadId"
SetError object for each identity that failed to be created. The
possible errors are defined in the description of the method for
specific data types.
o *notUpdated*: "String[SetError]" A map of Identity id to a o "sentAt"
SetError object for each identity that failed to be updated. The
possible errors are defined in the description of the method for
specific data types.
o *notDestroyed*: "String[SetError]" A map of Identity id to a 5.4. getMessageSubmissionListUpdates
SetError object for each identity that failed to be destroyed.
The possible errors are defined in the description of the method
for specific data types.
A *SetError* object has the following properties: Standard _getFooListUpdates_ method.
o *type*: "String" The type of error. 5.5. setMessageSubmissions
o *description*: "String|null" A description of the error to display Standard _setFoos_ method, with the following two extra arguments:
to the user.
The following errors may be returned instead of the _identitiesSet_ o *onSuccessUpdateMessage*: "String[Message]|null" A map of
response: _MessageSubmission id_ to an object containing properties to
update on the Message object referenced by the MessageSubmission
if the create/update/destroy succeeds. (For references to
MessageSubmission creations, this is equivalent to a back
reference so the id will be the creation id prefixed with a "#".)
"accountNotFound": Returned if an _accountId_ was explicitly included o *onSuccessDestroyMessage*: "String[]|null" A list of
with the request, but it does not correspond to a valid account. _MessageSubmission ids_ for which the message with the
corresponding messageId should be destroyed if the create/update/
destroy succeeds. (For references to MessageSubmission creations,
this is equivalent to a back reference so the id will be the
creation id prefixed with a "#".)
"accountNotSupportedByMethod": Returned if the _accountId_ given A single implicit _setMessages_ call MUST be made after all
corresponds to a valid account, but the account does not support this MessageSubmission create/update/destroy requests have been processed
data type. to perform any changes requested in these two arguments. The
_messagesSet_ response MUST be returned after the
_messageSubmissionsSet_ response.
"accountReadOnly": Returned if the account has MailCapabilities with A message is sent by creating a MessageSubmission object. When
"isReadOnly == true". processing each create, the server must check that the message is
valid, and the user has sufficient authorization to send it. If the
creation succeeds, the message will be sent to the recipients given
in the envelope _rcptTo_ parameter. The server MUST remove any _Bcc_
header present on the message during delivery. The server MAY add or
remove other headers from the submitted message, or make further
alterations in accordance with the server's policy during delivery.
"requestTooLarge": Returned if the total number of objects to create, If the referenced message is destroyed at any point after the
update or destroy exceeds the maximum number the server is willing to MessageSubmission object is created, this MUST NOT change the
process in a single method call. behaviour of the message submission (i.e. it does not cancel a future
send).
"invalidArguments": Returned if one of the arguments is of the wrong Similarly, destroying a MessageSubmission object MUST NOT affect the
type, or otherwise invalid. A _description_ property MAY be present deliveries it represents. It purely removes the record of the
on the response object to help debug with an explanation of what the message submission. The server MAY automatically destroy
problem was. MessageSubmission objects after a certain time or in response to
other triggers, and MAY forbid the client from manually destroying
MessageSubmission objects.
"stateMismatch": Returned if an _ifInState_ argument was supplied and The following extra _SetError_ types are defined:
it does not match the current state.
For *create*:
o "tooLarge" - The message size is larger than the server supports.
A _maxSize_ "Number" property MUST be present on the SetError
specifying the maximum size of a message that may be sent, in
bytes.
o "tooManyRecipients" - The envelope (supplied or generated) has
more recipients than the server allows. A _maxRecipients_
"Number" property MUST be present on the SetError specifying the
maximum number of allowed recipients.
o "noRecipients" - The envelope (supplied or generated) does not
have any rcptTo emails.
o "invalidRecipients" - The _rcptTo_ property of the envelope
(supplied or generated) contains at least one rcptTo value which
is not a valid email for sending to. An _invalidEmails_
"String[]" property MUST be present on the SetError, which is a
list of the invalid emails.
o "notPermittedFrom" - The server does not permit the user to send a
message with the From header of the message to be sent.
o "notPermittedToSend" - The user does not have permission to send
at all right now for some reason. A _description_ "String"
property MAY be present on the SetError object to display to the
user why they are not permitted.
o "messageNotFound" - The _messageId_ is not a valid id for a
message in the account.
o "invalidMessage" - The message 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 Message that
were invalid.
For *update*:
o "cannotUnsend": The client attempted to update the _undoStatus_ of
a valid MessageSubmission object from "pending" to "canceled", but
the message cannot be unsent.
For *destroy*:
o "forbidden": The server does not allow clients to destroy
MessageSubmission objects.
6. Identities
An *Identity* object stores information about an email address (or
domain) the user may send from. It has the following properties:
o *id*: "String" (immutable; server-set) The id of the identity.
o *name*: "String" (default: """") The "From" _name_ the client
SHOULD use when creating a new message from this identity.
o *email*: "String" The "From" email address the client MUST use
when creating a new message from this identity. This property is
immutable. The "email" property MAY alternatively be of the form
"*@example.com", in which case the client may use any valid email
address ending in "@example.com".
o *replyTo*: "Emailer[]|null" (default: "null") The Reply-To value
the client SHOULD set when creating a new message from this
identity.
o *bcc*: "Emailer[]|null" (default: "null") The Bcc value the client
SHOULD set when creating a new message from this identity.
o *textSignature*: "String" (default: """") Signature the client
SHOULD insert into new rich-text messages that will be sending
from this identity. Clients MAY ignore this and/or combine this
with a client-specific signature preference.
o *htmlSignature*: "String" (default: """") Signature the client
SHOULD insert into new HTML messages that will be sending from
this identity. This text MUST be an HTML snippet to be inserted
into the "<body></body>" section of the new email. Clients MAY
ignore this and/or combine this with a client-specific signature
preference.
o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete
this identity? Servers may wish to set this to "false" for the
user's username or other default address.
Multiple identities with the same email address MAY exist, to allow
for different settings the user wants to pick between (for example
with different names/signatures).
The following JMAP methods are supported:
6.1. getIdentities
Standard _getFoos_ method. The _ids_ argument may be "null" to fetch
all at once.
6.2. getIdentityUpdates
Standard _getFooUpdates_ method.
6.3. setIdentities
Standard _setFoos_ method. The following extra _SetError_ types are
defined:
For *create*:
o "maxQuotaReached": The user has reached a server-defined limit on
the number of identities.
o "emailNotPermitted": The user is not alloed 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".
7. SearchSnippets 7. SearchSnippets
When doing a search on a "String" property, the client may wish to 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 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 preview instead of the beginning of the message, and to highlight any
matching terms in both this and the subject of the message. Search matching terms in both this and the subject of the message. Search
snippets represent this data. snippets represent this data.
A *SearchSnippet* object has the following properties: A *SearchSnippet* object has the following properties:
skipping to change at page 57, line 5 skipping to change at page 36, line 31
subject, this is the subject of the message HTML-escaped, with subject, this is the subject of the message 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, up to 256
characters long. If it does not match, this is "null". characters long. 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, up to 256 characters
long. 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_ and _preview_ properties. MUST return "null" for both the _subject_, _preview_ and
_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:
7.1. getSearchSnippets 7.1. getSearchSnippets
To fetch search snippets, make a call to "getSearchSnippets". It To fetch search snippets, make a call to "getSearchSnippets". It
takes the following arguments: 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 primary account. call. If "null", defaults to the primary account.
o *messageIds*: "String[]" The list of ids of messages to fetch the o *messageIds*: "String[]" The list of ids of messages to fetch the
snippets for. snippets for.
skipping to change at page 58, line 28 skipping to change at page 38, line 13
or otherwise invalid. A "description" property MAY be present on the or otherwise invalid. A "description" property MAY be present on the
response object to help debug with an explanation of what the problem response object to help debug with an explanation of what the problem
was. was.
8. Vacation Response 8. Vacation Response
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" The id of the object. This property is immutable. o *id*: "String" (immutable) The id of the object. There is only
There is only ever one vacation response object, and its id is ever one vacation response object, and its id is ""singleton"".
""singleton"".
o *isEnabled* "Boolean" Should a vacation response be sent if a o *isEnabled* "Boolean" Should a vacation response be sent if a
message arrives between the _fromDate_ and _toDate_? message arrives between the _fromDate_ and _toDate_?
o *fromDate*: "Date|null" If _isEnabled_ is "true", the date/time o *fromDate*: "Date|null" If _isEnabled_ is "true", the date/time
after which messages that arrive should receive the user's after which messages that arrive should receive the user's
vacation response, in UTC. If "null", the vacation response is vacation response, in UTC. If "null", the vacation response is
effective immediately. effective immediately.
o *toDate*: "Date|null" If _isEnabled_ is "true", the date/time o *toDate*: "Date|null" If _isEnabled_ is "true", the date/time
skipping to change at page 59, line 13 skipping to change at page 38, line 46
enabled. If this is "null", when the vacation message is sent a enabled. If this is "null", when the vacation message is sent a
plain-text body part SHOULD be generated from the _htmlBody_ but plain-text body part SHOULD be generated from the _htmlBody_ but
the server MAY choose to send the response as HTML only. the server MAY choose to send the response as HTML only.
o *htmlBody*: "String|null" The HTML message to send in response to o *htmlBody*: "String|null" The HTML message to send in response to
messages when the vacation response is enabled. If this is messages when the vacation response is enabled. If this is
"null", when the vacation message is sent an HTML body part MAY be "null", 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:
8.1. getVacationResponse 8.1. getVacationResponse
Standard _getFoos_ 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"".
To fetch the vacation response object, make a call to
"getVacationResponse". It takes the following argument:
o *accountId*: "String|null" The Account to get the vacation
response for. If "null", the primary account is used.
The response to _getVacationResponse_ is called _vacationResponse_.
It has the following arguments:
o *accountId*: "String" The id of the account used for the call.
o *list*: "VacationResponse[]" An array containing the single
VacationResponse object.
The following errors may be returned instead of the
_vacationResponse_ response:
"accountNotFound": Returned if an _accountId_ was explicitly included
with the request, but it does not correspond to a valid account.
"accountNotSupportedByMethod": Returned if the _accountId_ given
corresponds to a valid account, but the account does not support this
data type.
8.2. setVacationResponse 8.2. setVacationResponse
Sets properties on the vacation response object. It takes the Standard _setFoos_ method. The following extra _SetError_ types are
following arguments: defined:
o *accountId*: "String|null" The Account to set the vacation For *create* or *destroy*:
response for. If "null", the primary account is used.
o *update*: "String[VacationResponse]|null" A map of id o "singleton": This is a singleton object, so you cannot create
("singleton") to the VacationResponse object with new values for another one or destroy the existing one.
the properties you wish to change. The object may omit any
property; only properties that have changed need be included.
If any of the properties in the update are invalid (immutable and 9. Security considerations
different to the current server value, wrong type), the server MUST
reject the update with a SetError of type "invalidProperties". The
SetError object SHOULD contain a property called _properties_ of type
"String[]" that lists *all* the properties that were invalid. The
object MAY also contain a _description_ property of type "String"
with a user-friendly description of the problems.
The response is called _vacationResponseSet_. It has the following All security considerations of JMAP {TODO: insert RFC ref} apply to
arguments: this specification.
o *updated*: "String[]" 10. References
o *updated*: "String[VacationResponse|null]" If successfully 10.1. Normative References
updated, this map will have a sole key of "singleton". The
_value_ in the map is an object containing the updated value of
each property the *server changed* on the record, if any.
Otherwise (if no properties changed on the server other than those
explicitly updated by the client), the value is "null".
o *notUpdated*: "String[SetError]" A map of id ("singleton") to a [RFC1870] Klensin, J., Freed, N., and K. Moore, "SMTP Service
SetError object if the update failed. Extension for Message Size Declaration", STD 10, RFC 1870,
DOI 10.17487/RFC1870, November 1995,
<https://www.rfc-editor.org/info/rfc1870>.
A *SetError* object has the following properties: [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions)
Part Three: Message Header Extensions for Non-ASCII Text",
RFC 2047, DOI 10.17487/RFC2047, November 1996,
<https://www.rfc-editor.org/info/rfc2047>.
o *type*: "String" The type of error. [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/rfc2119>.
o *description*: "String|null" A description of the error to display [RFC2852] Newman, D., "Deliver By SMTP Service Extension", RFC 2852,
to the user. DOI 10.17487/RFC2852, June 2000,
<https://www.rfc-editor.org/info/rfc2852>.
The following errors may be returned instead of the [RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service
_vacationResponseSet_ response: Extension for Delivery Status Notifications (DSNs)",
RFC 3461, DOI 10.17487/RFC3461, January 2003,
<https://www.rfc-editor.org/info/rfc3461>.
"accountNotFound": Returned if an _accountId_ was explicitly included [RFC3463] Vaudreuil, G., "Enhanced Mail System Status Codes",
with the request, but it does not correspond to a valid account. RFC 3463, DOI 10.17487/RFC3463, January 2003,
<https://www.rfc-editor.org/info/rfc3463>.
"accountNotSupportedByMethod": Returned if the _accountId_ given [RFC3464] Moore, K. and G. Vaudreuil, "An Extensible Message Format
corresponds to a valid account, but the account does not support this for Delivery Status Notifications", RFC 3464,
data type. DOI 10.17487/RFC3464, January 2003,
<https://www.rfc-editor.org/info/rfc3464>.
"invalidArguments": Returned if one of the arguments is of the wrong [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO
type, or otherwise invalid (including using an id other than 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November
""singleton""). A "description" property MAY be present on the 2003, <https://www.rfc-editor.org/info/rfc3629>.
response object to help debug with an explanation of what the problem
was.
9. References [RFC3798] Hansen, T., Ed. and G. Vaudreuil, Ed., "Message
Disposition Notification", RFC 3798, DOI 10.17487/RFC3798,
May 2004, <https://www.rfc-editor.org/info/rfc3798>.
9.1. Normative References [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006,
<https://www.rfc-editor.org/info/rfc4648>.
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate [RFC4865] White, G. and G. Vaudreuil, "SMTP Submission Service
Requirement Levels", BCP 14, RFC 2119, Extension for Future Message Release", RFC 4865,
DOI 10.17487/RFC2119, March 1997, DOI 10.17487/RFC4865, May 2007,
<http://www.rfc-editor.org/info/rfc2119>. <https://www.rfc-editor.org/info/rfc4865>.
[RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO [RFC5248] Hansen, T. and J. Klensin, "A Registry for SMTP Enhanced
10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November Mail System Status Codes", BCP 138, RFC 5248,
2003, <http://www.rfc-editor.org/info/rfc3629>. DOI 10.17487/RFC5248, June 2008,
<https://www.rfc-editor.org/info/rfc5248>.
[RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321,
DOI 10.17487/RFC5321, October 2008,
<https://www.rfc-editor.org/info/rfc5321>.
[RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322,
DOI 10.17487/RFC5322, October 2008, DOI 10.17487/RFC5322, October 2008,
<http://www.rfc-editor.org/info/rfc5322>. <https://www.rfc-editor.org/info/rfc5322>.
[RFC5788] Melnikov, A. and D. Cridland, "IMAP4 Keyword Registry", [RFC5788] Melnikov, A. and D. Cridland, "IMAP4 Keyword Registry",
RFC 5788, DOI 10.17487/RFC5788, March 2010, RFC 5788, DOI 10.17487/RFC5788, March 2010,
<http://www.rfc-editor.org/info/rfc5788>. <https://www.rfc-editor.org/info/rfc5788>.
[RFC6409] Gellens, R. and J. Klensin, "Message Submission for Mail",
STD 72, RFC 6409, DOI 10.17487/RFC6409, November 2011,
<https://www.rfc-editor.org/info/rfc6409>.
[RFC6533] Hansen, T., Ed., Newman, C., and A. Melnikov,
"Internationalized Delivery Status and Disposition
Notifications", RFC 6533, DOI 10.17487/RFC6533, February
2012, <https://www.rfc-editor.org/info/rfc6533>.
[RFC6710] Melnikov, A. and K. Carlberg, "Simple Mail Transfer
Protocol Extension for Message Transfer Priorities",
RFC 6710, DOI 10.17487/RFC6710, August 2012,
<https://www.rfc-editor.org/info/rfc6710>.
[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, <http://www.rfc-editor.org/info/rfc7159>. 2014, <https://www.rfc-editor.org/info/rfc7159>.
9.2. URIs
[1] server.html [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493,
DOI 10.17487/RFC7493, March 2015,
<https://www.rfc-editor.org/info/rfc7493>.
[2] https://tools.ietf.org/html/rfc4648 10.2. URIs
[3] http://tools.ietf.org/html/rfc2047 [1] server.html
[4] https://www.iana.org/assignments/imap-keywords/imap- [2] https://www.iana.org/assignments/imap-keywords/imap-
keywords.xhtml keywords.xhtml
Author's Address Author's Address
Neil Jenkins Neil Jenkins
FastMail FastMail
Level 1, 91 William St Level 2, 114 William St
Melbourne VIC 3000 Melbourne VIC 3000
Australia Australia
Email: neilj@fastmail.com Email: neilj@fastmailteam.com
URI: https://www.fastmail.com URI: https://www.fastmail.com
 End of changes. 314 change blocks. 
1990 lines changed or deleted 1032 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/