idnits 2.17.1 draft-ietf-jmap-mail-04.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The document seems to lack an IANA Considerations section. (See Section 2.2 of https://www.ietf.org/id-info/checklist for how to handle the case when there are no actions for IANA.) ** There are 6 instances of too long lines in the document, the longest one being 216 characters in excess of 72. == There are 4 instances of lines with non-RFC2606-compliant FQDNs in the document. -- The draft header indicates that this document updates RFC5788, but the abstract doesn't seem to mention this, which it should. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year (Using the creation date from RFC5788, updated by this document, for RFC5378 checks: 2002-06-21) -- The document seems to lack a disclaimer for pre-RFC5378 work, but may have content which was first submitted before 10 November 2008. If you have contacted all the original authors and they are all willing to grant the BCP78 rights to the IETF Trust, then this is fine, and you can ignore this comment. If not, you may need to add the pre-RFC5378 disclaimer. (See the Legal Provisions document at https://trustee.ietf.org/license-info for more information.) -- The document date (March 5, 2018) is 2242 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Looks like a reference, but probably isn't: '1' on line 2561 == Missing Reference: 'TODO' is mentioned on line 285, but not defined -- Looks like a reference, but probably isn't: '2' on line 2563 -- Looks like a reference, but probably isn't: '3' on line 2565 ** Obsolete normative reference: RFC 3798 (Obsoleted by RFC 8098) ** Obsolete normative reference: RFC 7159 (Obsoleted by RFC 8259) Summary: 4 errors (**), 0 flaws (~~), 3 warnings (==), 7 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 JMAP N. Jenkins 3 Internet-Draft FastMail 4 Updates: 5788 (if approved) March 5, 2018 5 Intended status: Standards Track 6 Expires: September 6, 2018 8 JMAP for Mail 9 draft-ietf-jmap-mail-04 11 Abstract 13 This document specifies a data model for synchronising email data 14 with a server using JMAP. 16 Status of This Memo 18 This Internet-Draft is submitted in full conformance with the 19 provisions of BCP 78 and BCP 79. 21 Internet-Drafts are working documents of the Internet Engineering 22 Task Force (IETF). Note that other groups may also distribute 23 working documents as Internet-Drafts. The list of current Internet- 24 Drafts is at https://datatracker.ietf.org/drafts/current/. 26 Internet-Drafts are draft documents valid for a maximum of six months 27 and may be updated, replaced, or obsoleted by other documents at any 28 time. It is inappropriate to use Internet-Drafts as reference 29 material or to cite them other than as "work in progress." 31 This Internet-Draft will expire on September 6, 2018. 33 Copyright Notice 35 Copyright (c) 2018 IETF Trust and the persons identified as the 36 document authors. All rights reserved. 38 This document is subject to BCP 78 and the IETF Trust's Legal 39 Provisions Relating to IETF Documents 40 (https://trustee.ietf.org/license-info) in effect on the date of 41 publication of this document. Please review these documents 42 carefully, as they describe your rights and restrictions with respect 43 to this document. Code Components extracted from this document must 44 include Simplified BSD License text as described in Section 4.e of 45 the Trust Legal Provisions and are provided without warranty as 46 described in the Simplified BSD License. 48 Table of Contents 50 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 51 1.1. Notational Conventions . . . . . . . . . . . . . . . . . 3 52 1.2. The Date datatypes . . . . . . . . . . . . . . . . . . . 4 53 1.3. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 54 1.4. Addition to the capabilities object . . . . . . . . . . . 4 55 1.5. Data profile name . . . . . . . . . . . . . . . . . . . . 6 56 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 6 57 2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 9 58 2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 9 59 2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 9 60 2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 10 61 2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 10 62 3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 63 3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 11 64 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 11 65 3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 12 66 4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 67 4.1. Properties of the Email object . . . . . . . . . . . . . 12 68 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 12 69 4.1.2. Header fields . . . . . . . . . . . . . . . . . . . . 14 70 4.1.3. Body parts . . . . . . . . . . . . . . . . . . . . . 19 71 4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 26 72 4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 28 73 4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 29 74 4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 30 75 4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 30 76 4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 32 77 4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 33 78 4.4.4. Response . . . . . . . . . . . . . . . . . . . . . . 34 79 4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 34 80 4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 34 81 4.7. Email/import . . . . . . . . . . . . . . . . . . . . . . 35 82 4.8. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 37 83 4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 39 84 5. Email submission . . . . . . . . . . . . . . . . . . . . . . 40 85 5.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 45 86 5.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 45 87 5.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 45 88 5.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 45 89 5.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 46 90 6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 47 91 6.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 48 92 6.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 48 93 6.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 49 94 7. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 49 95 7.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 50 97 8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 51 98 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 52 99 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 52 100 9. Security considerations . . . . . . . . . . . . . . . . . . . 52 101 9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 52 102 10. References . . . . . . . . . . . . . . . . . . . . . . . . . 52 103 10.1. Normative References . . . . . . . . . . . . . . . . . . 52 104 10.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 55 105 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 55 107 1. Introduction 109 JMAP is a 110 generic protocol for synchronising data, such as mail, calendars or 111 contacts, between a client and a server. It is optimised for mobile 112 and web environments, and aims to provide a consistent interface to 113 different data types. 115 This specification defines a data model for synchronising mail 116 between a client and a server using JMAP. 118 1.1. Notational Conventions 120 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 121 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 122 document are to be interpreted as described in [RFC2119]. 124 The underlying format used for this specification is I-JSON 125 ([RFC7493]). Consequently, the terms "object" and "array" as well as 126 the four primitive types (strings, numbers, booleans, and null) are 127 to be interpreted as described in Section 1 of [RFC7159]. Unless 128 otherwise noted, all the property names and values are case 129 sensitive. 131 Some examples in this document contain "partial" JSON documents used 132 for illustrative purposes. In these examples, three periods "..." 133 are used to indicate a portion of the document that has been removed 134 for compactness. 136 Types signatures are given for all JSON objects in this document. 137 The following conventions are used: 139 o "Boolean|String" - The value is either a JSON "Boolean" value, or 140 a JSON "String" value. 142 o "Foo" - Any name that is not a native JSON type means an object 143 for which the properties (and their types) are defined elsewhere 144 within this document. 146 o "Foo[]" - An array of objects of type "Foo". 148 o "String[Foo]" - A JSON "Object" being used as a map (associative 149 array), where all the values are of type "Foo". 151 Object properties may also have a set of attributes defined along 152 with the type signature. These have the following meanings: 154 o *sever-set*: Only the server can set the value for this property. 155 The client MUST NOT send this property when creating a new object 156 of this type. 158 o *immutable*: The value MUST NOT change after the object is 159 created. 161 o *default*: (This is followed by a JSON value). The value that 162 will be used for this property if it is omitted in an argument, or 163 when creating a new object of this type. 165 1.2. The Date datatypes 167 Where "Date" is given as a type, it means a string in [RFC3339] 168 _date-time_ format. To ensure a normalised form, the _time-secfrac_ 169 MUST always be omitted and any letters in the string (e.g. "T" and 170 "Z") MUST be upper-case. For example, ""2014-10-30T14:12:00+08:00"". 172 Where "UTCDate" is given as a type, it means a "Date" where the 173 _time-offset_ component MUST be "Z" (i.e. it must be in UTC time). 174 For example, ""2014-10-30T06:12:00Z"". 176 1.3. Terminology 178 The same terminology is used in this document as in the core JMAP 179 specification. 181 1.4. Addition to the capabilities object 183 The capabilities object is returned as part of the standard JMAP 184 Session object; see the JMAP spec. Servers supporting _this_ 185 specification MUST add a property called "ietf:jmapmail" to the 186 capabilities object. The value of this property is an object which 187 MUST contain the following information on server capabilities: 189 o *maxMailboxesPerEmail*: "Number|null" The maximum number of 190 mailboxes that can be can assigned to a single email. This MUST 191 be an integer >= 1, or "null" for no limit (or rather, the limit 192 is always the number of mailboxes in the account). 194 o *maxSizeAttachmentsPerEmail*: "Number" The maximum total size of 195 attachments, in octets, allowed for a single email. A server MAY 196 still reject emails with a lower attachment size total (for 197 example, if the body includes several megabytes of text, causing 198 the size of the encoded MIME structure to be over some server- 199 defined limit). 201 o *maxDelayedSend*: "Number" The number in seconds of the maximum 202 delay the server supports in sending (see the EmailSubmission 203 object). This is "0" if the server does not support delayed send. 205 o *emailsListSortOptions*: "String[]" A list of all the email 206 properties the server supports for sorting by. This MAY include 207 properties the client does not recognise (for example custom 208 properties specified in a vendor extension). Clients MUST ignore 209 any unknown properties in the list. 211 o *submissionExtensions*: "String[String[]]" A JMAP implementation 212 that talks to a Submission [RFC6409] server SHOULD have a 213 configuration setting that allows an administrator to expose a new 214 submission EHLO capability in this field. This allows a JMAP 215 server to gain access to a new submission extension without code 216 changes. By default, the JMAP server should show only known safe- 217 to-expose EHLO capabilities in this field, and hide EHLO 218 capabilities that are only relevant to the JMAP server. Each key 219 in the object is the _ehlo-name_, and the value is a list of 220 _ehlo-args_. Examples of safe-to-expose Submission extensions 221 include: 223 * FUTURERELEASE ([RFC4865]) 225 * SIZE ([RFC1870]) 227 * DSN ([RFC3461]) 229 * DELIVERYBY ([RFC2852]) 231 * MT-PRIORITY ([RFC6710]) 233 A JMAP server MAY advertise an extension and implement the 234 semantics of that extension locally on the JMAP server even if a 235 submission server used by JMAP doesn't implement it. The full 236 IANA registry of submission extensions can be found at 237 240 1.5. Data profile name 242 The data profile name for the set of types defined in this 243 specification is "mail". 245 The JMAP Session object has an _accounts_ property with the set of 246 accounts to which the user has access. Any account that contains 247 data of the types defined in this specification MUST include the 248 string ""mail"" in the _hasDataFor_ property of the account object. 250 2. Mailboxes 252 A mailbox represents a named set of emails. This is the primary 253 mechanism for organising emails within an account. It is analogous 254 to a folder or a label in other systems. A mailbox may perform a 255 certain role in the system; see below for more details. 257 For compatibility with IMAP, an email MUST belong to one or more 258 mailboxes. The email id does not change if the email changes 259 mailboxes. 261 A *Mailbox* object has the following properties: 263 o *id*: "String" (immutable; server-set) The id of the mailbox. 265 o *name*: "String" User-visible name for the mailbox, e.g. "Inbox". 266 This may be any Net-Unicode string ([RFC5198]) of at least 1 267 character in length and maximum 256 octets in size. Servers 268 SHOULD forbid sibling Mailboxes with the same name. Servers MAY 269 reject names that violate server policy (e.g., names containing 270 slash (/) or control characters). 272 o *parentId*: "String|null" (default: "null") The mailbox id for the 273 parent of this mailbox, or "null" if this mailbox is at the top 274 level. Mailboxes form acyclic graphs (forests) directed by the 275 child-to-parent relationship. There MUST NOT be a loop. 277 o *role*: "String|null" (default: "null") Identifies mailboxes that 278 have a particular common purpose (e.g. the "inbox"), regardless of 279 the _name_ (which may be localised). This value is shared with 280 IMAP (exposed in IMAP via the [RFC6154] SPECIAL-USE extension). 281 However, unlike in IMAP, a mailbox may only have a single role, 282 and no two mailboxes in the same account may have the same role. 283 The value MUST be one of the mailbox attribute names listed in the 284 IANA Mailbox Name Attributes Registry [1], as established in 285 [TODO], converted to lower-case. New roles may be established 286 here in the future. An account is not required to have mailboxes 287 with any particular roles. 289 o *sortOrder*: "Number" (default: "0") Defines the sort order of 290 mailboxes when presented in the client's UI, so it is consistent 291 between devices. The number MUST be an integer in the range 0 <= 292 sortOrder < 2^31. A mailbox with a lower order should be 293 displayed before a mailbox with a higher order (that has the same 294 parent) in any mailbox listing in the client's UI. Mailboxes with 295 equal order SHOULD be sorted in alphabetical order by name. The 296 sorting SHOULD take into account locale-specific character order 297 convention.. 299 o *totalEmails*: "Number" (server-set) The number of emails in this 300 mailbox. 302 o *unreadEmails*: "Number" (server-set) The number of emails in this 303 mailbox that have neither the "$seen" keyword nor the "$draft" 304 keyword. 306 o *totalThreads*: "Number" (server-set) The number of threads where 307 at least one email in the thread is in this mailbox. 309 o *unreadThreads*: "Number" (server-set) The number of threads where 310 at least one email in the thread has neither the "$seen" keyword 311 nor the "$draft" keyword AND at least one email in the thread is 312 in this mailbox (but see below for special case handling of 313 Trash). Note, the unread email does not need to be the one in 314 this mailbox. 316 o *myRights*: "MailboxRights" (server-set) The set of rights (ACLs) 317 the user has in relation to this mailbox. A _MailboxRights_ 318 object has the following properties: 320 * *mayReadItems*: "Boolean" If true, the user may use this 321 mailbox as part of a filter in a _Email/query_ call and the 322 mailbox may be included in the _mailboxIds_ set of _Email_ 323 objects. If a sub-mailbox is shared but not the parent 324 mailbox, this may be "false". Corresponds to IMAP ACLs "lr". 326 * *mayAddItems*: "Boolean" The user may add mail to this mailbox 327 (by either creating a new email or moving an existing one). 328 Corresponds to IMAP ACL "i". 330 * *mayRemoveItems*: "Boolean" The user may remove mail from this 331 mailbox (by either changing the mailboxes of an email or 332 deleting it). Corresponds to IMAP ACLs "te". 334 * *maySetSeen*: "Boolean" The user may add or remove the "$seen" 335 keyword to/from an email. If an email belongs to multiple 336 mailboxes, the user may only modify "$seen" if *all* of the 337 mailboxes have this permission. Corresponds to IMAP ACL "s". 339 * *maySetKeywords*: "Boolean" The user may add or remove any 340 keyword _other than_ "$seen" to/from an email. If an email 341 belongs to multiple mailboxes, the user may only modify 342 keywords if *all* of the mailboxes have this permission. 343 Corresponds to IMAP ACL "w". 345 * *mayCreateChild*: "Boolean" The user may create a mailbox with 346 this mailbox as its parent. Corresponds to IMAP ACL "k". 348 * *mayRename*: "Boolean" The user may rename the mailbox or make 349 it a child of another mailbox. Corresponds to IMAP ACL "x". 351 * *mayDelete*: "Boolean" The user may delete the mailbox itself. 352 Corresponds to IMAP ACL "x". 354 * *maySubmit*: "Boolean" Messages may be submitted directly to 355 this mailbox. Corresponds to IMAP ACL "p". 357 The Trash mailbox (that is a mailbox with "role == "trash"") MUST be 358 treated specially for the purpose of unread counts: 360 1. Emails that are *only* in the Trash (and no other mailbox) are 361 ignored when calculating the "unreadThreads" count of other 362 mailboxes. 364 2. Emails that are *not* in the Trash are ignored when calculating 365 the "unreadThreads" count for the Trash mailbox. 367 The result of this is that emails in the Trash are treated as though 368 they are in a separate thread for the purposes of unread counts. It 369 is expected that clients will hide emails in the Trash when viewing a 370 thread in another mailbox and vice versa. This allows you to delete 371 a single email to the Trash out of a thread. 373 So for example, suppose you have an account where the entire contents 374 is a single conversation with 2 emails: an unread email in the Trash 375 and a read email in the Inbox. The "unreadThreads" count would be 376 "1" for the Trash and "0" for the Inbox. 378 For IMAP compatibility, an email in both the Trash and another 379 mailbox SHOULD be treated by the client as existing in both places 380 (i.e. when emptying the trash, the client SHOULD just remove the 381 Trash mailbox and leave it in the other mailbox). 383 The following JMAP methods are supported: 385 2.1. Mailbox/get 387 Standard _/get_ method. The _ids_ argument may be "null" to fetch 388 all at once. 390 2.2. Mailbox/changes 392 Standard _/changes_ method, but with one extra argument to the 393 response: 395 o *changedProperties*: "String[]|null" If only the mailbox counts 396 (unread/total emails/threads) have changed since the old state, 397 this will be the list of properties that may have changed, i.e. 398 "["totalEmails", "unreadEmails", "totalThreads", 399 "unreadThreads"]". If the server is unable to tell if only counts 400 have changed, it MUST just be "null". 402 Since counts frequently change but the rest of the mailboxes state 403 for most use cases changes rarely, the server can help the client 404 optimise data transfer by keeping track of changes to email/thread 405 counts separately to other state changes. The _changedProperties_ 406 array may be used directly via a result reference in a subsequent 407 Mailboxe/get call in a single request. 409 2.3. Mailbox/query 411 Standard _/query_ method. 413 A *FilterCondition* object has the following properties, any of which 414 may be omitted: 416 o *parentId*: "String|null" The Mailbox _parentId_ property must 417 match the given value exactly. 419 o *hasRole*: "Boolean" If this is "true", a Mailbox matches if it 420 has a non-"null" value for its _role_ property. 422 A Mailbox object matches the filter if and only if all of the given 423 conditions given match. If zero properties are specified, it is 424 automatically "true" for all objects. 426 The following properties MUST be supported for sorting: 428 o "sortOrder" 430 o "name" 431 o "parent/name": This is a pseudo-property, just for sorting, with 432 the following semantics: if two mailboxes have a common parent, 433 sort them by name. Otherwise, find the nearest ancestors of each 434 that share a common parent and sort by their names instead. (i.e. 435 This sorts the mailbox list in tree order). 437 2.4. Mailbox/queryChanges 439 Standard _/queryChanges_ method. 441 2.5. Mailbox/set 443 Standard _/set_ method, but with the following additional argument: 445 o *onDestroyRemoveMessages*: "Boolean" (default: "false") If 446 "false", attempts to destroy a mailbox that still has any messages 447 in it will be rejected with a "mailboxHasEmail" SetError. If 448 "true", any messages that were in the mailbox will be removed from 449 it, and if in no other mailboxes will be destroyed when the 450 mailbox is destroyed. 452 The following extra _SetError_ types are defined: 454 For *destroy*: 456 o "mailboxHasChild": The mailbox still has at least one child 457 mailbox. The client MUST remove these before it can delete the 458 parent mailbox. 460 o "mailboxHasEmail": The mailbox has at least one message assigned 461 to it and the _onDestroyRemoveMessages_ argument was "false". 463 3. Threads 465 Replies are grouped together with the original message to form a 466 thread. In JMAP, a thread is simply a flat list of emails, ordered 467 by date. Every email MUST belong to a thread, even if it is the only 468 email in the thread. 470 The JMAP spec does not require the server to use any particular 471 algorithm for determining whether two emails belong to the same 472 thread, however there is a recommended algorithm in the 473 implementation guide [2]. 475 If emails are delivered out of order for some reason, a user may 476 receive two emails in the same thread but without headers that 477 associate them with each other. The arrival of a third email in the 478 thread may provide the missing references to join them all together 479 into a single thread. Since the _threadId_ of an email is immutable, 480 if the server wishes to merge the threads, it MUST handle this by 481 deleting and reinserting (with a new email id) the emails that change 482 threadId. 484 A *Thread* object has the following properties: 486 o *id*: "String" (immutable) The id of the thread. 488 o *emailIds*: "String[]" The ids of the emails in the thread, sorted 489 such that: 491 * Any email with the "$draft" keyword that has an "In-Reply-To" 492 header is sorted after the _first_ non-draft email in the 493 thread with the corresponding "Message-Id" header, but before 494 any subsequent non-draft emails. 496 * Other than that, everything is sorted by the _receivedAt_ date 497 of the email, oldest first. 499 * If two emails are identical under the above two conditions, the 500 sort is server-dependent but MUST be stable (sorting by id is 501 recommended). 503 The following JMAP methods are supported: 505 3.1. Thread/get 507 Standard _/get_ method. 509 3.1.1. Example 511 Request: 513 [ "Thread/get", { 514 "ids": ["f123u4", "f41u44"], 515 }, "#1" ] 517 with response: 519 [ "Thread/get", { 520 "accountId": "acme", 521 "state": "f6a7e214", 522 "list": [ 523 { 524 "id": "f123u4", 525 "emailIds": [ "eaa623", "f782cbb"] 526 }, 527 { 528 "id": "f41u44", 529 "emailIds": [ "82cf7bb" ] 530 } 531 ], 532 "notFound": null 533 }, "#1" ] 535 3.2. Thread/changes 537 Standard _/changes_ method. 539 4. Emails 541 The *Email* object is a representation of an [RFC5322] message, which 542 allows clients to avoid the complexities of MIME parsing, transport 543 encoding and character encoding. 545 4.1. Properties of the Email object 547 Broadly, a message consists of two parts: a list of header fields, 548 then a body. The body is normally a MIME-encoded set of documents in 549 a tree structure. The JMAP Email object provides a way to access the 550 full structure, or to use simplified properties and avoid some 551 complexity if this is sufficient for the client application. 553 Due to the number of properties involved, the set of _Email_ 554 properties is specified over the following three sub-sections. 556 4.1.1. Metadata 558 These properties represent metadata about the [RFC5322] message, and 559 are not derived from parsing the message itself. 561 o *id*: "String" (immutable; server-set) The id of the Email object. 562 Note, this is the JMAP object id, NOT the [RFC5322] Message-ID 563 header field value. 565 o *blobId*: "String" (immutable; server-set) The id representing the 566 raw octets of the [RFC5322] message. This may be used to download 567 the raw original message, or to attach it directly to another 568 Email etc. 570 o *threadId*: "String" (immutable; server-set) The id of the Thread 571 to which this Email belongs. 573 o *mailboxIds*: "String[Boolean]" The set of mailbox ids this email 574 belongs to. An email MUST belong to one or more mailboxes at all 575 times (until it is deleted). The set is represented as an object, 576 with each key being a _Mailbox id_. The value for each key in the 577 object MUST be "true". 579 o *keywords*: "String[Boolean]" (default: "{}") A set of keywords 580 that apply to the email. The set is represented as an object, 581 with the keys being the _keywords_. The value for each key in the 582 object MUST be "true". Keywords are shared with IMAP. The six 583 system keywords from IMAP are treated specially. The following 584 four keywords have their first character changed from "\" in IMAP 585 to "$" in JMAP and have particular semantic meaning: 587 * "$draft": The email is a draft the user is composing. 589 * "$seen": The email has been read. 591 * "$flagged": The email has been flagged for urgent/special 592 attention. 594 * "$answered": The email has been replied to. 596 The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP 597 "\Deleted" keyword is also not present: IMAP uses a delete+expunge 598 model, which JMAP does not. Any message with the "\Deleted" 599 keyword MUST NOT be visible via JMAP. Users may add arbitrary 600 keywords to an email. For compatibility with IMAP, a keyword is a 601 case-insensitive string of 1-255 characters in the ASCII subset 602 %x21-%x7e (excludes control chars and space), and MUST NOT include 603 any of these characters: "( ) { ] % * " \" Because JSON is case- 604 sensitive, servers MUST return keywords in lower-case. The IANA 605 Keyword Registry [3] as established in [RFC5788] assigns semantic 606 meaning to some other keywords in common use. New keywords may be 607 established here in the future. In particular, note: 609 * "$forwarded": The email has been forwarded. 611 * "$phishing": The email is highly likely to be phishing. 612 Clients SHOULD warn users to take care when viewing this email 613 and disable links and attachments. 615 * "$junk": The email is definitely spam. Clients SHOULD set this 616 flag when users report spam to help train automated spam- 617 detection systems. 619 * "$notjunk": The email is definitely not spam. Clients SHOULD 620 set this flag when users indicate an email is legitimate, to 621 help train automated spam-detection systems. 623 o *size*: "Number" (immutable; server-set) The size, in octets, of 624 the raw data for the RFC5322 message (as referenced by the 625 _blobId_, i.e. the number of octets in the file the user would 626 download). 628 o *receivedAt*: "UTCDate" (immutable; default: time of creation on 629 server) The date the email was received by the message store. 630 This is the _internal date_ in IMAP. 632 4.1.2. Header fields 634 These properties are derived from the [RFC5322] and [RFC6532] message 635 header fields. All header fields may be fetched in a raw form. Some 636 headers may also be fetched in a parsed form. The structured form 637 that may be fetched depends on the header. The following forms are 638 defined: 640 o *Raw* ("String") The raw octets of the header field value from the 641 first octet following the header field name terminating colon, up 642 to but excluding the header field terminating CRLF. Any 643 standards-compliant message MUST be either ASCII (RFC5322) or 644 UTF-8 (RFC6532), however other encodings exist in the wild. A 645 server MAY use heuristics to determine a charset and decode the 646 octets, or MAY replace any octet or octet run with the high bit 647 set that violates UTF-8 syntax with the unicode replacement 648 character (U+FFFD). Any NUL octet MUST be dropped. 650 o *Text* ("String") The header field value with: 652 1. White space unfolded (as defined in [RFC5322] section 2.2.3) 654 2. The terminating CRLF at the end of the value removed 656 3. Any SP characters at the beginning of the value removed 658 4. Any syntactically correct [RFC2047] encoded sections with a 659 known character set decoded. Any [RFC2047] encoded NUL octets 660 or control characters are dropped from the decoded value. Any 661 text that looks like [RFC2047] syntax but violates [RFC2047] 662 placement or whitespace rules MUST NOT be decoded. 664 5. Any [RFC6532] UTF-8 values decoded. 666 6. The resulting unicode converted to NFC form. 668 If any decodings fail, the parser SHOULD insert a unicode 669 replacement character (U+FFFD) and attempt to continue as much as 670 possible. To prevent obviously nonsense behaviour, which can lead 671 to interoperability issues, this form may only be fetched or set 672 for the following header fields: 674 * Subject 676 * Comment 678 * Any header not defined in [RFC5322] or [RFC2369] 680 o *Addresses* ("EmailAddress[]") The header is parsed as an 681 "address-list" value, as specified in [RFC5322] section 3.4, into 682 the "EmailAddress[]" type. The *EmailAddress* object has the 683 following properties: 685 * *name*: "String|null" The _display-name_ of the [RFC5322] 686 _mailbox_ or _group_, or "null" if none. If this is a _quoted- 687 string_: 689 1. The surrounding DQUOTE characters are removed. 691 2. Any _quoted-pair_ is decoded. 693 3. White-space is unfolded, and then any leading or trailing 694 white-space is removed. 696 * *email*: "String|null" The _addr-spec_ of the [RFC5322] 697 _mailbox_, or "null" if a _group_. 699 Any syntactically correct [RFC2047] encoded sections with a known 700 encoding MUST be decoded, following the same rules as for the _Text_ 701 form. Any [RFC6532] UTF-8 values MUST be decoded. 703 Parsing SHOULD be best-effort in the face of invalid structure to 704 accommodate invalid messages and semi-complete drafts. EmailAddress 705 objects MAY have an _email_ property that does not conform to the 706 _addr-spec_ form (for example, may not contain an @ symbol). 708 To prevent obviously nonsense behaviour, which can lead to 709 interoperability issues, this form may only be fetched or set for the 710 following header fields: 712 o From 714 o Sender 716 o Reply-To 718 o To 720 o Cc 722 o Bcc 724 o Resent-From 726 o Resent-Sender 728 o Resent-Reply-To 730 o Resent-To 732 o Resent-Cc 734 o Resent-Bcc 736 o Any header not defined in [RFC5322] or [RFC2369] 738 o *MessageIds* ("String[]|null") The header is parsed as a list of 739 "msg-id" values, as specified in [RFC5322] section 3.6.4, into the 740 "String[]" type. If parsing fails, the value is "null". 742 To prevent obviously nonsense behaviour, which can lead to 743 interoperability issues, this form may only be fetched or set for the 744 following header fields: 746 o Message-ID 748 o In-Reply-To 750 o References 752 o Resent-Message-ID 754 o Any header not defined in [RFC5322] or [RFC2369] 756 o *Date* ("Date|null") The header is parsed as a "date-time" value, 757 as specified in [RFC5322] section 3.3, into the "Date" type. If 758 parsing fails, the value is "null". 760 To prevent obviously nonsense behaviour, which can lead to 761 interoperability issues, this form may only be fetched or set for the 762 following header fields: 764 o Date 766 o Resent-Date 768 o Any header not defined in [RFC5322] or [RFC2369] 770 o *URL* ("String|null") The header is parsed as a URL, as described 771 in [RFC2369], into the "String" type. This does not include the 772 surrounding angle brackets or any comments in the header with the 773 URL. If parsing fails, the value is "null". 775 To prevent obviously nonsense behaviour, which can lead to 776 interoperability issues, this form may only be fetched or set for the 777 following header fields: 779 o List-Help 781 o List-Unsubscribe 783 o List-Subscribe 785 o List-Post 787 o List-Owner 789 o List-Archive 791 o Any header not defined in [RFC5322] or [RFC2369] 793 The following low-level *Email* property is specified for complete 794 access to the header data of the message: 796 o *headers*: "EmailHeader[]" (immutable) This is a list of all 797 [RFC5322] header fields, in the same order they appear in the 798 message. An *EmailHeader* object has the following properties: 800 * *name*: "String" The header _field name_ as defined in RFC5322, 801 with the same capitalization that it has in the message. 803 * *value*: "String" The header _field value_ as defined in 804 RFC5322, in _Raw_ form. 806 In addition, the client may request/send properties representing 807 individual header fields of the form: 809 header:{header-field-name} 811 Where "{header-field-name}" means any series of one or more printable 812 ASCII characters (i.e. characters that have values between 33 and 813 126, inclusive), except colon. The property may also have the 814 following suffixes: 816 o *:as{header-form}* This means the value is in a parsed form, where 817 "{header-form}" is one of the parsed-form names specified above. 818 If not given, the value is in _Raw_ form. 820 o *:all* This means the value is an array, with the items 821 corresponding to each instance of the header field, in the order 822 they appear in the message. If this suffix is not used, the 823 result is the value of the *last* instance of the header field 824 (i.e. identical to the *last* item in the array if :all is used), 825 or "null" if none. 827 If both suffixes are used, they MUST be specified in the order above. 828 Header field names are matched case-insensitively. The value is 829 typed according to the requested form, or an array of that type if 830 :all is used. If no header fields exist in the message with the 831 requested name, the value is "null" if fetching a single instance, or 832 the empty array if requesting :all. 834 As a simple example, if the client requests a property called 835 "header:subject", this means find the _last_ header field in the 836 message named "subject" (matched case-insensitively) and return the 837 value in _Raw_ form, or "null" if no header of this name is found. 839 For a more complex example, consider the client requesting a property 840 called "header:Resent-To:asAddresses:all". This means: 842 1. Find _all_ header fields named Resent-To (matched case- 843 insensitively). 845 2. For each instance parse the header field value in the _Addresses_ 846 form. 848 3. The result is of type "EmailAddress[][]" - each item in the array 849 corresponds to the parsed value (which is itself an array) of the 850 Resent-To header field instance. 852 The following convenience properties are also specified for the 853 *Email* object: 855 o *messageId*: "String[]|null" (immutable) The value is identical to 856 the value of _header:Message-ID:asMessageIds_. For messages 857 conforming to RFC5322 this will be an array with a single entry. 859 o *inReplyTo*: "String[]|null" (immutable) The value is identical to 860 the value of _header:In-Reply-To:asMessageIds_. 862 o *references*: "String[]|null" (immutable) The value is identical 863 to the value of _header:References:asMessageIds_. 865 o *sender*: "EmailAddress[]|null" (immutable) The value is identical 866 to the value of _header:Sender:asAddresses_. 868 o *from*: "EmailAddress[]|null" (immutable) The value is identical 869 to the value of _header:From:asAddresses_. 871 o *to*: "EmailAddress[]|null" (immutable) The value is identical to 872 the value of _header:To:asAddresses_. 874 o *cc*: "EmailAddress[]|null" (immutable) The value is identical to 875 the value of _header:Cc:asAddresses_. 877 o *bcc*: "EmailAddress[]|null" (immutable) The value is identical to 878 the value of _header:Bcc:asAddresses_. 880 o *replyTo*: "EmailAddress[]|null" (immutable) The value is 881 identical to the value of _header:Reply-To:asAddresses_. 883 o *subject*: "String|null" (immutable) The value is identical to the 884 value of _header:Subject:asText_. 886 o *sentAt*: "Date|null" (immutable; default on creation: current 887 server time) The value is identical to the value of 888 _header:Date:asDate_. 890 4.1.3. Body parts 892 These properties are derived from the [RFC5322] message body and its 893 [RFC2045] MIME entities. 895 A *EmailBodyPart* object has the following properties: 897 o *partId*: "String" Identifies this part uniquely within the Email. 898 This is scoped to the _emailId_ and has no meaning outside of the 899 JMAP Email object representation. 901 o *blobId*: "String" The id references the raw octets of the 902 contents of the part after decoding any _Content-Transfer_ 903 encoding (as defined in [RFC2045]). Note, two parts may be 904 transfer-encoded differently but have same the same blob id if 905 their decoded octets are identical and the server is using a 906 secure hash of the data for the blob id. 908 o *size*: "Number" The size, in octets, of the raw data after 909 content-transfer decoding (as referenced by the _blobId_, i.e. the 910 number of octets in the file the user would download). 912 o *headers*: "EmailHeader[]" (immutable) This is a list of all 913 header fields in the part, in the order they appear. The values 914 are in _Raw_ form. 916 o *name*: "String|null" This is the [RFC2231] decoded _filename_ 917 parameter of the _Content-Disposition_ header field, or (for 918 compatibility with existing systems) if not present then the 919 [RFC2047] decoded _name_ parameter of the _Content-Type_ header 920 field. 922 o *type*: "String" The value of the _Content-Type_ header field of 923 the part, if present, otherwise "null". CFWS is removed and any 924 parameters are stripped. 926 o *charset*: "String|null" The value of the charset parameter of the 927 _Content-Type_ header field, if present. 929 o *disposition*: "String|null" The value of the _Content- 930 Disposition_ header field of the part, if present, otherwise 931 "null". CFWS is removed and any parameters are stripped. 933 o *cid*: "String|null" The value of the _Content-Id_ header field of 934 the part, if present, otherwise "null". CFWS is removed. This 935 may be used to reference the content from within an html body part 936 using the "cid:" protocol. 938 o *language*: "String[]|null" The list of language tags, as defined 939 in [RFC3282], in the _Content-Language_ header field of the part, 940 if present. 942 o *location*: "String|null" The URI, as defined in [RFC2557], in the 943 _Content-Location_ header field of the part, if present. 945 o *subParts*: "EmailBodyPart[]" (optional) If type is "multipart/*", 946 this contains the body parts of each child. 948 The following *Email* properties are specified for access to the body 949 data of the message: 951 o *bodyStructure*: "EmailBodyPart[]" (immutable) This is the full 952 MIME structure of the message body, including sub parts but not 953 recursing into "message/rfc822" or "message/global" parts. 955 o *bodyValues*: "String[BodyValue]" (immutable) This is a map of 956 _partId_ to an *EmailBodyValue* object for none, some or all 957 "text/*" parts. Which parts are included and whether the value is 958 truncated is determined by various arguments to _Email/get_ and 959 _Email/parse_. An *EmailBodyValue* object has the following 960 properties: 962 * *value*: "String" The value of the body part after decoding 963 _Content-Transport-Encoding_ and decoding the _Content-Type_ 964 charset, if known to the server. The server MAY use heuristics 965 to determine the charset to use for decoding if the charset is 966 unknown, or if no charset is given, or if it believes the 967 charset given is incorrect. Decoding is best-effort and SHOULD 968 insert the unicode replacement character (U+FFFD) and continue 969 when a malformed section is encountered. 971 * *isEncodingProblem*: "Boolean" This is "true" if malformed 972 sections were found while decoding the charset, or the charset 973 was unknown. 975 * *isTruncated*: "Boolean" This is "true" if the _value_ has been 976 truncated. 978 See the security considerations section for issues related to 979 truncation and heuristic determination of content-type and 980 charset. 982 o *textBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", 983 "text/html" and "image/*" parts to display (sequentially) as the 984 message body, with a preference for "text/plain" when alternative 985 versions are available. 987 o *htmlBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", 988 "text/html" and "image/*" parts to display (sequentially) as the 989 message body, with a preference for "text/html" when alternative 990 versions are available. 992 o *attachedEmails*: "EmailBodyPart[]" (immutable) A list of all 993 parts of type "message/rfc822" or "message/global". Note, this 994 *does not* recurse, so the parts within these are not included. 995 The attached message may be fetched using the Email/parse method 996 and the blobId. 998 o *attachedFiles*: "EmailBodyPart[]" (immutable) A list of all parts 999 in _bodyStructure_, traversing depth-first, which satisfy either 1000 of the following conditions: 1002 * not of type "multipart/*" and not included in _attachedEmails_, 1003 _textBody_ or _htmlBody_ 1005 * of type "image/*" and not in both _textBody_ and _htmlBody_ 1007 Note, an HTML body part may reference image parts in attachedFiles 1008 using "cid:" links to reference the _Content-Id_ or by referencing 1009 the _Content-Location_. 1011 o *hasAttachment*: "Boolean" (immutable; server-set) This is "true" 1012 if there are one or more parts in the message that a client UI 1013 should offer as downloadable. A server SHOULD set hasAttachment 1014 if either: 1016 * The _attachedEmails_ list contains at least one item. 1018 * The _attachedFiles_ list contains at least one item that does 1019 not have "Content-Disposition: inline". The server MAY ignore 1020 parts in this list that are processed automatically in some 1021 way, or are referenced as embedded images in one of the "text/ 1022 html" parts of the message. 1024 The server MAY set hasAttachment based on implementation-defined 1025 or site configurable heuristics. 1027 o *preview*: "String" (immutable; server-set) Up to 256 characters 1028 of plain text, summarising the message body. This is intended to 1029 be shown as a preview line on a mailbox listing, and may be 1030 truncated when shown. The server may choose which part of the 1031 message to include in the preview, for example skipping quoted 1032 sections and salutations and collapsing white-space can result in 1033 a more useful preview. 1035 MIME structures are arbitrary nested trees of documents, but the 1036 majority of email clients present a model of an email body (normally 1037 plain text or HTML), with a set of attachments. Interpreting the 1038 MIME structure to form this flat model represents considerable 1039 difficulty and causes inconsistency between clients. Therefore in 1040 addition to the _bodyStructure_ property, which gives the full tree, 1041 the Email object contains 4 alternate properties with flat lists of 1042 body parts: 1044 o _textBody_/_htmlBody_: These provide a list of parts that should 1045 be rendered as the "body" of the message. This is a list rather 1046 than a single part as messages may have headers and/or footers 1047 appended/prepended as separate parts as they are transmitted, and 1048 some clients send text and images intended to be displayed inline 1049 in the body as multiple parts rather than a single HTML part with 1050 referenced images. 1052 Because MIME allows for multiple representations of the same data 1053 (using "multipart/alternative"), there is a textBody property (which 1054 prefers a plain text representation) and an htmlBody property (which 1055 prefers an HTML representation) to accommodate the two most common 1056 client requirements. The same part may appear in both lists where 1057 there is no alternative between the two. 1059 o _attachedEmails_/_attachedFiles_: These provide a list of parts 1060 that should be presented as "attachments" to the message. Emails 1061 are presented in a separate list so their contents may be easily 1062 fetched via a back-reference with the "Email/parse" method in the 1063 same request, if the client wishes to. Some images in 1064 attachedFiles may be solely there for embedding within an HTML 1065 body part; clients may wish to not present these as attachments in 1066 the user interface if they are displaying the HTML with the 1067 embedded images directly. Some parts may also be in htmlBody/ 1068 textBody; again, clients may wish to not present these as 1069 attachments in the user interface if rendered as part of the body. 1071 The _bodyValues_ property allows for clients to fetch the value of 1072 text parts directly without having to do a second request for the 1073 blob, and have the server handle decoding the charset into unicode. 1074 This data is in a separate property rather than on the EmailBodyPart 1075 object to avoid duplication of large amounts of data, as the same 1076 part may be included twice if the client fetches more than one of 1077 bodyStructure, textBody and htmlBody. 1079 The exact algorithm for decomposing bodyStructure into textBody, 1080 htmlBody, attachedEmails and attachedFiles part lists is not 1081 mandated, as this is a quality-of-service implementation issue and 1082 likely to require workarounds for malformed content discovered over 1083 time. However, the following algorithm (expressed here in 1084 JavaScript) is suggested as a starting point, based on real-world 1085 experience: 1087 function parseStructure ( parts, multipartType, inAlternative, 1088 htmlBody, textBody, attachedEmails, attachedFiles ) { 1090 // For multipartType == alternative 1091 let textLength = textBody ? textBody.length : -1; 1092 let htmlLength = htmlBody ? htmlBody.length : -1; 1093 for ( let i = 0; i < parts.length; i += 1 ) { 1094 let part = parts[i]; 1095 let isMultipart = part.type.startsWith( 'multipart/' ); 1096 // Is this a body part rather than an attachment 1097 let isInline = part.disposition != "attachment" && 1098 // Must be one of the allowed body types 1099 ( part.type == "text/plain" || 1100 part.type == "text/html" || 1101 part.type.startsWith( 'image/' ) ) && 1102 // If not the first part and has a filename, assume attachment 1103 ( i == 0 || !part.name ) && 1104 // If multipart/related, only the first part can be inline 1105 ( i > 0 || multipartType != 'related' ); 1107 if ( isMultipart ) { 1108 let subMultiType = part.type.split( '/' )[1]; 1109 parseStructure( part.subParts, subMultiType, 1110 inAlternative || ( subMultiType == 'alternative' ), 1111 htmlBody, textBody, attachedEmails, attachedFiles ); 1112 } else if ( isInline ) { 1113 if ( inAlternative && part.type == 'text/plain' ) { 1114 htmlBody = null; 1115 } 1116 if ( inAlternative && part.type == 'text/html' ) { 1117 textBody = null; 1118 } 1119 if ( textBody ) { 1120 textBody.push( part ); 1121 } 1122 if ( htmlBody ) { 1123 htmlBody.push( part ); 1124 } 1125 if ( ( !textBody || !htmlBody ) && 1126 part.type.startsWith( 'image/' ) ) { 1127 attachedFiles.push( part ); 1128 } 1129 } else if ( part.type == 'message/rfc822' || 1130 part.type == 'message/global' ) { 1131 attachedEmails.push( part ); 1132 } else { 1133 attachedFiles.push( part ); 1134 } 1136 if ( multipartType == 'alternative' ) { 1137 // Found HTML part only 1138 if ( textBody && textLength == textBody.length && 1139 htmlLength != htmlBody.length ) { 1140 for ( let i = htmlLength; i < htmlBody.length; i += 1 ) { 1141 textBody.push( htmlBody[i] ); 1142 } 1143 } 1144 // Found plain text part only 1145 if ( htmlBody && htmlLength == htmlBody.length && 1146 textLength != textBody.length ) { 1147 for ( let i = textLength; i < textBody.length; i += 1 ) { 1148 htmlBody.push( textBody[i] ); 1149 } 1150 } 1151 } 1152 } 1153 } 1155 // Usage: 1156 let htmlBody = []; 1157 let textBody = []; 1158 let attachedEmails = []; 1159 let attachedFiles = []; 1161 parseStructure( bodyStructure, 'mixed', false, 1162 htmlBody, textBody, attachedEmails, attachedFiles ); 1164 For instance, consider a message with both text and html versions 1165 that's then gone through a list software manager that attaches a 1166 header/footer. It might have a MIME structure something like: 1168 multipart/mixed 1169 text/plain, content-disposition=inline - A 1170 multipart/mixed 1171 multipart/alternative 1172 multipart/mixed 1173 text/plain, content-disposition=inline - B 1174 image/jpeg, content-disposition=inline - C 1175 text/plain, content-disposition=inline - D 1176 multipart/related 1177 text/html - E 1178 image/jpeg - F 1179 image/jpeg, content-disposition=attachment - G 1180 application/x-excel - H 1181 message/rfc822 - J 1182 text/plain, content-disposition=inline - K 1184 In this case, the above algorithm would decompose this to: 1186 textBody => [ A, B, C, D, K ] 1187 htmlBody => [ A, E, K ] 1188 attachedEmails: [ J ] 1189 attachedFiles => [ C, F, G, H ] 1191 4.2. Email/get 1193 Standard _/get_ method, with the following additional arguments: 1195 o *bodyProperties*: "String[]" (optional) A list of properties to 1196 fetch for each EmailBodyPart returned. If omitted, this defaults 1197 to: [ "partId", "blobId", "size", "name", "type", "charset", 1198 "disposition", cid", "language", "location" ] 1200 o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the 1201 _bodyValues_ property includes any "text/*" part in the "textBody" 1202 property. 1204 o *fetchHTMLBodyValues*: "Boolean" (default: "false") If "true", the 1205 _bodyValues_ property includes any "text/*" part in the "htmlBody" 1206 property. 1208 o *fetchAllBodyValues*: "Boolean" (default: "false") If "true", the 1209 _bodyValues_ property includes any "text/*" part in the 1210 "bodyStructure" property. 1212 o *maxBodyValueBytes*: "Number" (optional) If supplied by the 1213 client, the value MUST be a positive integer greater than 0. If a 1214 value outside of this range is given, the server MUST reject the 1215 call with an "invalidArguments" error. When given, the _value_ 1216 property of any EmailBodyValue object returned in _bodyValues_ 1217 MUST be truncated if necessary so it does not exceed this number 1218 of octets in size. The server MUST ensure the truncation results 1219 in valid UTF-8 and does not occur mid-codepoint. If the part is 1220 of type "text/html", the server SHOULD NOT truncate inside an HTML 1221 tag. 1223 If the standard _properties_ argument is omitted or "null", the 1224 following default MUST be used instead of "all" properties: 1226 [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size", "receivedAt", "messageId", "inReplyTo", "references", "sender", "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", "attachedFiles", "attachedEmails" ] 1228 The following properties are expected to be fast to fetch in a 1229 quality implementation: 1231 o id 1233 o blobId 1234 o threadId 1236 o mailboxIds 1238 o keywords 1240 o size 1242 o receivedAt 1244 o messageId 1246 o inReplyTo 1248 o sender 1250 o from 1252 o to 1254 o cc 1256 o bcc 1258 o replyTo 1260 o subject 1262 o sentAt 1264 o hasAttachment 1266 o preview 1268 Clients SHOULD take care when fetching any other properties, as there 1269 may be significantly longer latency in fetching and returning the 1270 data. 1272 As specified above, parsed forms of headers may only be used on 1273 appropriate header fields. Attempting to fetch a form that is 1274 forbidden (e.g. "header:From:asDate") MUST result in the method call 1275 being rejected with an "invalidArguments" error. 1277 Where a specific header is requested as a property, the 1278 capitalization of the property name in the response MUST be identical 1279 to that used in the request. 1281 4.2.1. Example 1283 Request: 1285 ["Email/get", { 1286 "ids": [ "f123u456", "f123u457" ], 1287 "properties": [ "threadId", "mailboxIds", "from", "subject", "receivedAt", "header:List-POST:asURL" "htmlBody", "bodyValues" ], 1288 "bodyProperties": [ "partId", "blobId", "size", "type" ], 1289 "fetchHTMLBodyValues": true, 1290 "maxBodyValueBytes": 256 1291 }, "#1"] 1293 and response: 1295 ["Email/get", { 1296 "accountId": "abc", 1297 "state": "41234123231", 1298 "list": [ 1299 { 1300 "id": "f123u457", 1301 "threadId": "ef1314a", 1302 "mailboxIds": { "f123": true }, 1303 "from": [{name: "Joe Bloggs", email: "joe@bloggs.com"}], 1304 "subject": "Dinner on Thursday?", 1305 "receivedAt": "2013-10-13T14:12:00Z", 1306 "header:List-POST:asURL": "mailto:partytime@lists.example.com", 1307 "htmlBody": [{ 1308 "partId": "1", 1309 "blobId": "841623871", 1310 "size": 283331, 1311 "type": "text/html" 1312 }, { 1313 "partId": "2", 1314 "blobId": "319437193", 1315 "size": 10343, 1316 "type": "text/plain" 1317 }], 1318 "bodyValues": { 1319 "1": { 1320 "isEncodingProblem": false, 1321 "isTruncated": true, 1322 "value": "

Hello ..." 1323 }, 1324 "2": { 1325 "isEncodingProblem": false, 1326 "isTruncated": false, 1327 "value": "-- \nSent by your friendly mailing list ..." 1328 } 1329 } 1330 } 1331 ], 1332 notFound: [ "f123u456" ] 1333 }, "#1"] 1335 4.3. Email/changes 1337 Standard _/changes_ method. 1339 4.4. Email/query 1341 Standard _/query_ method, but with the following additional 1342 arguments: 1344 o *collapseThreads*: "Boolean" (default: "false") If "true", emails 1345 in the same thread as a previous email in the list (given the 1346 filter and sort order) will be removed from the list. This means 1347 at most only one email will be included in the list for any given 1348 thread. 1350 4.4.1. Filtering 1352 A *FilterCondition* object has the following properties, any of which 1353 may be omitted: 1355 o *inMailbox*: "String" A mailbox id. An email must be in this 1356 mailbox to match the condition. 1358 o *inMailboxOtherThan*: "String[]" A list of mailbox ids. An email 1359 must be in at least one mailbox not in this list to match the 1360 condition. This is to allow messages solely in trash/spam to be 1361 easily excluded from a search. 1363 o *before*: "UTCDate" The _receivedAt_ date of the email must be 1364 before this date to match the condition. 1366 o *after*: "UTCDate" The _receivedAt_ date of the email must be on 1367 or after this date to match the condition. 1369 o *minSize*: "Number" The _size_ of the email in octets must be 1370 equal to or greater than this number to match the condition. 1372 o *maxSize*: "Number" The size of the email in octets must be less 1373 than this number to match the condition. 1375 o *allInThreadHaveKeyword*: "String" All emails (including this one) 1376 in the same thread as this email must have the given keyword to 1377 match the condition. 1379 o *someInThreadHaveKeyword*: "String" At least one email (possibly 1380 this one) in the same thread as this email must have the given 1381 keyword to match the condition. 1383 o *noneInThreadHaveKeyword*: "String" All emails (including this 1384 one) in the same thread as this email must *not* have the given 1385 keyword to match the condition. 1387 o *hasKeyword*: "String" This email must have the given keyword to 1388 match the condition. 1390 o *notKeyword*: "String" This email must not have the given keyword 1391 to match the condition. 1393 o *hasAttachment*: "Boolean" The "hasAttachment" property of the 1394 email must be identical to the value given to match the condition. 1396 o *text*: "String" Looks for the text in emails. The server SHOULD 1397 look up text in the _from_, _to_, _cc_, _bcc_, _subject_ header 1398 fields of the message, and inside any "text/*" or other body parts 1399 that may converted to text by the server. The server MAY extend 1400 the search to any additional textual property. 1402 o *from*: "String" Looks for the text in the _From_ header field of 1403 the message. 1405 o *to*: "String" Looks for the text in the _To_ header field of the 1406 message. 1408 o *cc*: "String" Looks for the text in the _Cc_ header field of the 1409 message. 1411 o *bcc*: "String" Looks for the text in the _Bcc_ header field of 1412 the message. 1414 o *subject*: "String" Looks for the text in the _subject_ property 1415 of the email. 1417 o *body*: "String" Looks for the text in one of the "text/*" body 1418 parts of the email. 1420 o *attachments*: "String" Looks for the text in the attachments of 1421 the email. Server MAY handle text extraction when possible for 1422 the different kinds of media. 1424 o *header*: "String[]" The array MUST contain either one or two 1425 elements. The first element is the name of the header field to 1426 match against. The second (optional) element is the text to look 1427 for in the header field value. If not supplied, the message 1428 matches simply if it _has_ a header field of the given name. 1430 If zero properties are specified on the FilterCondition, the 1431 condition MUST always evaluate to "true". If multiple properties are 1432 specified, ALL must apply for the condition to be "true" (it is 1433 equivalent to splitting the object into one-property conditions and 1434 making them all the child of an AND filter operator). 1436 The exact semantics for matching "String" fields is *deliberately not 1437 defined* to allow for flexibility in indexing implementation, subject 1438 to the following: 1440 o Any syntactically correct [RFC2047] encoded sections of header 1441 fields with a known encoding SHOULD be decoded before attempting 1442 to match text. 1444 o When searching inside a "text/html" body part, HTML tags and 1445 attributes SHOULD be ignored. 1447 o Text SHOULD be matched in a case-insensitive manner. 1449 o Text contained in either (but matched) single or double quotes 1450 SHOULD be treated as a *phrase search*, that is a match is 1451 required for that exact word or sequence of words, excluding the 1452 surrounding quotation marks. Use "\"", "\'" and "\\" to match a 1453 literal """, "'" and "\" respectively in a phrase. 1455 o Outside of a phrase, white-space SHOULD be treated as dividing 1456 separate tokens that may be searched for separately, but MUST all 1457 be present for the email to match the filter. 1459 o Tokens MAY be matched on a whole-word basis using stemming (so for 1460 example a text search for "bus" would match "buses" but not 1461 "business"). 1463 4.4.2. Sorting 1465 The following properties MUST be supported for sorting: 1467 o *receivedAt* - The _receivedAt_ date as returned in the Email 1468 object. 1470 The following properties SHOULD be supported for sorting: 1472 o *size* - The size as returned in the Email object. 1474 o *from* - This is taken to be either the "name" part, or if 1475 "null"/empty then the "email" part, of the *first* EmailAddress 1476 object in the _from_ property. If still none, consider the value 1477 to be the empty string. 1479 o *to* - This is taken to be either the "name" part, or if 1480 "null"/empty then the "email" part, of the *first* EmailAddress 1481 object in the _to_ property. If still none, consider the value to 1482 be the empty string. 1484 o *subject* - This is taken to be the base subject of the email, as 1485 defined in section 2.1 of [RFC5256]. 1487 o *sentAt* - The _sentAt_ property on the Email object. 1489 o *hasKeyword* - This value MUST be considered "true" if the email 1490 has the keyword given as the _keyword_ property on this 1491 _Comparator_ object, or "false" otherwise. 1493 o *allInThreadHaveKeyword* - This value MUST be considered "true" 1494 for the email if *all* of the emails in the same thread 1495 (regardless of mailbox) have the keyword given as the _keyword_ 1496 property on this _Comparator_ object. 1498 o *someInThreadHaveKeyword* - This value MUST be considered "true" 1499 for the email if *any* of the emails in the same thread 1500 (regardless of mailbox) have the keyword given as the _keyword_ 1501 property on this _Comparator_ object. 1503 The server MAY support sorting based on other properties as well. A 1504 client can discover which properties are supported by inspecting the 1505 server's _capabilities_ object (see section 1). 1507 Example sort: 1509 [{ 1510 "property": "someInThreadHaveKeyword", 1511 "keyword": "$flagged", 1512 "isAscending": false, 1513 }, { 1514 "property": "subject", 1515 "collation": "i;ascii-casemap" 1516 }, { 1517 "property": "receivedAt desc", 1518 "isAscending": false, 1519 }] 1521 This would sort emails in flagged threads first (the thread is 1522 considered flagged if any email within it is flagged), and then in 1523 subject order, then newest first for messages with the same subject. 1524 If two emails have both identical flagged status, subject and date, 1525 the order is server-dependent but must be stable. 1527 4.4.3. Thread collapsing 1529 When "collapseThreads == true", then after filtering and sorting the 1530 email list, the list is further winnowed by removing any emails for a 1531 thread id that has already been seen (when passing through the list 1532 sequentially). A thread will therefore only appear *once* in the 1533 "threadIds" list of the result, at the position of the first email in 1534 the list that belongs to the thread. 1536 4.4.4. Response 1538 The response has the following additional argument: 1540 o *collapseThreads*: "Boolean" The _collapseThreads_ value that was 1541 used when calculating the email list for this call. 1543 4.5. Email/queryChanges 1545 Standard _/queryChanges_ method, with the following additional 1546 arguments: 1548 o *collapseThreads*: "Boolean" (default: "false") The 1549 _collapseThreads_ argument that was used with _Email/query_. 1551 The response has the following additional argument: 1553 o *collapseThreads*: "Boolean" The _collapseThreads_ value that was 1554 used when calculating the email list for this call. 1556 4.6. Email/set 1558 Standard _/set_ method. The _Email/set_ method encompasses: 1560 o Creating a draft 1562 o Changing the keywords of an email (unread/flagged status) 1564 o Adding/removing an email to/from mailboxes (moving a message) 1566 o Deleting emails 1568 Due to the format of the Email object, when creating an email there 1569 are a number of ways to specify headers. The client MUST NOT supply 1570 conflicting information (for example, if a _headers_ property is 1571 given, no other header field property may be given as these form a 1572 complete set). Header fields MUST NOT be specified in parsed forms 1573 that are forbidden for that field. Creation attempts that violate 1574 any of this MUST be rejected with an "invalidProperties" error. 1576 The server MAY also choose to set additional headers. If not 1577 included, the server MUST generate and set a "Message-ID" header 1578 field in conformance with [RFC5322] section 3.6.4, and a "Date" 1579 header field in conformance with section 3.6.1. 1581 Other than making sure it conforms to the correct type, the server 1582 MUST NOT attempt to validate _from_/_to_/_cc_/_bcc_ (e.g. checking if 1583 an email address is valid) when creating an email. This is to ensure 1584 drafts can be saved at any point. 1586 Destroying an email removes it from all mailboxes to which it 1587 belonged. To just delete an email to trash, simply change the 1588 "mailboxIds" property so it is now in the mailbox with "role == 1589 "trash"", and remove all other mailbox ids. 1591 When emptying the trash, clients SHOULD NOT destroy emails which are 1592 also in a mailbox other than trash. For those emails, they SHOULD 1593 just remove the Trash mailbox from the email. 1595 The following extra _SetError_ types are defined: 1597 For *create*: 1599 o "blobNotFound": At least one blob id given for an EmailBodyPart 1600 doesn't exist. An extra _notFound_ property of type "String[]" 1601 MUST be included in the error object containing every _blobId_ 1602 referenced by an EmailBodyPart that could not be found on the 1603 server. 1605 For *create* and *update*: 1607 o "tooManyKeywords": The change to the email's keywords would exceed 1608 a server-defined maximum. 1610 o "tooManyMailboxes": The change to the email's mailboxes would 1611 exceed a server-defined maximum. 1613 4.7. Email/import 1615 The _Email/import_ method adds [RFC5322] messages to a user's set of 1616 emails. The messages must first be uploaded as a file using the 1617 standard upload mechanism. It takes the following arguments: 1619 o *accountId*: "String|null" The id of the account to use for this 1620 call. If "null", defaults to the primary account. 1622 o *emails*: "String[EmailImport]" A map of creation id (client 1623 specified) to EmailImport objects 1625 An *EmailImport* object has the following properties: 1627 o *blobId*: "String" The id of the blob containing the raw [RFC5322] 1628 message. 1630 o *mailboxIds* "String[Boolean]" The ids of the mailbox(es) to 1631 assign this email to. At least one mailbox MUST be given. 1633 o *keywords*: "String[Boolean]" (default: "{}") The keywords to 1634 apply to the email. 1636 o *receivedAt*: "UTCDate" (default: time of import on server) The 1637 _receivedAt_ date to set on the email. 1639 Each email to import is considered an atomic unit which may succeed 1640 or fail individually. Importing successfully creates a new email 1641 object from the data reference by the blobId and applies the given 1642 mailboxes, keywords and receivedAt date. 1644 The server MAY forbid two email objects with the same exact [RFC5322] 1645 content, or even just with the same [RFC5322] Message-ID, to coexist 1646 within an account. In this case, it MUST reject attempts to import 1647 an email considered a duplicate with an "alreadyExists" SetError. An 1648 _emailId_ property of type "String" MUST be included on the error 1649 object with the id of the existing email. 1651 If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid 1652 (e.g. missing, wrong type, id not found), the server MUST reject the 1653 import with an "invalidProperties" SetError. 1655 If the email cannot be imported because it would take the account 1656 over quota, the import should be rejected with a "maxQuotaReached" 1657 SetError. 1659 If the blob referenced is not a valid [RFC5322] message, the server 1660 MAY modify the message to fix errors (such as removing NUL octets or 1661 fixing invalid headers). If it does this, the _blobId_ on the 1662 response MUST represent the new representation and therefore be 1663 different to the _blobId_ on the EmailImport object. Alternatively, 1664 the server MAY reject the import with an "invalidEmail" SetError. 1666 The response has the following arguments: 1668 o *accountId*: "String" The id of the account used for this call. 1670 o *created*: "String[Email]" A map of the creation id to an object 1671 containing the _id_, _blobId_, _threadId_ and _size_ properties 1672 for each successfully imported Email. 1674 o *notCreated*: "String[SetError]" A map of creation id to a 1675 SetError object for each Email that failed to be created. The 1676 possible errors are defined above. 1678 4.8. Email/copy 1680 The only way to move messages *between* two different accounts is to 1681 copy them using the _Email/copy_ method, then once the copy has 1682 succeeded, delete the original. The _onSuccessDestroyOriginal_ 1683 argument allows you to try to do this in one method call, however 1684 note that the two different actions are not atomic, and so it is 1685 possible for the copy to succeed but the original not to be destroyed 1686 for some reason. 1688 The _Email/copy_ method takes the following arguments: 1690 o *fromAccountId*: "String|null" The id of the account to copy 1691 emails from. If "null", defaults to the primary account. 1693 o *toAccountId*: "String|null" The id of the account to copy emails 1694 to. If "null", defaults to the primary account. 1696 o *create*: "String[EmailCopy]" A map of _creation id_ to an 1697 EmailCopy object. 1699 o *onSuccessDestroyOriginal*: "Boolean" (default: "false") If 1700 "true", an attempt will be made to destroy the emails that were 1701 successfully copied: after emitting the _Email/copy_ response, but 1702 before processing the next method, the server MUST make a single 1703 call to _Email/set_ to destroy the original of each successfully 1704 copied message; the output of this is added to the responses as 1705 normal to be returned to the client. 1707 An *EmailCopy* object has the following properties: 1709 o *id*: "String" The id of the email to be copied in the "from" 1710 account. 1712 o *mailboxIds*: "String[Boolean]" The ids of the mailboxes (in the 1713 "to" account) to add the copied email to. At least one mailbox 1714 MUST be given. 1716 o *keywords*: "String[Boolean]" (default: "{}") The _keywords_ 1717 property for the copy. 1719 o *receivedAt*: "UTCDate" (default: _receivedAt_ date of original) 1720 The _receivedAt_ date to set on the copy. 1722 The server MAY forbid two email objects with the same exact [RFC5322] 1723 content, or even just with the same [RFC5322] Message-ID, to coexist 1724 within an account. If duplicates are allowed though, the "from" 1725 account may be the same as the "to" account to copy emails within an 1726 account. 1728 Each email copy is considered an atomic unit which may succeed or 1729 fail individually. Copying successfully MUST create a new email 1730 object, with separate ids and mutable properties (e.g. mailboxes and 1731 keywords) to the original email. 1733 The response has the following arguments: 1735 o *fromAccountId*: "String" The id of the account emails were copied 1736 from. 1738 o *toAccountId*: "String" The id of the account emails were copied 1739 to. 1741 o *created*: "String[Email]|null" A map of the creation id to an 1742 object containing the _id_, _blobId_, _threadId_ and _size_ 1743 properties for each successfully copied Email. 1745 o *notCreated*: "String[SetError]|null" A map of creation id to a 1746 SetError object for each Email that failed to be copied, "null" if 1747 none. 1749 The *SetError* may be any of the standard set errors that may be 1750 returned for a _create_. The following extra _SetError_ type is also 1751 defined: 1753 "alreadyExists": The server forbids duplicates and the email already 1754 exists in the target account. An _emailId_ property of type "String" 1755 MUST be included on the error object with the id of the existing 1756 email. 1758 The following additional errors may be returned instead of the 1759 _Email/copy_ response: 1761 "fromAccountNotFound": A _fromAccountId_ was explicitly included with 1762 the request, but it does not correspond to a valid account. 1764 "toAccountNotFound": A _toAccountId_ was explicitly included with the 1765 request, but it does not correspond to a valid account. 1767 "fromAccountNotSupportedByMethod": The _fromAccountId_ given 1768 corresponds to a valid account, but does not contain any mail data. 1770 "toAccountNotSupportedByMethod": The _toAccountId_ given corresponds 1771 to a valid account, but does not contain any mail data. 1773 4.9. Email/parse 1775 This method allows you to parse blobs as [RFC5322] messages to get 1776 Email objects (excluding the metadata properties). 1778 The _Email/parse_ method takes the following arguments: 1780 o *accountId*: "String|null" The id of the Account to use. If 1781 "null", the primary account is used. 1783 o *blobIds*: "String[]" The ids of the blobs to parse. 1785 o *properties*: "String[]" If supplied, only the properties listed 1786 in the array are returned for each Email object. If omitted, 1787 defaults to the same value as the Email/get "properties" default 1788 argument. 1790 o *bodyProperties*: "String[]" (optional) A list of properties to 1791 fetch for each EmailBodyPart returned. If omitted, defaults to 1792 the same value as the Email/get "bodyProperties" default argument. 1794 o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the 1795 _bodyValues_ property includes any "text/*" part in the "textBody" 1796 property. 1798 o *fetchHTMLBodyValues*: "Boolean" (default: "false") If "true", the 1799 _bodyValues_ property includes any "text/*" part in the "htmlBody" 1800 property. 1802 o *fetchAllBodyValues*: "Boolean" (default: "false") If "true", the 1803 _bodyValues_ property includes any "text/*" part in the 1804 "bodyStructure" property. 1806 o *maxBodyValueBytes*: "Number" (optional) If supplied by the 1807 client, the value MUST be a positive integer greater than 0. If a 1808 value outside of this range is given, the server MUST reject the 1809 call with an "invalidArguments" error. When given, the _value_ 1810 property of any EmailBodyValue object returned in _bodyValues_ 1811 MUST be truncated if necessary so it does not exceed this number 1812 of octets in size. The server MUST ensure the truncation results 1813 in valid UTF-8 and does not occur mid-codepoint. If the part is 1814 of type "text/html", the server SHOULD NOT truncate inside an HTML 1815 tag. 1817 The response has the following arguments: 1819 o *accountId*: "String" The id of the account used for the call. 1821 o *parsed*: "String[Email]|null" A map of blob id to parsed Email 1822 representation for each successfully parsed blob, or "null" if 1823 none. 1825 o *notParsable*: "String[]|null" A list of ids given that 1826 corresponded to blobs that could not be parsed as emails, or 1827 "null" if none. 1829 o *notFound*: "String[]|null" A list of blob ids given that could 1830 not be found, or "null" if none. 1832 As specified above, parsed forms of headers may only be used on 1833 appropriate header fields. Attempting to fetch a form that is 1834 forbidden (e.g. "header:From:asDate") MUST result in the method call 1835 being rejected with an "invalidArguments" error. 1837 Where a specific header is requested as a property, the 1838 capitalization of the property name in the response MUST be identical 1839 to that used in the request. 1841 5. Email submission 1843 An *EmailSubmission* object represents the submission of an email for 1844 delivery to one or more recipients. It has the following properties: 1846 o *id*: "String" (immutable; server-set) The id of the email 1847 submission. 1849 o *identityId*: "String" (immutable) The id of the identity to 1850 associate with this submission. 1852 o *emailId*: "String" (immutable) The id of the email to send. The 1853 email being sent does not have to be a draft, for example when 1854 "redirecting" an existing email to a different address. 1856 o *threadId*: "String" (immutable; server-set) The thread id of the 1857 email to send. This is set by the server to the _threadId_ 1858 property of the email referenced by the _emailId_. 1860 o *envelope*: "Envelope|null" (immutable; default: "null") 1861 Information for use when sending via SMTP. An *Envelope* object 1862 has the following properties: 1864 * *mailFrom*: "Address" The email address to use as the return 1865 address in the SMTP submission, plus any parameters to pass 1866 with the MAIL FROM address. The JMAP server MAY allow the 1867 address to be the empty string. When a JMAP server performs an 1868 SMTP message submission, it MAY use the same id string for the 1870 [RFC3461] ENVID parameter and the EmailSubmission object id. 1871 Servers that do this MAY replace a client-provided value for 1872 ENVID with a server-provided value. 1874 * *rcptTo*: "Address[]" The email addresses to send the message 1875 to, and any RCPT TO parameters to pass with the recipient. 1877 An *Address* object has the following properties: 1879 * *email*: "String" The email address being represented by the 1880 object. This as a "Mailbox" as used in the Reverse-path or 1881 Foward-path of the MAIL FROM or RCPT TO command in [RFC5321]. 1883 * *parameters*: "Object|null" Any parameters to send with the 1884 email (either mail-parameter or rcpt-parameter as appropriate, 1885 as specified in [RFC5321]). If supplied, each key in the 1886 object is a parameter name, and the value either the parameter 1887 value (type "String") or if the parameter does not take a value 1888 then "null". For both name and value, any xtext or unitext 1889 encodings are removed ([RFC3461], [RFC6533]) and JSON string 1890 encoding applied. 1892 If the _envelope_ property is "null" or omitted on creation, the 1893 server MUST generate this from the referenced email as follows: 1895 * *mailFrom*: The email in the _Sender_ header, if present, 1896 otherwise the _From_ header, if present, and no parameters. If 1897 multiple addresses are present in one of these headers, or 1898 there is more than one _Sender_/_From_ header, the server 1899 SHOULD reject the email as invalid but otherwise MUST take the 1900 first address in the last _Sender_/_From_ header in the 1901 [RFC5322] version of the message. If the address found from 1902 this is not allowed by the identity associated with this 1903 submission, the _email_ property from the identity MUST be used 1904 instead. 1906 * *rcptTo*: The deduplicated set of email addresses from the 1907 _To_, _Cc_ and _Bcc_ headers, if present, with no parameters 1908 for any of them. 1910 o *sendAt*: "UTCDate" (immutable; server-set) The date the email 1911 was/will be released for delivery. If the client successfully 1912 used [RFC4865] FUTURERELEASE with the email, this MUST be the time 1913 when the server will release the email; otherwise it MUST be the 1914 time the EmailSubmission was created. 1916 o *undoStatus*: "String" (server-set) This represents whether the 1917 submission may be canceled. This is server set and MUST be one of 1918 the following values: 1920 * "pending": It MAY be possible to cancel this submission. 1922 * "final": The email has been relayed to at least one recipient 1923 in a manner that cannot be recalled. It is no longer possible 1924 to cancel this submission. 1926 * "canceled": The email submission was canceled and will not be 1927 delivered to any recipient. 1929 On systems that do not support unsending, the value of this 1930 property will always be "final". On systems that do support 1931 canceling submission, it will start as "pending", and MAY 1932 transition to "final" when the server knows it definitely cannot 1933 recall the email, but MAY just remain "pending". If in pending 1934 state, a client can attempt to cancel the submission by setting 1935 this property to "canceled"; if the update succeeds, the 1936 submission was successfully canceled and the email has not been 1937 delivered to any of the original recipients. 1939 o *deliveryStatus*: "String[DeliveryStatus]|null" (server-set) This 1940 represents the delivery status for each of the email's recipients, 1941 if known. This property MAY not be supported by all servers, in 1942 which case it will remain "null". Servers that support it SHOULD 1943 update the EmailSubmission object each time the status of any of 1944 the recipients changes, even if some recipients are still being 1945 retried. This value is a map from the email address of each 1946 recipient to a _DeliveryStatus_ object. A *DeliveryStatus* object 1947 has the following properties: 1949 * *smtpReply*: "String" The SMTP reply string returned for this 1950 recipient when the server last tried to relay the email, or in 1951 a later DSN response for the email. This SHOULD be the 1952 response to the RCPT TO stage, unless this was accepted and the 1953 email as a whole rejected at the end of the DATA stage, in 1954 which case the DATA stage reply SHOULD be used instead. Multi- 1955 line SMTP responses should be concatenated to a single string 1956 as follows: 1958 + The hyphen following the SMTP code on all but the last line 1959 is replaced with a space. 1961 + Any prefix in common with the first line is stripped from 1962 lines after the first. 1964 + CRLF is replaced by a space. 1966 For example: 1968 550-5.7.1 Our system has detected that this message is 1969 550 5.7.1 likely spam, sorry. 1971 would become: 1973 550 5.7.1 Our system has detected that this message is likely spam, sorry. 1975 For emails relayed via an alternative to SMTP, the server MAY 1976 generate a synthetic string representing the status instead. 1977 If it does this, the string MUST be of the following form: 1979 + A 3-digit SMTP reply code, as defined in [RFC5321], section 1980 4.2.3. 1982 + Then a single space character. 1984 + Then an SMTP Enhanced Mail System Status Code as defined in 1985 [RFC3463], with a registry defined in [RFC5248]. 1987 + Then a single space character. 1989 + Then an implementation-specific information string with a 1990 human readable explanation of the response. 1992 * *delivered*: "String" Represents whether the email has been 1993 successfully delivered to the recipient. This MUST be one of 1994 the following values: 1996 + "queued": The email is in a local mail queue and status will 1997 change once it exits the local mail queues. The _smtpReply_ 1998 property may still change. 2000 + "yes": The email was successfully delivered to the mailbox 2001 of the recipient. The _smtpReply_ property is final. 2003 + "no": Delivery to the recipient permanently failed. The 2004 _smtpReply_ property is final. 2006 + "unknown": The final delivery status is unknown, (e.g. it 2007 was relayed to an external machine and no further 2008 information is available). The _smtpReply_ property may 2009 still change if a DSN arrives. 2011 Note, successful relaying to an external SMTP server SHOULD NOT 2012 be taken as an indication that the email has successfully 2013 reached the final mailbox. In this case though, the server MAY 2014 receive a DSN response, if requested. If a DSN is received for 2015 the recipient with Action equal to "delivered", as per 2016 [RFC3464] section 2.3.3, then the _delivered_ property SHOULD 2017 be set to "yes"; if the Action equals "failed", the property 2018 SHOULD be set to "no". Receipt of any other DSN SHOULD NOT 2019 affect this property. The server MAY also set this property 2020 based on other feedback channels. 2022 * *displayed*: "String" Represents whether the email has been 2023 displayed to the recipient. This MUST be one of the following 2024 values: 2026 + "unknown": The display status is unknown. This is the 2027 initial value. 2029 + "yes": The recipient's system claims the email content has 2030 been displayed to the recipient. Note, there is no 2031 guarantee that the recipient has noticed, read, or 2032 understood the content. 2034 If an MDN is received for this recipient with Disposition-Type 2035 (as per [RFC3798] section 3.2.6.2) equal to "displayed", this 2036 property SHOULD be set to "yes". The server MAY also set this 2037 property based on other feedback channels. 2039 o *dsnBlobIds*: "String[]" (server-set) A list of blob ids for DSNs 2040 received for this submission, in order of receipt, oldest first. 2042 o *mdnBlobIds*: "String[]" (server-set) A list of blob ids for MDNs 2043 received for this submission, in order of receipt, oldest first. 2045 JMAP servers MAY choose not to expose DSN and MDN responses as Email 2046 objects if they correlate to a EmailSubmission object. It SHOULD 2047 only do this if it exposes them in the _dsnBlobIds_ and _mdnblobIds_ 2048 fields instead, and expects the user to be using clients capable of 2049 fetching and displaying delivery status via the EmailSubmission 2050 object. 2052 For efficiency, a server MAY destroy EmailSubmission objects a 2053 certain amount of time after the email is successfully sent or it has 2054 finished retrying sending the email. For very basic SMTP proxies, 2055 this MAY be immediately after creation, as it has no way to assign a 2056 real id and return the information again if fetched later. 2058 The following JMAP methods are supported: 2060 5.1. EmailSubmission/get 2062 Standard _/get_ method. 2064 5.2. EmailSubmission/changes 2066 Standard _/changes_ method. 2068 5.3. EmailSubmission/query 2070 Standard _/query_ method. 2072 A *FilterCondition* object has the following properties, any of which 2073 may be omitted: 2075 o *emailIds*: "String[]" The EmailSubmission _emailId_ property must 2076 be in this list to match the condition. 2078 o *threadIds*: "String[]" The EmailSubmission _threadId_ property 2079 must be in this list to match the condition. 2081 o *undoStatus*: "String" The EmailSubmission _undoStatus_ property 2082 must be identical to the value given to match the condition. 2084 o *before*: "UTCDate" The _sendAt_ property of the EmailSubmission 2085 object must be before this date to match the condition. 2087 o *after*: "UTCDate" The _sendAt_ property of the EmailSubmission 2088 object must be after this date to match the condition. 2090 A EmailSubmission object matches the filter if and only if all of the 2091 given conditions given match. If zero properties are specified, it 2092 is automatically "true" for all objects. 2094 The following properties MUST be supported for sorting: 2096 o "emailId" 2098 o "threadId" 2100 o "sentAt" 2102 5.4. EmailSubmission/queryChanges 2104 Standard _/queryChanges_ method. 2106 5.5. EmailSubmission/set 2108 Standard _/set_ method, with the following two extra arguments: 2110 o *onSuccessUpdateEmail*: "String[Email]|null" A map of 2111 _EmailSubmission id_ to an object containing properties to update 2112 on the Email object referenced by the EmailSubmission if the 2113 create/update/destroy succeeds. (For references to 2114 EmailSubmission creations, this is equivalent to a back reference 2115 so the id will be the creation id prefixed with a "#".) 2117 o *onSuccessDestroyEmail*: "String[]|null" A list of 2118 _EmailSubmission ids_ for which the email with the corresponding 2119 emailId should be destroyed if the create/update/destroy succeeds. 2120 (For references to EmailSubmission creations, this is equivalent 2121 to a back reference so the id will be the creation id prefixed 2122 with a "#".) 2124 A single implicit _Email/set_ call MUST be made after all 2125 EmailSubmission create/update/destroy requests have been processed to 2126 perform any changes requested in these two arguments. The response 2127 to this MUST be returned after the _EmailSubmission/set_ response. 2129 An email is sent by creating a EmailSubmission object. When 2130 processing each create, the server must check that the email is 2131 valid, and the user has sufficient authorization to send it. If the 2132 creation succeeds, the email will be sent to the recipients given in 2133 the envelope _rcptTo_ parameter. The server MUST remove any _Bcc_ 2134 header present on the email during delivery. The server MAY add or 2135 remove other headers from the submitted email, or make further 2136 alterations in accordance with the server's policy during delivery. 2138 If the referenced email is destroyed at any point after the 2139 EmailSubmission object is created, this MUST NOT change the behaviour 2140 of the email submission (i.e. it does not cancel a future send). 2142 Similarly, destroying a EmailSubmission object MUST NOT affect the 2143 deliveries it represents. It purely removes the record of the email 2144 submission. The server MAY automatically destroy EmailSubmission 2145 objects after a certain time or in response to other triggers, and 2146 MAY forbid the client from manually destroying EmailSubmission 2147 objects. 2149 The following extra _SetError_ types are defined: 2151 For *create*: 2153 o "tooLarge" - The email size is larger than the server supports 2154 sending. A _maxSize_ "Number" property MUST be present on the 2155 SetError specifying the maximum size of an email that may be sent, 2156 in octets. 2158 o "tooManyRecipients" - The envelope (supplied or generated) has 2159 more recipients than the server allows. A _maxRecipients_ 2160 "Number" property MUST be present on the SetError specifying the 2161 maximum number of allowed recipients. 2163 o "noRecipients" - The envelope (supplied or generated) does not 2164 have any rcptTo emails. 2166 o "invalidRecipients" - The _rcptTo_ property of the envelope 2167 (supplied or generated) contains at least one rcptTo value which 2168 is not a valid email for sending to. An _invalidRecipients_ 2169 "String[]" property MUST be present on the SetError, which is a 2170 list of the invalid addresses. 2172 o "forbiddenFrom" - The server does not permit the user to send an 2173 email with the From header of the email to be sent. 2175 o "forbiddenToSend" - The user does not have permission to send at 2176 all right now for some reason. A _description_ "String" property 2177 MAY be present on the SetError object to display to the user why 2178 they are not permitted. The server MAY choose to localise this 2179 string into the user's preferred language, if known. 2181 o "emailNotFound" - The _emailId_ is not a valid id for an email in 2182 the account. 2184 o "invalidEmail" - The email to be sent is invalid in some way. The 2185 SetError SHOULD contain a property called _properties_ of type 2186 "String[]" that lists *all* the properties of the email that were 2187 invalid. 2189 For *update*: 2191 o "cannotUnsend": The client attempted to update the _undoStatus_ of 2192 a valid EmailSubmission object from "pending" to "canceled", but 2193 the email cannot be unsent. 2195 6. Identities 2197 An *Identity* object stores information about an email address (or 2198 domain) the user may send from. It has the following properties: 2200 o *id*: "String" (immutable; server-set) The id of the identity. 2202 o *name*: "String" (default: """") The "From" _name_ the client 2203 SHOULD use when creating a new message from this identity. 2205 o *email*: "String" The "From" email address the client MUST use 2206 when creating a new message from this identity. This property is 2207 immutable. The "email" property MAY alternatively be of the form 2208 "*@example.com", in which case the client may use any valid email 2209 address ending in "@example.com". 2211 o *replyTo*: "Emailer[]|null" (default: "null") The Reply-To value 2212 the client SHOULD set when creating a new message from this 2213 identity. 2215 o *bcc*: "Emailer[]|null" (default: "null") The Bcc value the client 2216 SHOULD set when creating a new message from this identity. 2218 o *textSignature*: "String" (default: """") Signature the client 2219 SHOULD insert into new plain-text messages that will be sent from 2220 this identity. Clients MAY ignore this and/or combine this with a 2221 client-specific signature preference. 2223 o *htmlSignature*: "String" (default: """") Signature the client 2224 SHOULD insert into new HTML messages that will be sent from this 2225 identity. This text MUST be an HTML snippet to be inserted into 2226 the "" section of the new email. Clients MAY ignore 2227 this and/or combine this with a client-specific signature 2228 preference. 2230 o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete 2231 this identity? Servers may wish to set this to "false" for the 2232 user's username or other default address. 2234 Multiple identities with the same email address MAY exist, to allow 2235 for different settings the user wants to pick between (for example 2236 with different names/signatures). 2238 The following JMAP methods are supported: 2240 6.1. Identity/get 2242 Standard _/get_ method. The _ids_ argument may be "null" to fetch 2243 all at once. 2245 6.2. Identity/changes 2247 Standard _/changes_ method. 2249 6.3. Identity/set 2251 Standard _/set_ method. The following extra _SetError_ types are 2252 defined: 2254 For *create*: 2256 o "maxQuotaReached": The user has reached a server-defined limit on 2257 the number of identities. 2259 o "emailNotPermitted": The user is not allowed to send from the 2260 address given as the _email_ property of the identity. 2262 For *destroy*: 2264 o "forbidden": Returned if the identity's _mayDelete_ value is 2265 "false". 2267 7. Search snippets 2269 When doing a search on a "String" property, the client may wish to 2270 show the relevant section of the body that matches the search as a 2271 preview instead of the beginning of the message, and to highlight any 2272 matching terms in both this and the subject of the email. Search 2273 snippets represent this data. 2275 A *SearchSnippet* object has the following properties: 2277 o *emailId*: "String" The email id the snippet applies to. 2279 o *subject*: "String|null" If text from the filter matches the 2280 subject, this is the subject of the email HTML-escaped, with 2281 matching words/phrases wrapped in "" tags. If it 2282 does not match, this is "null". 2284 o *preview*: "String|null" If text from the filter matches the 2285 plain-text or HTML body, this is the relevant section of the body 2286 (converted to plain text if originally HTML), HTML-escaped, with 2287 matching words/phrases wrapped in "" tags, up to 256 2288 characters long. If it does not match, this is "null". 2290 o *attachments*: "String|null" If text from the filter matches the 2291 text extracted from an attachment, this is the relevant section of 2292 the attachment (converted to plain text), with matching words/ 2293 phrases wrapped in "" tags, up to 256 characters 2294 long. If it does not match, this is "null". 2296 It is server-defined what is a relevant section of the body for 2297 preview. If the server is unable to determine search snippets, it 2298 MUST return "null" for both the _subject_, _preview_ and 2299 _attachments_ properties. 2301 Note, unlike most data types, a SearchSnippet DOES NOT have a 2302 property called "id". 2304 The following JMAP method is supported: 2306 7.1. SearchSnippet/get 2308 To fetch search snippets, make a call to "SearchSnippet/get". It 2309 takes the following arguments: 2311 o *accountId*: "String|null" The id of the account to use for this 2312 call. If "null", defaults to the primary account. 2314 o *emailIds*: "String[]" The list of ids of emails to fetch the 2315 snippets for. 2317 o *filter*: "FilterOperator|FilterCondition|null" The same filter as 2318 passed to Email/query; see the description of this method for 2319 details. 2321 The response has the following arguments: 2323 o *accountId*: "String" The id of the account used for the call. 2325 o *filter*: "FilterOperator|FilterCondition|null" Echoed back from 2326 the call. 2328 o *list*: "SearchSnippet[]" An array of SearchSnippet objects for 2329 the requested email ids. This may not be in the same order as the 2330 ids that were in the request. 2332 o *notFound*: "String[]|null" An array of email ids requested which 2333 could not be found, or "null" if all ids were found. 2335 Since snippets are only based on immutable properties, there is no 2336 state string or update mechanism needed. 2338 The following additional errors may be returned instead of the 2339 _searchSnippets_ response: 2341 "requestTooLarge": Returned if the number of _emailIds_ requested by 2342 the client exceeds the maximum number the server is willing to 2343 process in a single method call. 2345 "unsupportedFilter": Returned if the server is unable to process the 2346 given _filter_ for any reason. 2348 8. Vacation response 2350 The *VacationResponse* object represents the state of vacation- 2351 response related settings for an account. It has the following 2352 properties: 2354 o *id*: "String" (immutable) The id of the object. There is only 2355 ever one vacation response object, and its id is ""singleton"". 2357 o *isEnabled* "Boolean" Should a vacation response be sent if an 2358 email arrives between the _fromDate_ and _toDate_? 2360 o *fromDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time 2361 in UTC after which emails that arrive should receive the user's 2362 vacation response. If "null", the vacation response is effective 2363 immediately. 2365 o *toDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time 2366 in UTC after which emails that arrive should no longer receive the 2367 user's vacation response. If "null", the vacation response is 2368 effective indefinitely. 2370 o *subject*: "String|null" The subject that will be used by the 2371 message sent in response to emails when the vacation response is 2372 enabled. If null, an appropriate subject SHOULD be set by the 2373 server. 2375 o *textBody*: "String|null" The plain text part of the message to 2376 send in response to emails when the vacation response is enabled. 2377 If this is "null", when the vacation message is sent a plain-text 2378 body part SHOULD be generated from the _htmlBody_ but the server 2379 MAY choose to send the response as HTML only. 2381 o *htmlBody*: "String|null" The HTML message to send in response to 2382 emails when the vacation response is enabled. If this is "null", 2383 when the vacation message is sent an HTML body part MAY be 2384 generated from the _textBody_, or the server MAY choose to send 2385 the response as plain-text only. 2387 The following JMAP methods are supported: 2389 8.1. VacationResponse/get 2391 Standard _/get_ method. 2393 There MUST only be exactly one VacationResponse object in an account. 2394 It MUST have the id ""singleton"". 2396 8.2. VacationResponse/set 2398 Standard _/set_ method. 2400 9. Security considerations 2402 All security considerations of JMAP {TODO: insert RFC ref} apply to 2403 this specification. 2405 9.1. EmailBodyPart value 2407 Service providers typically perform security filtering on incoming 2408 email and it's important the detection of content-type and charset 2409 for the security filter aligns with the heuristics performed by JMAP 2410 servers. Servers that apply heuristics to determine the content-type 2411 or charset for _EmailBodyValue_ SHOULD document the heuristics and 2412 provide a mechanism to turn them off in the event they are misaligned 2413 with the security filter used at a particular mailbox host. 2415 Automatic conversion of charsets that allow hidden channels for ASCII 2416 text, such as UTF-7, have been problematic for security filters in 2417 the past so server implementations can mitigate this risk by having 2418 such conversions off-by-default and/or separately configurable. 2420 To allow the client to restrict the volume of data it can receive in 2421 response to a request, a maximum length may be requested for the data 2422 returned for a textual body part. However, truncating the data may 2423 change the semantic meaning, for example truncating a URL changes its 2424 location. Servers that scan for links to malicious sites should take 2425 care to either ensure truncation is not at a semantically significant 2426 point, or to rescan the truncated value for malicious content before 2427 returning it. 2429 10. References 2431 10.1. Normative References 2433 [RFC1870] Klensin, J., Freed, N., and K. Moore, "SMTP Service 2434 Extension for Message Size Declaration", STD 10, RFC 1870, 2435 DOI 10.17487/RFC1870, November 1995, 2436 . 2438 [RFC2045] Freed, N. and N. Borenstein, "Multipurpose Internet Mail 2439 Extensions (MIME) Part One: Format of Internet Message 2440 Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996, 2441 . 2443 [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions) 2444 Part Three: Message Header Extensions for Non-ASCII Text", 2445 RFC 2047, DOI 10.17487/RFC2047, November 1996, 2446 . 2448 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 2449 Requirement Levels", BCP 14, RFC 2119, 2450 DOI 10.17487/RFC2119, March 1997, 2451 . 2453 [RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and Encoded 2454 Word Extensions: Character Sets, Languages, and 2455 Continuations", RFC 2231, DOI 10.17487/RFC2231, November 2456 1997, . 2458 [RFC2369] Neufeld, G. and J. Baer, "The Use of URLs as Meta-Syntax 2459 for Core Mail List Commands and their Transport through 2460 Message Header Fields", RFC 2369, DOI 10.17487/RFC2369, 2461 July 1998, . 2463 [RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME 2464 Encapsulation of Aggregate Documents, such as HTML 2465 (MHTML)", RFC 2557, DOI 10.17487/RFC2557, March 1999, 2466 . 2468 [RFC2852] Newman, D., "Deliver By SMTP Service Extension", RFC 2852, 2469 DOI 10.17487/RFC2852, June 2000, 2470 . 2472 [RFC3282] Alvestrand, H., "Content Language Headers", RFC 3282, 2473 DOI 10.17487/RFC3282, May 2002, 2474 . 2476 [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: 2477 Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, 2478 . 2480 [RFC3461] Moore, K., "Simple Mail Transfer Protocol (SMTP) Service 2481 Extension for Delivery Status Notifications (DSNs)", 2482 RFC 3461, DOI 10.17487/RFC3461, January 2003, 2483 . 2485 [RFC3463] Vaudreuil, G., "Enhanced Mail System Status Codes", 2486 RFC 3463, DOI 10.17487/RFC3463, January 2003, 2487 . 2489 [RFC3464] Moore, K. and G. Vaudreuil, "An Extensible Message Format 2490 for Delivery Status Notifications", RFC 3464, 2491 DOI 10.17487/RFC3464, January 2003, 2492 . 2494 [RFC3798] Hansen, T., Ed. and G. Vaudreuil, Ed., "Message 2495 Disposition Notification", RFC 3798, DOI 10.17487/RFC3798, 2496 May 2004, . 2498 [RFC4865] White, G. and G. Vaudreuil, "SMTP Submission Service 2499 Extension for Future Message Release", RFC 4865, 2500 DOI 10.17487/RFC4865, May 2007, 2501 . 2503 [RFC5198] Klensin, J. and M. Padlipsky, "Unicode Format for Network 2504 Interchange", RFC 5198, DOI 10.17487/RFC5198, March 2008, 2505 . 2507 [RFC5248] Hansen, T. and J. Klensin, "A Registry for SMTP Enhanced 2508 Mail System Status Codes", BCP 138, RFC 5248, 2509 DOI 10.17487/RFC5248, June 2008, 2510 . 2512 [RFC5256] Crispin, M. and K. Murchison, "Internet Message Access 2513 Protocol - SORT and THREAD Extensions", RFC 5256, 2514 DOI 10.17487/RFC5256, June 2008, 2515 . 2517 [RFC5321] Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, 2518 DOI 10.17487/RFC5321, October 2008, 2519 . 2521 [RFC5322] Resnick, P., Ed., "Internet Message Format", RFC 5322, 2522 DOI 10.17487/RFC5322, October 2008, 2523 . 2525 [RFC5788] Melnikov, A. and D. Cridland, "IMAP4 Keyword Registry", 2526 RFC 5788, DOI 10.17487/RFC5788, March 2010, 2527 . 2529 [RFC6154] Leiba, B. and J. Nicolson, "IMAP LIST Extension for 2530 Special-Use Mailboxes", RFC 6154, DOI 10.17487/RFC6154, 2531 March 2011, . 2533 [RFC6409] Gellens, R. and J. Klensin, "Message Submission for Mail", 2534 STD 72, RFC 6409, DOI 10.17487/RFC6409, November 2011, 2535 . 2537 [RFC6532] Yang, A., Steele, S., and N. Freed, "Internationalized 2538 Email Headers", RFC 6532, DOI 10.17487/RFC6532, February 2539 2012, . 2541 [RFC6533] Hansen, T., Ed., Newman, C., and A. Melnikov, 2542 "Internationalized Delivery Status and Disposition 2543 Notifications", RFC 6533, DOI 10.17487/RFC6533, February 2544 2012, . 2546 [RFC6710] Melnikov, A. and K. Carlberg, "Simple Mail Transfer 2547 Protocol Extension for Message Transfer Priorities", 2548 RFC 6710, DOI 10.17487/RFC6710, August 2012, 2549 . 2551 [RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 2552 Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March 2553 2014, . 2555 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 2556 DOI 10.17487/RFC7493, March 2015, 2557 . 2559 10.2. URIs 2561 [1] TODO 2563 [2] server.html 2565 [3] https://www.iana.org/assignments/imap-keywords/imap- 2566 keywords.xhtml 2568 Author's Address 2570 Neil Jenkins 2571 FastMail 2572 Level 2, 114 William St 2573 Melbourne VIC 3000 2574 Australia 2576 Email: neilj@fastmailteam.com 2577 URI: https://www.fastmail.com