idnits 2.17.1 draft-ietf-jmap-mail-06.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 : ---------------------------------------------------------------------------- ** There are 7 instances of too long lines in the document, the longest one being 58 characters in excess of 72. == There are 2 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 (July 2, 2018) is 2118 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 3456 -- Looks like a reference, but probably isn't: '2' on line 3458 -- Looks like a reference, but probably isn't: '3' on line 3461 -- Looks like a reference, but probably isn't: '4' on line 3463 ** Obsolete normative reference: RFC 3798 (Obsoleted by RFC 8098) Summary: 2 errors (**), 0 flaws (~~), 2 warnings (==), 8 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) July 2, 2018 5 Intended status: Standards Track 6 Expires: January 3, 2019 8 JMAP for Mail 9 draft-ietf-jmap-mail-06 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 January 3, 2019. 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 data types . . . . . . . . . . . . . . . . . . . 4 53 1.3. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 54 1.4. Addition to the capabilities object . . . . . . . . . . . 4 55 1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 6 56 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 6 57 2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 9 58 2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 9 59 2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 10 60 2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 10 61 2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 10 62 2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 11 63 3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 64 3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 17 65 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 17 66 3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 17 67 4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 68 4.1. Properties of the Email object . . . . . . . . . . . . . 17 69 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 19 70 4.1.2. Header fields . . . . . . . . . . . . . . . . . . . . 20 71 4.1.3. Body parts . . . . . . . . . . . . . . . . . . . . . 26 72 4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 32 73 4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 34 74 4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 35 75 4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 36 76 4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 36 77 4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 38 78 4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 40 79 4.4.4. Response . . . . . . . . . . . . . . . . . . . . . . 40 80 4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 40 81 4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 40 82 4.7. Email/import . . . . . . . . . . . . . . . . . . . . . . 43 83 4.8. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 44 84 4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 46 85 5. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 48 86 5.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 49 87 5.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 49 88 5.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 49 89 5.4. Example . . . . . . . . . . . . . . . . . . . . . . . . . 49 90 6. Email submission . . . . . . . . . . . . . . . . . . . . . . 50 91 6.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 55 92 6.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 55 93 6.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 55 94 6.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 56 95 6.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 56 96 6.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 58 97 7. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 59 98 7.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 60 99 7.2. Example . . . . . . . . . . . . . . . . . . . . . . . . . 61 100 8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 62 101 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 63 102 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 63 103 9. Security considerations . . . . . . . . . . . . . . . . . . . 63 104 9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 63 105 9.2. HTML email display . . . . . . . . . . . . . . . . . . . 64 106 9.3. Email submission . . . . . . . . . . . . . . . . . . . . 66 107 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 67 108 10.1. JMAP Capability Registration for "mail" . . . . . . . . 67 109 10.2. IMAP and JMAP Keywords Registry . . . . . . . . . . . . 67 110 10.2.1. Registration of JMAP keyword '$draft' . . . . . . . 68 111 10.2.2. Registration of JMAP keyword '$seen' . . . . . . . . 69 112 10.2.3. Registration of JMAP keyword '$flagged' . . . . . . 69 113 10.2.4. Registration of JMAP keyword '$answered' . . . . . . 70 114 10.2.5. Registration of '$recent' Keyword . . . . . . . . . 71 115 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 72 116 11.1. Normative References . . . . . . . . . . . . . . . . . . 72 117 11.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 75 118 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 75 120 1. Introduction 122 JMAP is a 123 generic protocol for synchronising data, such as mail, calendars or 124 contacts, between a client and a server. It is optimised for mobile 125 and web environments, and aims to provide a consistent interface to 126 different data types. 128 This specification defines a data model for synchronising mail 129 between a client and a server using JMAP. 131 1.1. Notational conventions 133 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 134 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 135 document are to be interpreted as described in [RFC2119]. 137 Type signatures, examples and property descriptions in this document 138 follow the conventions established in Section 1.1 of 139 . 141 Object properties may also have a set of attributes defined along 142 with the type signature. These have the following meanings: 144 o *sever-set*: Only the server can set the value for this property. 145 The client MUST NOT send this property when creating a new object 146 of this type. 148 o *immutable*: The value MUST NOT change after the object is 149 created. 151 o *default*: (This is followed by a JSON value). The value that 152 will be used for this property if it is omitted in an argument, or 153 when creating a new object of this type. 155 1.2. The Date data types 157 Where "Date" is given as a type, it means a string in [RFC3339] 158 _date-time_ format. To ensure a normalised form, the _time-secfrac_ 159 MUST always be omitted and any letters in the string (e.g. "T" and 160 "Z") MUST be upper-case. For example, ""2014-10-30T14:12:00+08:00"". 162 Where "UTCDate" is given as a type, it means a "Date" where the 163 _time-offset_ component MUST be "Z" (i.e. it must be in UTC time). 164 For example, ""2014-10-30T06:12:00Z"". 166 1.3. Terminology 168 The same terminology is used in this document as in the core JMAP 169 specification. 171 1.4. Addition to the capabilities object 173 The capabilities object is returned as part of the standard JMAP 174 Session object; see the JMAP spec. Servers supporting _this_ 175 specification MUST add a property called "urn:ietf:params:jmap:mail" 176 to the capabilities object. The value of this property is an object 177 which MUST contain the following information on server capabilities: 179 o *maxMailboxesPerEmail*: "Number|null" The maximum number of 180 mailboxes that can be can assigned to a single email. This MUST 181 be an integer >= 1, or "null" for no limit (or rather, the limit 182 is always the number of mailboxes in the account). 184 o *maxSizeAttachmentsPerEmail*: "Number" The maximum total size of 185 attachments, in octets, allowed for a single email. A server MAY 186 still reject emails with a lower attachment size total (for 187 example, if the body includes several megabytes of text, causing 188 the size of the encoded MIME structure to be over some server- 189 defined limit). Note, this limit is for the sum of unencoded 190 attachment sizes. Users are generally not knowledgeable about 191 encoding overhead etc., nor should they need to be, so services 192 marketing and help materials normally tells them the "max size 193 attachments". This is the unencoded size they see on their hard 194 drive, and so this capability matches that and allows the client 195 to consistently enforce what the user understands as the limit. 196 The server may separately have a limit for the total size of the 197 RFC5322 message, which will have attachments Base64 encoded and 198 message headers and bodies too. For example, suppose the server 199 advertises "maxSizeAttachmentsPerEmail: 50000000" (50 MB). The 200 enforced server limit may be for an RFC5322 size of 70000000 201 octets (70 MB). Even with Base64 encoding and a 2 MB HTML body, 202 50 MB attachments would fit under this limit. 204 o *maxDelayedSend*: "Number" The number in seconds of the maximum 205 delay the server supports in sending (see the EmailSubmission 206 object). This is "0" if the server does not support delayed send. 208 o *emailsListSortOptions*: "String[]" A list of all the email 209 properties the server supports for sorting by. This MAY include 210 properties the client does not recognise (for example custom 211 properties specified in a vendor extension). Clients MUST ignore 212 any unknown properties in the list. 214 o *submissionExtensions*: "String[String[]]" A JMAP implementation 215 that talks to a Submission [RFC6409] server SHOULD have a 216 configuration setting that allows an administrator to expose a new 217 submission EHLO capability in this field. This allows a JMAP 218 server to gain access to a new submission extension without code 219 changes. By default, the JMAP server should show only known safe- 220 to-expose EHLO capabilities in this field, and hide EHLO 221 capabilities that are only relevant to the JMAP server. Each key 222 in the object is the _ehlo-name_, and the value is a list of 223 _ehlo-args_. Examples of safe-to-expose Submission extensions 224 include: 226 * FUTURERELEASE ([RFC4865]) 228 * SIZE ([RFC1870]) 230 * DSN ([RFC3461]) 232 * DELIVERYBY ([RFC2852]) 234 * MT-PRIORITY ([RFC6710]) 236 A JMAP server MAY advertise an extension and implement the 237 semantics of that extension locally on the JMAP server even if a 238 submission server used by JMAP doesn't implement it. The full 239 IANA registry of submission extensions can be found at 240 243 The server MUST also include the string "urn:ietf:params:jmap:mail" 244 in the _hasDataFor_ property of any account in which the user may use 245 the data types contained in this specification. 247 1.5. Push 249 Servers MUST support the standard JMAP push mechanisms to receive 250 notifications when the state changes for any of the types defined in 251 this specification. 253 In addition, servers MUST support a psuedo-type called 254 "EmailDelivery" in the push mechanisms. The state string for this 255 MUST change whenever a new Email is added to the store, but SHOULD 256 NOT change upon any other change to the Email objects. 258 Clients in battery constrained environments may wish to delay 259 fetching changes initiated by the user, but fetch new messages 260 immediately so they can notify the user. 262 2. Mailboxes 264 A mailbox represents a named set of emails. This is the primary 265 mechanism for organising emails within an account. It is analogous 266 to a folder or a label in other systems. A mailbox may perform a 267 certain role in the system; see below for more details. 269 For compatibility with IMAP, an email MUST belong to one or more 270 mailboxes. The email id does not change if the email changes 271 mailboxes. 273 A *Mailbox* object has the following properties: 275 o *id*: "String" (immutable; server-set) The id of the mailbox. 277 o *name*: "String" User-visible name for the mailbox, e.g. "Inbox". 278 This may be any Net-Unicode string ([RFC5198]) of at least 1 279 character in length and maximum 255 octets in size. Servers MUST 280 forbid sibling Mailboxes with the same name. Servers MAY reject 281 names that violate server policy (e.g., names containing slash (/) 282 or control characters). 284 o *parentId*: "String|null" (default: "null") The mailbox id for the 285 parent of this mailbox, or "null" if this mailbox is at the top 286 level. Mailboxes form acyclic graphs (forests) directed by the 287 child-to-parent relationship. There MUST NOT be a loop. 289 o *role*: "String|null" (default: "null") Identifies mailboxes that 290 have a particular common purpose (e.g. the "inbox"), regardless of 291 the _name_ (which may be localised). This value is shared with 292 IMAP (exposed in IMAP via the [RFC6154] SPECIAL-USE extension). 293 However, unlike in IMAP, a mailbox may only have a single role, 294 and no two mailboxes in the same account may have the same role. 295 The value MUST be one of the mailbox attribute names listed in the 296 IANA Mailbox Name Attributes Registry [1], as established in 297 [TODO:being established in EXTRA], converted to lower-case. New 298 roles may be established here in the future. An account is not 299 required to have mailboxes with any particular roles. 301 o *sortOrder*: "Number" (default: "0") Defines the sort order of 302 mailboxes when presented in the client's UI, so it is consistent 303 between devices. The number MUST be an integer in the range 0 <= 304 sortOrder < 2^31. A mailbox with a lower order should be 305 displayed before a mailbox with a higher order (that has the same 306 parent) in any mailbox listing in the client's UI. Mailboxes with 307 equal order SHOULD be sorted in alphabetical order by name. The 308 sorting SHOULD take into account locale-specific character order 309 convention. 311 o *totalEmails*: "Number" (server-set) The number of emails in this 312 mailbox. 314 o *unreadEmails*: "Number" (server-set) The number of emails in this 315 mailbox that have neither the "$seen" keyword nor the "$draft" 316 keyword. 318 o *totalThreads*: "Number" (server-set) The number of threads where 319 at least one email in the thread is in this mailbox. 321 o *unreadThreads*: "Number" (server-set) The number of threads where 322 at least one email in the thread has neither the "$seen" keyword 323 nor the "$draft" keyword AND at least one email in the thread is 324 in this mailbox (but see below for special case handling of 325 Trash). Note, the unread email does not need to be the one in 326 this mailbox. 328 o *myRights*: "MailboxRights" (server-set) The set of rights (ACLs) 329 the user has in relation to this mailbox. A _MailboxRights_ 330 object has the following properties: 332 * *mayReadItems*: "Boolean" If true, the user may use this 333 mailbox as part of a filter in a _Email/query_ call and the 334 mailbox may be included in the _mailboxIds_ set of _Email_ 335 objects. If a sub-mailbox is shared but not the parent 336 mailbox, this may be "false". Corresponds to IMAP ACLs "lr". 338 * *mayAddItems*: "Boolean" The user may add mail to this mailbox 339 (by either creating a new email or moving an existing one). 340 Corresponds to IMAP ACL "i". 342 * *mayRemoveItems*: "Boolean" The user may remove mail from this 343 mailbox (by either changing the mailboxes of an email or 344 deleting it). Corresponds to IMAP ACLs "te". 346 * *maySetSeen*: "Boolean" The user may add or remove the "$seen" 347 keyword to/from an email. If an email belongs to multiple 348 mailboxes, the user may only modify "$seen" if *all* of the 349 mailboxes have this permission. Corresponds to IMAP ACL "s". 351 * *maySetKeywords*: "Boolean" The user may add or remove any 352 keyword _other than_ "$seen" to/from an email. If an email 353 belongs to multiple mailboxes, the user may only modify 354 keywords if *all* of the mailboxes have this permission. 355 Corresponds to IMAP ACL "w". 357 * *mayCreateChild*: "Boolean" The user may create a mailbox with 358 this mailbox as its parent. Corresponds to IMAP ACL "k". 360 * *mayRename*: "Boolean" The user may rename the mailbox or make 361 it a child of another mailbox. Corresponds to IMAP ACL "x". 363 * *mayDelete*: "Boolean" The user may delete the mailbox itself. 364 Corresponds to IMAP ACL "x". 366 * *maySubmit*: "Boolean" Messages may be submitted directly to 367 this mailbox. Corresponds to IMAP ACL "p". 369 o *isSubscribed*: "Boolean" Has the user indicated they wish to see 370 this mailbox in their client? This SHOULD default to "false" for 371 mailboxes in shared accounts the user has access to, and "true" 372 for any new mailboxes created by the user themself. This MUST be 373 stored separately per-user where multiple users have access to a 374 shared mailbox. A user may have permission to access a large 375 number of shared accounts, or a shared account with a very large 376 set of mailboxes, but only be interested in the contents of a few 377 of these. Clients may choose only to display mailboxes to the 378 user that have the "isSubscribed" property set to "true", and 379 offer a separate UI to allow the user to see and subscribe/ 380 unsubscribe from the full set of mailboxes. However, clients MAY 381 choose to ignore this property, either entirely, for ease of 382 implementation, or just for the primary account (which is normally 383 the user's own, rather than a shared account). 385 The Trash mailbox (that is a mailbox with "role == "trash"") MUST be 386 treated specially for the purpose of unread counts: 388 1. Emails that are *only* in the Trash (and no other mailbox) are 389 ignored when calculating the "unreadThreads" count of other 390 mailboxes. 392 2. Emails that are *not* in the Trash are ignored when calculating 393 the "unreadThreads" count for the Trash mailbox. 395 The result of this is that emails in the Trash are treated as though 396 they are in a separate thread for the purposes of unread counts. It 397 is expected that clients will hide emails in the Trash when viewing a 398 thread in another mailbox and vice versa. This allows you to delete 399 a single email to the Trash out of a thread. 401 So for example, suppose you have an account where the entire contents 402 is a single conversation with 2 emails: an unread email in the Trash 403 and a read email in the Inbox. The "unreadThreads" count would be 404 "1" for the Trash and "0" for the Inbox. 406 For IMAP compatibility, an email in both the Trash and another 407 mailbox SHOULD be treated by the client as existing in both places 408 (i.e. when emptying the trash, the client SHOULD just remove the 409 Trash mailbox and leave it in the other mailbox). 411 The following JMAP methods are supported: 413 2.1. Mailbox/get 415 Standard _/get_ method. The _ids_ argument may be "null" to fetch 416 all at once. 418 2.2. Mailbox/changes 420 Standard _/changes_ method, but with one extra argument to the 421 response: 423 o *changedProperties*: "String[]|null" If only the mailbox counts 424 (unread/total emails/threads) have changed since the old state, 425 this will be the list of properties that may have changed, i.e. 426 "["totalEmails", "unreadEmails", "totalThreads", 427 "unreadThreads"]". If the server is unable to tell if only counts 428 have changed, it MUST just be "null". 430 Since counts frequently change but the rest of the mailboxes state 431 for most use cases changes rarely, the server can help the client 432 optimise data transfer by keeping track of changes to email/thread 433 counts separately to other state changes. The _changedProperties_ 434 array may be used directly via a result reference in a subsequent 435 Mailbox/get call in a single request. 437 2.3. Mailbox/query 439 Standard _/query_ method. 441 A *FilterCondition* object has the following properties, any of which 442 may be omitted: 444 o *parentId*: "String|null" The Mailbox _parentId_ property must 445 match the given value exactly. 447 o *hasRole*: "Boolean" If this is "true", a Mailbox matches if it 448 has a non-"null" value for its _role_ property. If "false", it 449 must has a "null" _role_ value to match. 451 o *isSubscribed*: "Boolean" The "isSubscribed" property of the 452 mailbox must be identical to the value given to match the 453 condition. 455 A Mailbox object matches the filter if and only if all of the given 456 conditions given match. If zero properties are specified, it is 457 automatically "true" for all objects. 459 The following properties MUST be supported for sorting: 461 o "sortOrder" 463 o "name" 465 o "parent/name": This is a pseudo-property, just for sorting, with 466 the following semantics: if two mailboxes have a common parent, 467 sort them by name. Otherwise, find the nearest ancestors of each 468 that share a common parent and sort by their names instead. (i.e. 469 This sorts the mailbox list in tree order). 471 2.4. Mailbox/queryChanges 473 Standard _/queryChanges_ method. 475 2.5. Mailbox/set 477 Standard _/set_ method, but with the following additional argument: 479 o *onDestroyRemoveMessages*: "Boolean" (default: "false") If 480 "false", attempts to destroy a mailbox that still has any messages 481 in it will be rejected with a "mailboxHasEmail" SetError. If 482 "true", any messages that were in the mailbox will be removed from 483 it, and if in no other mailboxes will be destroyed when the 484 mailbox is destroyed. 486 The following extra _SetError_ types are defined: 488 For *destroy*: 490 o "mailboxHasChild": The mailbox still has at least one child 491 mailbox. The client MUST remove these before it can delete the 492 parent mailbox. 494 o "mailboxHasEmail": The mailbox has at least one message assigned 495 to it and the _onDestroyRemoveMessages_ argument was "false". 497 2.6. Example 499 Fetching all mailboxes in an account: 501 [ 502 "Mailbox/get", 503 { 504 "accountId": "u33084183", 505 "ids": null 506 }, 507 "0" 508 ] 510 And response: 512 [ "Mailbox/get", 513 { 514 "accountId": "u33084183", 515 "state": "78540", 516 "list": [ 517 { 518 "id": "23cfa8094c0f41e6", 519 "name": "Inbox", 520 "parentId": null, 521 "role": "inbox", 522 "sortOrder": 10, 523 "totalEmails": 16307, 524 "unreadEmails": 13905, 525 "totalThreads": 5833, 526 "unreadThreads": 5128, 527 "myRights": { 528 "mayAddItems": true, 529 "mayRename": false, 530 "maySubmit": true, 531 "mayDelete": false, 532 "maySetKeywords": true, 533 "mayRemoveItems": true, 534 "mayCreateChild": true, 535 "maySetSeen": true, 536 "mayReadItems": true 537 }, 538 "isSubscribed": true 539 }, 540 { 541 "id": "674cc24095db49ce", 542 "name": "Important mail", 543 ... 544 } 545 ... 546 ], 547 "notFound": [] 548 }, 549 "0" 550 ] 552 Now suppose a message is marked read and we get a push update that 553 the Mailbox state has changed. You might fetch the updates like 554 this: 556 [ 557 "Mailbox/changes", 558 { 559 "accountId": "u33084183", 560 "sinceState": "78540" 561 }, 562 "0" 563 ], 564 [ 565 "Mailbox/get", 566 { 567 "accountId": "u33084183", 568 "#ids": { 569 "resultOf": "0", 570 "name": "Mailbox/changes", 571 "path": "/created" 572 } 573 }, 574 "1" 575 ], 576 [ 577 "Mailbox/get", 578 { 579 "accountId": "u33084183", 580 "#ids": { 581 "resultOf": "0", 582 "name": "Mailbox/changes", 583 "path": "/updated" 584 }, 585 "#properties": { 586 "resultOf": "0", 587 "name": "Mailbox/changes", 588 "path": "/changedProperties" 589 } 590 }, 591 "2" 592 ] 594 This fetches the list of ids for created/updated/destroyed mailboxes, 595 then using back references fetches the data for just the created/ 596 updated mailboxes in the same request. The response may look 597 something like this: 599 [ 600 "Mailbox/changes", 601 { 602 "accountId": "u33084183", 603 "oldState": "78541", 604 "newState": "78542", 605 "hasMoreChanges": false, 606 "changedProperties": [ 607 "totalEmails", "unreadEmails", 608 "totalThreads", "unreadThreads" 609 ], 610 "created": [], 611 "updated": ["23cfa8094c0f41e6"], 612 "destroyed": [] 613 }, 614 "0" 615 ], 616 ["Mailbox/get", { 617 "accountId": "u33084183", 618 "state": "78542", 619 "list": [], 620 "notFound": [] 621 }, "1"], 622 ["Mailbox/get", { 623 "accountId": "u33084183", 624 "state": "78542", 625 "list": [{ 626 "id": "23cfa8094c0f41e6", 627 "totalEmails": 16307, 628 "unreadEmails": 13903, 629 "totalThreads": 5833, 630 "unreadThreads": 5127 631 }], 632 "notFound": [] 633 }, "2"], 635 Here's an example where we try to rename one mailbox and destroy 636 another: 638 [ 639 "Mailbox/set", 640 { 641 "accountId": "u33084183", 642 "ifInState": "78542", 643 "update": { 644 "674cc24095db49ce": { 645 "name": "Maybe important mail" 646 } 647 }, 648 "destroy": [ "23cfa8094c0f41e6" ] 649 }, 650 "0" 651 ] 653 Suppose the rename succeeds, but we don't have permission to destroy 654 the mailbox we tried to destroy, we might get back: 656 [ 657 "Mailbox/set", 658 { 659 "accountId": "u33084183", 660 "oldState": "78542", 661 "newState": "78549", 662 "created": null, 663 "notCreated": null, 664 "updated": { 665 "674cc24095db49ce": null 666 }, 667 "notUpdated": null, 668 "destroyed": null, 669 "notDestroyed": { 670 "23cfa8094c0f41e6": { 671 "type": "forbidden" 672 } 673 } 674 }, 675 "0" 676 ] 678 3. Threads 680 Replies are grouped together with the original message to form a 681 thread. In JMAP, a thread is simply a flat list of emails, ordered 682 by date. Every email MUST belong to a thread, even if it is the only 683 email in the thread. 685 The exact algorithm for determining whether two emails belong to the 686 same thread is not mandated in this spec to allow for compatibility 687 with different existing systems. For new implementations, it is 688 suggested that two messages belong in the same thread if both of the 689 following conditions apply: 691 1. An identical RFC5322 message id appears in both messages in any 692 of the Message-Id, In-Reply-To and References headers. 694 2. After stripping automatically added prefixes such as "Fwd:", 695 "Re:", "[List-Tag]" etc. and ignoring whitespace, the subjects 696 are the same. This avoids the situation where a person replies 697 to an old message as a convenient way of finding the right 698 recipient to send to, but changes the subject and starts a new 699 conversation. 701 If emails are delivered out of order for some reason, a user may 702 receive two emails in the same thread but without headers that 703 associate them with each other. The arrival of a third email in the 704 thread may provide the missing references to join them all together 705 into a single thread. Since the _threadId_ of an email is immutable, 706 if the server wishes to merge the threads, it MUST handle this by 707 deleting and reinserting (with a new email id) the emails that change 708 threadId. 710 A *Thread* object has the following properties: 712 o *id*: "String" (immutable) The id of the thread. 714 o *emailIds*: "String[]" The ids of the emails in the thread, sorted 715 such that: 717 * Any email with the "$draft" keyword that has an "In-Reply-To" 718 header is sorted after the _first_ non-draft email in the 719 thread with the corresponding "Message-Id" header, but before 720 any subsequent non-draft emails. 722 * Other than that, everything is sorted by the _receivedAt_ date 723 of the email, oldest first. 725 * If two emails are identical under the above two conditions, the 726 sort is server-dependent but MUST be stable (sorting by id is 727 recommended). 729 The following JMAP methods are supported: 731 3.1. Thread/get 733 Standard _/get_ method. 735 3.1.1. Example 737 Request: 739 [ "Thread/get", { 740 "ids": ["f123u4", "f41u44"], 741 }, "#1" ] 743 with response: 745 [ "Thread/get", { 746 "accountId": "acme", 747 "state": "f6a7e214", 748 "list": [ 749 { 750 "id": "f123u4", 751 "emailIds": [ "eaa623", "f782cbb"] 752 }, 753 { 754 "id": "f41u44", 755 "emailIds": [ "82cf7bb" ] 756 } 757 ], 758 "notFound": [] 759 }, "#1" ] 761 3.2. Thread/changes 763 Standard _/changes_ method. 765 4. Emails 767 The *Email* object is a representation of an [RFC5322] message, which 768 allows clients to avoid the complexities of MIME parsing, transport 769 encoding and character encoding. 771 4.1. Properties of the Email object 773 Broadly, a message consists of two parts: a list of header fields, 774 then a body. The JMAP Email object provides a way to access the full 775 structure, or to use simplified properties and avoid some complexity 776 if this is sufficient for the client application. 778 While raw headers can be fetched and set, the vast majority of 779 clients should use an appropriate parsed form for each of the headers 780 it wants to process, as this allows it to avoid the complexities of 781 various encodings that are required in a valid RFC5322 message. 783 The body of a message is normally a MIME-encoded set of documents in 784 a tree structure. This may be arbitrarily nested, but the majority 785 of email clients present a flat model of an email body (normally 786 plain text or HTML), with a set of attachments. Flattening the MIME 787 structure to form this model can be difficult, and causes 788 inconsistency between clients. Therefore in addition to the 789 _bodyStructure_ property, which gives the full tree, the Email object 790 contains 3 alternate properties with flat lists of body parts: 792 o _textBody_/_htmlBody_: These provide a list of parts that should 793 be rendered sequentially as the "body" of the message. This is a 794 list rather than a single part as messages may have headers and/or 795 footers appended/prepended as separate parts as they are 796 transmitted, and some clients send text and images, or even videos 797 and sound clips, intended to be displayed inline in the body as 798 multiple parts rather than a single HTML part with referenced 799 images. 801 Because MIME allows for multiple representations of the same data 802 (using "multipart/alternative"), there is a textBody property (which 803 prefers a plain text representation) and an htmlBody property (which 804 prefers an HTML representation) to accommodate the two most common 805 client requirements. The same part may appear in both lists where 806 there is no alternative between the two. 808 o _attachments_: This provides a list of parts that should be 809 presented as "attachments" to the message. Some images may be 810 solely there for embedding within an HTML body part; clients may 811 wish to not present these as attachments in the user interface if 812 they are displaying the HTML with the embedded images directly. 813 Some parts may also be in htmlBody/textBody; again, clients may 814 wish to not present these as attachments in the user interface if 815 rendered as part of the body. 817 The _bodyValues_ property allows for clients to fetch the value of 818 text parts directly without having to do a second request for the 819 blob, and have the server handle decoding the charset into unicode. 820 This data is in a separate property rather than on the EmailBodyPart 821 object to avoid duplication of large amounts of data, as the same 822 part may be included twice if the client fetches more than one of 823 bodyStructure, textBody and htmlBody. 825 Due to the number of properties involved, the set of _Email_ 826 properties is specified over the following three sub-sections. 828 4.1.1. Metadata 830 These properties represent metadata about the [RFC5322] message, and 831 are not derived from parsing the message itself. 833 o *id*: "String" (immutable; server-set) The id of the Email object. 834 Note, this is the JMAP object id, NOT the [RFC5322] Message-ID 835 header field value. 837 o *blobId*: "String" (immutable; server-set) The id representing the 838 raw octets of the [RFC5322] message. This may be used to download 839 the raw original message, or to attach it directly to another 840 Email etc. 842 o *threadId*: "String" (immutable; server-set) The id of the Thread 843 to which this Email belongs. 845 o *mailboxIds*: "String[Boolean]" The set of mailbox ids this email 846 belongs to. An email MUST belong to one or more mailboxes at all 847 times (until it is deleted). The set is represented as an object, 848 with each key being a _Mailbox id_. The value for each key in the 849 object MUST be "true". 851 o *keywords*: "String[Boolean]" (default: "{}") A set of keywords 852 that apply to the email. The set is represented as an object, 853 with the keys being the _keywords_. The value for each key in the 854 object MUST be "true". Keywords are shared with IMAP. The six 855 system keywords from IMAP are treated specially. The following 856 four keywords have their first character changed from "\" in IMAP 857 to "$" in JMAP and have particular semantic meaning: 859 * "$draft": The email is a draft the user is composing. 861 * "$seen": The email has been read. 863 * "$flagged": The email has been flagged for urgent/special 864 attention. 866 * "$answered": The email has been replied to. 868 The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP 869 "\Deleted" keyword is also not present: IMAP uses a delete+expunge 870 model, which JMAP does not. Any message with the "\Deleted" 871 keyword MUST NOT be visible via JMAP. Users may add arbitrary 872 keywords to an email. For compatibility with IMAP, a keyword is a 873 case-insensitive string of 1-255 characters in the ASCII subset 874 %x21-%x7e (excludes control chars and space), and MUST NOT include 875 any of these characters: "( ) { ] % * " \" Because JSON is case- 876 sensitive, servers MUST return keywords in lower-case. The IANA 877 Keyword Registry [2] as established in [RFC5788] assigns semantic 878 meaning to some other keywords in common use. New keywords may be 879 established here in the future. In particular, note: 881 * "$forwarded": The email has been forwarded. 883 * "$phishing": The email is highly likely to be phishing. 884 Clients SHOULD warn users to take care when viewing this email 885 and disable links and attachments. 887 * "$junk": The email is definitely spam. Clients SHOULD set this 888 flag when users report spam to help train automated spam- 889 detection systems. 891 * "$notjunk": The email is definitely not spam. Clients SHOULD 892 set this flag when users indicate an email is legitimate, to 893 help train automated spam-detection systems. 895 o *size*: "Number" (immutable; server-set) The size, in octets, of 896 the raw data for the [RFC5322] message (as referenced by the 897 _blobId_, i.e. the number of octets in the file the user would 898 download). 900 o *receivedAt*: "UTCDate" (immutable; default: time of creation on 901 server) The date the email was received by the message store. 902 This is the _internal date_ in IMAP. 904 4.1.2. Header fields 906 These properties are derived from the [RFC5322] and [RFC6532] message 907 header fields. All header fields may be fetched in a raw form. Some 908 headers may also be fetched in a parsed form. The structured form 909 that may be fetched depends on the header. The following forms are 910 defined: 912 o *Raw* ("String") The raw octets of the header field value from the 913 first octet following the header field name terminating colon, up 914 to but excluding the header field terminating CRLF. Any 915 standards-compliant message MUST be either ASCII (RFC5322) or 916 UTF-8 (RFC6532), however other encodings exist in the wild. A 917 server MAY use heuristics to determine a charset and decode the 918 octets, or MAY replace any octet or octet run with the high bit 919 set that violates UTF-8 syntax with the unicode replacement 920 character (U+FFFD). Any NUL octet MUST be dropped. 922 o *Text* ("String") The header field value with: 924 1. White space unfolded (as defined in [RFC5322] section 2.2.3) 926 2. The terminating CRLF at the end of the value removed 928 3. Any SP characters at the beginning of the value removed 930 4. Any syntactically correct [RFC2047] encoded sections with a 931 known character set decoded. Any [RFC2047] encoded NUL octets 932 or control characters are dropped from the decoded value. Any 933 text that looks like [RFC2047] syntax but violates [RFC2047] 934 placement or whitespace rules MUST NOT be decoded. 936 5. Any [RFC6532] UTF-8 values decoded. 938 6. The resulting unicode converted to NFC form. 940 If any decodings fail, the parser SHOULD insert a unicode 941 replacement character (U+FFFD) and attempt to continue as much as 942 possible. To prevent obviously nonsense behaviour, which can lead 943 to interoperability issues, this form may only be fetched or set 944 for the following header fields: 946 * Subject 948 * Comment 950 * List-Id 952 * Any header not defined in [RFC5322] or [RFC2369] 954 o *Addresses* ("EmailAddress[]") The header is parsed as an 955 "address-list" value, as specified in [RFC5322] section 3.4, into 956 the "EmailAddress[]" type. The *EmailAddress* object has the 957 following properties: 959 * *name*: "String|null" The _display-name_ of the [RFC5322] 960 _mailbox_ or _group_, or "null" if none. If this is a _quoted- 961 string_: 963 1. The surrounding DQUOTE characters are removed. 965 2. Any _quoted-pair_ is decoded. 967 3. White-space is unfolded, and then any leading or trailing 968 white-space is removed. 970 * *email*: "String|null" The _addr-spec_ of the [RFC5322] 971 _mailbox_, or "null" if a _group_. 973 Any syntactically correct [RFC2047] encoded sections with a known 974 encoding MUST be decoded, following the same rules as for the 975 _Text_ form. Any [RFC6532] UTF-8 values MUST be decoded. Parsing 976 SHOULD be best-effort in the face of invalid structure to 977 accommodate invalid messages and semi-complete drafts. 978 EmailAddress objects MAY have an _email_ property that does not 979 conform to the _addr-spec_ form (for example, may not contain an @ 980 symbol). To prevent obviously nonsense behaviour, which can lead 981 to interoperability issues, this form may only be fetched or set 982 for the following header fields: 984 * From 986 * Sender 988 * Reply-To 990 * To 992 * Cc 994 * Bcc 996 * Resent-From 998 * Resent-Sender 1000 * Resent-Reply-To 1002 * Resent-To 1004 * Resent-Cc 1006 * Resent-Bcc 1008 * Any header not defined in [RFC5322] or [RFC2369] 1010 o *MessageIds* ("String[]|null") The header is parsed as a list of 1011 "msg-id" values, as specified in [RFC5322] section 3.6.4, into the 1012 "String[]" type. CFWS and surrounding angle brackets ("<>") are 1013 removed. If parsing fails, the value is "null". To prevent 1014 obviously nonsense behaviour, which can lead to interoperability 1015 issues, this form may only be fetched or set for the following 1016 header fields: 1018 * Message-ID 1020 * In-Reply-To 1022 * References 1024 * Resent-Message-ID 1026 * Any header not defined in [RFC5322] or [RFC2369] 1028 o *Date* ("Date|null") The header is parsed as a "date-time" value, 1029 as specified in [RFC5322] section 3.3, into the "Date" type. If 1030 parsing fails, the value is "null". To prevent obviously nonsense 1031 behaviour, which can lead to interoperability issues, this form 1032 may only be fetched or set for the following header fields: 1034 * Date 1036 * Resent-Date 1038 * Any header not defined in [RFC5322] or [RFC2369] 1040 o *URLs* ("String[]|null") The header is parsed as a list of URLs, 1041 as described in [RFC2369], into the "String[]" type. Values do 1042 not include the surrounding angle brackets or any comments in the 1043 header with the URLs. If parsing fails, the value is "null". To 1044 prevent obviously nonsense behaviour, which can lead to 1045 interoperability issues, this form may only be fetched or set for 1046 the following header fields: 1048 * List-Help 1050 * List-Unsubscribe 1052 * List-Subscribe 1054 * List-Post 1056 * List-Owner 1058 * List-Archive 1060 * Any header not defined in [RFC5322] or [RFC2369] 1062 The following low-level *Email* property is specified for complete 1063 access to the header data of the message: 1065 o *headers*: "EmailHeader[]" (immutable) This is a list of all 1066 [RFC5322] header fields, in the same order they appear in the 1067 message. An *EmailHeader* object has the following properties: 1069 * *name*: "String" The header _field name_ as defined in 1070 [RFC5322], with the same capitalization that it has in the 1071 message. 1073 * *value*: "String" The header _field value_ as defined in 1074 [RFC5322], in _Raw_ form. 1076 In addition, the client may request/send properties representing 1077 individual header fields of the form: 1079 header:{header-field-name} 1081 Where "{header-field-name}" means any series of one or more printable 1082 ASCII characters (i.e. characters that have values between 33 and 1083 126, inclusive), except colon. The property may also have the 1084 following suffixes: 1086 o *:as{header-form}* This means the value is in a parsed form, where 1087 "{header-form}" is one of the parsed-form names specified above. 1088 If not given, the value is in _Raw_ form. 1090 o *:all* This means the value is an array, with the items 1091 corresponding to each instance of the header field, in the order 1092 they appear in the message. If this suffix is not used, the 1093 result is the value of the *last* instance of the header field 1094 (i.e. identical to the *last* item in the array if :all is used), 1095 or "null" if none. 1097 If both suffixes are used, they MUST be specified in the order above. 1098 Header field names are matched case-insensitively. The value is 1099 typed according to the requested form, or an array of that type if 1100 :all is used. If no header fields exist in the message with the 1101 requested name, the value is "null" if fetching a single instance, or 1102 the empty array if requesting :all. 1104 As a simple example, if the client requests a property called 1105 "header:subject", this means find the _last_ header field in the 1106 message named "subject" (matched case-insensitively) and return the 1107 value in _Raw_ form, or "null" if no header of this name is found. 1109 For a more complex example, consider the client requesting a property 1110 called "header:Resent-To:asAddresses:all". This means: 1112 1. Find _all_ header fields named Resent-To (matched case- 1113 insensitively). 1115 2. For each instance parse the header field value in the _Addresses_ 1116 form. 1118 3. The result is of type "EmailAddress[][]" - each item in the array 1119 corresponds to the parsed value (which is itself an array) of the 1120 Resent-To header field instance. 1122 The following convenience properties are also specified for the 1123 *Email* object: 1125 o *messageId*: "String[]|null" (immutable) The value is identical to 1126 the value of _header:Message-ID:asMessageIds_. For messages 1127 conforming to RFC5322 this will be an array with a single entry. 1129 o *inReplyTo*: "String[]|null" (immutable) The value is identical to 1130 the value of _header:In-Reply-To:asMessageIds_. 1132 o *references*: "String[]|null" (immutable) The value is identical 1133 to the value of _header:References:asMessageIds_. 1135 o *sender*: "EmailAddress[]|null" (immutable) The value is identical 1136 to the value of _header:Sender:asAddresses_. 1138 o *from*: "EmailAddress[]|null" (immutable) The value is identical 1139 to the value of _header:From:asAddresses_. 1141 o *to*: "EmailAddress[]|null" (immutable) The value is identical to 1142 the value of _header:To:asAddresses_. 1144 o *cc*: "EmailAddress[]|null" (immutable) The value is identical to 1145 the value of _header:Cc:asAddresses_. 1147 o *bcc*: "EmailAddress[]|null" (immutable) The value is identical to 1148 the value of _header:Bcc:asAddresses_. 1150 o *replyTo*: "EmailAddress[]|null" (immutable) The value is 1151 identical to the value of _header:Reply-To:asAddresses_. 1153 o *subject*: "String|null" (immutable) The value is identical to the 1154 value of _header:Subject:asText_. 1156 o *sentAt*: "Date|null" (immutable; default on creation: current 1157 server time) The value is identical to the value of 1158 _header:Date:asDate_. 1160 4.1.3. Body parts 1162 These properties are derived from the [RFC5322] message body and its 1163 [RFC2045] MIME entities. 1165 A *EmailBodyPart* object has the following properties: 1167 o *partId*: "String|null" Identifies this part uniquely within the 1168 Email. This is scoped to the _emailId_ and has no meaning outside 1169 of the JMAP Email object representation. This is "null" if, and 1170 only if, the part is of type "multipart/*". 1172 o *blobId*: "String|null" The id representing the raw octets of the 1173 contents of the part after decoding any _Content-Transfer- 1174 Encoding_ (as defined in [RFC2045]), or "null" if, and only if, 1175 the part is of type "multipart/*". Note, two parts may be 1176 transfer-encoded differently but have same the same blob id if 1177 their decoded octets are identical and the server is using a 1178 secure hash of the data for the blob id. 1180 o *size*: "Number" The size, in octets, of the raw data after 1181 content transfer decoding (as referenced by the _blobId_, i.e. the 1182 number of octets in the file the user would download). 1184 o *headers*: "EmailHeader[]" This is a list of all header fields in 1185 the part, in the order they appear. The values are in _Raw_ form. 1187 o *name*: "String|null" This is the [RFC2231] decoded _filename_ 1188 parameter of the _Content-Disposition_ header field, or (for 1189 compatibility with existing systems) if not present then the 1190 [RFC2047] decoded _name_ parameter of the _Content-Type_ header 1191 field. 1193 o *type*: "String" The value of the _Content-Type_ header field of 1194 the part, if present, otherwise the implicit type as per the MIME 1195 standard ("text/plain", or "message/rfc822" if inside a 1196 "multipart/digest"). CFWS is removed and any parameters are 1197 stripped. 1199 o *charset*: "String|null" The value of the charset parameter of the 1200 _Content-Type_ header field, if present, or "null" if the header 1201 field is present but has no charset parameter. If there is no 1202 _Content-Type_ header field, this is the implicit charset as per 1203 the MIME standard ("us-ascii"). 1205 o *disposition*: "String|null" The value of the _Content- 1206 Disposition_ header field of the part, if present, otherwise 1207 "null". CFWS is removed and any parameters are stripped. 1209 o *cid*: "String|null" The value of the _Content-Id_ header field of 1210 the part, if present, otherwise "null". CFWS and surrounding 1211 angle brackets ("<>") are removed. This may be used to reference 1212 the content from within an html body part using the "cid:" 1213 protocol. 1215 o *language*: "String[]|null" The list of language tags, as defined 1216 in [RFC3282], in the _Content-Language_ header field of the part, 1217 if present. 1219 o *location*: "String|null" The URI, as defined in [RFC2557], in the 1220 _Content-Location_ header field of the part, if present. 1222 o *subParts*: "EmailBodyPart[]" (optional) If type is "multipart/*", 1223 this contains the body parts of each child. 1225 In addition, the client may request/send EmailBodyPart properties 1226 representing individual header fields, following the same syntax and 1227 semantics as for the Email object, e.g. "header:Content-Type". 1229 The following *Email* properties are specified for access to the body 1230 data of the message: 1232 o *bodyStructure*: "EmailBodyPart" (immutable) This is the full MIME 1233 structure of the message body, represented as an array of the 1234 message's top-level MIME parts, without recursing into "message/ 1235 rfc822" or "message/global" parts. Note that EmailBodyParts may 1236 have subParts if they are of type "multipart/*". 1238 o *bodyValues*: "String[EmailBodyValue]" (immutable) This is a map 1239 of _partId_ to an *EmailBodyValue* object for none, some or all 1240 "text/*" parts. Which parts are included and whether the value is 1241 truncated is determined by various arguments to _Email/get_ and 1242 _Email/parse_. An *EmailBodyValue* object has the following 1243 properties: 1245 * *value*: "String" The value of the body part after decoding 1246 _Content-Transport-Encoding_ and decoding the _Content-Type_ 1247 charset, if known to the server, and with any CRLF replaced 1248 with a single LF. The server MAY use heuristics to determine 1249 the charset to use for decoding if the charset is unknown, or 1250 if no charset is given, or if it believes the charset given is 1251 incorrect. Decoding is best-effort and SHOULD insert the 1252 unicode replacement character (U+FFFD) and continue when a 1253 malformed section is encountered. Note that due to the charset 1254 decoding and line ending normalisation, the length of this 1255 string will probably not be exactly the same as the _size_ 1256 property on the corresponding EmailBodyPart. 1258 * *isEncodingProblem*: "Boolean" (default: "false") This is 1259 "true" if malformed sections were found while decoding the 1260 charset, or the charset was unknown. 1262 * *isTruncated*: "Boolean" (default: "false") This is "true" if 1263 the _value_ has been truncated. 1265 See the security considerations section for issues related to 1266 truncation and heuristic determination of content-type and 1267 charset. 1269 o *textBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", 1270 "text/html", "image/*", "audio/*" and/or "video/*" parts to 1271 display (sequentially) as the message body, with a preference for 1272 "text/plain" when alternative versions are available. 1274 o *htmlBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", 1275 "text/html", "image/*", "audio/*" and/or "video/*" parts to 1276 display (sequentially) as the message body, with a preference for 1277 "text/html" when alternative versions are available. 1279 o *attachments*: "EmailBodyPart[]" (immutable) A list of all parts 1280 in _bodyStructure_, traversing depth-first, which satisfy either 1281 of the following conditions: 1283 * not of type "multipart/*" and not included in _textBody_ or 1284 _htmlBody_ 1286 * of type "image/*", "audio/*" or "video/*" and not in both 1287 _textBody_ and _htmlBody_ 1289 None of these parts include subParts, including "message/*" types. 1290 Attached messages may be fetched using the Email/parse method and 1291 the blobId. Note, an HTML body part may reference image parts in 1292 attachments using "cid:" links to reference the _Content-Id_ or by 1293 referencing the _Content-Location_. 1295 o *hasAttachment*: "Boolean" (immutable; server-set) This is "true" 1296 if there are one or more parts in the message that a client UI 1297 should offer as downloadable. A server SHOULD set hasAttachment 1298 if either: 1300 * The _attachments_ list contains at least one item that does not 1301 have "Content-Disposition: inline". The server MAY ignore 1302 parts in this list that are processed automatically in some 1303 way, or are referenced as embedded images in one of the "text/ 1304 html" parts of the message. 1306 The server MAY set hasAttachment based on implementation-defined 1307 or site configurable heuristics. 1309 o *preview*: "String" (immutable; server-set) Up to 255 octets of 1310 plain text, summarising the message body. This is intended to be 1311 shown as a preview line on a mailbox listing, and may be truncated 1312 when shown. The server may choose which part of the message to 1313 include in the preview, for example skipping quoted sections and 1314 salutations and collapsing white-space can result in a more useful 1315 preview. 1317 The exact algorithm for decomposing bodyStructure into textBody, 1318 htmlBody and attachments part lists is not mandated, as this is a 1319 quality-of-service implementation issue and likely to require 1320 workarounds for malformed content discovered over time. However, the 1321 following algorithm (expressed here in JavaScript) is suggested as a 1322 starting point, based on real-world experience: 1324 function isInlineMediaType ( type ) { 1325 return type.startsWith( 'image/' ) || 1326 type.startsWith( 'audio/' ) || 1327 type.startsWith( 'video/' ); 1328 } 1330 function parseStructure ( parts, multipartType, inAlternative, 1331 htmlBody, textBody, attachments ) { 1333 // For multipartType == alternative 1334 let textLength = textBody ? textBody.length : -1; 1335 let htmlLength = htmlBody ? htmlBody.length : -1; 1337 for ( let i = 0; i < parts.length; i += 1 ) { 1338 let part = parts[i]; 1339 let isMultipart = part.type.startsWith( 'multipart/' ); 1340 // Is this a body part rather than an attachment 1341 let isInline = part.disposition != "attachment" && 1342 // Must be one of the allowed body types 1343 ( part.type == "text/plain" || 1344 part.type == "text/html" || 1345 isInlineMediaType( part.type ) ) && 1346 // If multipart/related, only the first part can be inline 1347 // If a text part with a filename, and not the first item in the 1348 // multipart, assume it is an attachment 1349 ( i === 0 || 1350 ( multipartType != "related" && 1351 ( isInlineMediaType( part.type ) || !part.name ) ) ); 1353 if ( isMultipart ) { 1354 let subMultiType = part.type.split( '/' )[1]; 1355 parseStructure( part.subParts, subMultiType, 1356 inAlternative || ( subMultiType == 'alternative' ), 1357 htmlBody, textBody, attachments ); 1358 } else if ( isInline ) { 1359 if ( multipartType == 'alternative' ) { 1360 switch ( part.type ) { 1361 case 'text/plain': 1362 textBody.push( part ); 1363 break; 1364 case 'text/html': 1365 htmlBody.push( part ); 1366 break; 1367 default: 1368 attachments.push( part ); 1369 break; 1370 } 1371 continue; 1372 } else if ( inAlternative ) { 1373 if ( part.type == 'text/plain' ) { 1374 htmlBody = null; 1375 } 1376 if ( part.type == 'text/html' ) { 1377 textBody = null; 1378 } 1379 } 1380 if ( textBody ) { 1381 textBody.push( part ); 1382 } 1383 if ( htmlBody ) { 1384 htmlBody.push( part ); 1385 } 1386 if ( ( !textBody || !htmlBody ) && 1387 isInlineMediaType( part.type ) ) { 1388 attachments.push( part ); 1389 } 1390 } else { 1391 attachments.push( part ); 1392 } 1393 } 1395 if ( multipartType == 'alternative' && textBody && htmlBody ) { 1396 // Found HTML part only 1397 if ( textLength == textBody.length && 1398 htmlLength != htmlBody.length ) { 1399 for ( let i = htmlLength; i < htmlBody.length; i += 1 ) { 1400 textBody.push( htmlBody[i] ); 1401 } 1403 } 1404 // Found plain text part only 1405 if ( htmlLength == htmlBody.length && 1406 textLength != textBody.length ) { 1407 for ( let i = textLength; i < textBody.length; i += 1 ) { 1408 htmlBody.push( textBody[i] ); 1409 } 1410 } 1411 } 1412 } 1414 // Usage: 1415 let htmlBody = []; 1416 let textBody = []; 1417 let attachments = []; 1419 parseStructure( [ bodyStructure ], 'mixed', false, 1420 htmlBody, textBody, attachments ); 1422 For instance, consider a message with both text and html versions 1423 that's then gone through a list software manager that attaches a 1424 header/footer. It might have a MIME structure something like: 1426 multipart/mixed 1427 text/plain, content-disposition=inline - A 1428 multipart/mixed 1429 multipart/alternative 1430 multipart/mixed 1431 text/plain, content-disposition=inline - B 1432 image/jpeg, content-disposition=inline - C 1433 text/plain, content-disposition=inline - D 1434 multipart/related 1435 text/html - E 1436 image/jpeg - F 1437 image/jpeg, content-disposition=attachment - G 1438 application/x-excel - H 1439 message/rfc822 - J 1440 text/plain, content-disposition=inline - K 1442 In this case, the above algorithm would decompose this to: 1444 textBody => [ A, B, C, D, K ] 1445 htmlBody => [ A, E, K ] 1446 attachments => [ C, F, G, H, J ] 1448 4.2. Email/get 1450 Standard _/get_ method, with the following additional arguments: 1452 o *bodyProperties*: "String[]" (optional) A list of properties to 1453 fetch for each EmailBodyPart returned. If omitted, this defaults 1454 to: [ "partId", "blobId", "size", "name", "type", "charset", 1455 "disposition", cid", "language", "location" ] 1457 o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the 1458 _bodyValues_ property includes any "text/*" part in the "textBody" 1459 property. 1461 o *fetchHTMLBodyValues*: "Boolean" (default: "false") If "true", the 1462 _bodyValues_ property includes any "text/*" part in the "htmlBody" 1463 property. 1465 o *fetchAllBodyValues*: "Boolean" (default: "false") If "true", the 1466 _bodyValues_ property includes any "text/*" part in the 1467 "bodyStructure" property. 1469 o *maxBodyValueBytes*: "Number" (optional) If supplied by the 1470 client, the value MUST be a positive integer greater than 0. If a 1471 value outside of this range is given, the server MUST reject the 1472 call with an "invalidArguments" error. When given, the _value_ 1473 property of any EmailBodyValue object returned in _bodyValues_ 1474 MUST be truncated if necessary so it does not exceed this number 1475 of octets in size. The server MUST ensure the truncation results 1476 in valid UTF-8 and does not occur mid-codepoint. If the part is 1477 of type "text/html", the server SHOULD NOT truncate inside an HTML 1478 tag e.g. in the middle of "". There 1479 is no requirement for the truncated form to be a balanced tree or 1480 valid HTML (indeed, the original source may well be neither of 1481 these things). 1483 If the standard _properties_ argument is omitted or "null", the 1484 following default MUST be used instead of "all" properties: 1486 [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size", 1487 "receivedAt", "messageId", "inReplyTo", "references", "sender", "from", 1488 "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", 1489 "preview", "bodyValues", "textBody", "htmlBody", "attachments" ] 1491 The following properties are expected to be fast to fetch in a 1492 quality implementation: 1494 o id 1495 o blobId 1497 o threadId 1499 o mailboxIds 1501 o keywords 1503 o size 1505 o receivedAt 1507 o messageId 1509 o inReplyTo 1511 o sender 1513 o from 1515 o to 1517 o cc 1519 o bcc 1521 o replyTo 1523 o subject 1525 o sentAt 1527 o hasAttachment 1529 o preview 1531 Clients SHOULD take care when fetching any other properties, as there 1532 may be significantly longer latency in fetching and returning the 1533 data. 1535 As specified above, parsed forms of headers may only be used on 1536 appropriate header fields. Attempting to fetch a form that is 1537 forbidden (e.g. "header:From:asDate") MUST result in the method call 1538 being rejected with an "invalidArguments" error. 1540 Where a specific header is requested as a property, the 1541 capitalization of the property name in the response MUST be identical 1542 to that used in the request. 1544 4.2.1. Example 1546 Request: 1548 ["Email/get", { 1549 "ids": [ "f123u456", "f123u457" ], 1550 "properties": [ "threadId", "mailboxIds", "from", "subject", "receivedAt", "header:List-POST:asURLs" "htmlBody", "bodyValues" ], 1551 "bodyProperties": [ "partId", "blobId", "size", "type" ], 1552 "fetchHTMLBodyValues": true, 1553 "maxBodyValueBytes": 256 1554 }, "#1"] 1556 and response: 1558 ["Email/get", { 1559 "accountId": "abc", 1560 "state": "41234123231", 1561 "list": [ 1562 { 1563 "id": "f123u457", 1564 "threadId": "ef1314a", 1565 "mailboxIds": { "f123": true }, 1566 "from": [{name: "Joe Bloggs", email: "joe@bloggs.com"}], 1567 "subject": "Dinner on Thursday?", 1568 "receivedAt": "2013-10-13T14:12:00Z", 1569 "header:List-POST:asURLs": [ "mailto:partytime@lists.example.com" ], 1570 "htmlBody": [{ 1571 "partId": "1", 1572 "blobId": "841623871", 1573 "size": 283331, 1574 "type": "text/html" 1575 }, { 1576 "partId": "2", 1577 "blobId": "319437193", 1578 "size": 10343, 1579 "type": "text/plain" 1580 }], 1581 "bodyValues": { 1582 "1": { 1583 "isEncodingProblem": false, 1584 "isTruncated": true, 1585 "value": "

Hello ..." 1586 }, 1587 "2": { 1588 "isEncodingProblem": false, 1589 "isTruncated": false, 1590 "value": "-- \nSent by your friendly mailing list ..." 1591 } 1592 } 1593 } 1594 ], 1595 notFound: [ "f123u456" ] 1596 }, "#1"] 1598 4.3. Email/changes 1600 Standard _/changes_ method. 1602 4.4. Email/query 1604 Standard _/query_ method, but with the following additional 1605 arguments: 1607 o *collapseThreads*: "Boolean" (default: "false") If "true", emails 1608 in the same thread as a previous email in the list (given the 1609 filter and sort order) will be removed from the list. This means 1610 at most only one email will be included in the list for any given 1611 thread. 1613 4.4.1. Filtering 1615 A *FilterCondition* object has the following properties, any of which 1616 may be omitted: 1618 o *inMailbox*: "String" A mailbox id. An email must be in this 1619 mailbox to match the condition. 1621 o *inMailboxOtherThan*: "String[]" A list of mailbox ids. An email 1622 must be in at least one mailbox not in this list to match the 1623 condition. This is to allow messages solely in trash/spam to be 1624 easily excluded from a search. 1626 o *before*: "UTCDate" The _receivedAt_ date of the email must be 1627 before this date to match the condition. 1629 o *after*: "UTCDate" The _receivedAt_ date of the email must be on 1630 or after this date to match the condition. 1632 o *minSize*: "Number" The _size_ of the email in octets must be 1633 equal to or greater than this number to match the condition. 1635 o *maxSize*: "Number" The size of the email in octets must be less 1636 than this number to match the condition. 1638 o *allInThreadHaveKeyword*: "String" All emails (including this one) 1639 in the same thread as this email must have the given keyword to 1640 match the condition. 1642 o *someInThreadHaveKeyword*: "String" At least one email (possibly 1643 this one) in the same thread as this email must have the given 1644 keyword to match the condition. 1646 o *noneInThreadHaveKeyword*: "String" All emails (including this 1647 one) in the same thread as this email must *not* have the given 1648 keyword to match the condition. 1650 o *hasKeyword*: "String" This email must have the given keyword to 1651 match the condition. 1653 o *notKeyword*: "String" This email must not have the given keyword 1654 to match the condition. 1656 o *hasAttachment*: "Boolean" The "hasAttachment" property of the 1657 email must be identical to the value given to match the condition. 1659 o *text*: "String" Looks for the text in emails. The server SHOULD 1660 look up text in the _from_, _to_, _cc_, _bcc_, _subject_ header 1661 fields of the message, and inside any "text/*" or other body parts 1662 that may be converted to text by the server. The server MAY 1663 extend the search to any additional textual property. 1665 o *from*: "String" Looks for the text in the _From_ header field of 1666 the message. 1668 o *to*: "String" Looks for the text in the _To_ header field of the 1669 message. 1671 o *cc*: "String" Looks for the text in the _Cc_ header field of the 1672 message. 1674 o *bcc*: "String" Looks for the text in the _Bcc_ header field of 1675 the message. 1677 o *subject*: "String" Looks for the text in the _subject_ property 1678 of the email. 1680 o *body*: "String" Looks for the text in one of the "text/*" body 1681 parts of the email. 1683 o *attachments*: "String" Looks for the text in the attachments of 1684 the email. Servers MAY handle text extraction when possible for 1685 the different kinds of media. 1687 o *header*: "String[]" The array MUST contain either one or two 1688 elements. The first element is the name of the header field to 1689 match against. The second (optional) element is the text to look 1690 for in the header field value. If not supplied, the message 1691 matches simply if it _has_ a header field of the given name. 1693 If zero properties are specified on the FilterCondition, the 1694 condition MUST always evaluate to "true". If multiple properties are 1695 specified, ALL must apply for the condition to be "true" (it is 1696 equivalent to splitting the object into one-property conditions and 1697 making them all the child of an AND filter operator). 1699 The exact semantics for matching "String" fields is *deliberately not 1700 defined* to allow for flexibility in indexing implementation, subject 1701 to the following: 1703 o Any syntactically correct [RFC2047] encoded sections of header 1704 fields with a known encoding SHOULD be decoded before attempting 1705 to match text. 1707 o When searching inside a "text/html" body part, any text considered 1708 markup rather than content SHOULD be ignored, including HTML tags 1709 and most attributes, anything inside the "" tag, CSS and 1710 JavaScript. Attribute content intended for presentation to the 1711 user such as "alt" and "title" SHOULD be considered in the search. 1713 o Text SHOULD be matched in a case-insensitive manner. 1715 o Text contained in either (but matched) single or double quotes 1716 SHOULD be treated as a *phrase search*, that is a match is 1717 required for that exact word or sequence of words, excluding the 1718 surrounding quotation marks. Use "\"", "\'" and "\\" to match a 1719 literal """, "'" and "\" respectively in a phrase. 1721 o Outside of a phrase, white-space SHOULD be treated as dividing 1722 separate tokens that may be searched for separately, but MUST all 1723 be present for the email to match the filter. 1725 o Tokens MAY be matched on a whole-word basis using stemming (so for 1726 example a text search for "bus" would match "buses" but not 1727 "business"). 1729 4.4.2. Sorting 1731 The following properties MUST be supported for sorting: 1733 o *receivedAt* - The _receivedAt_ date as returned in the Email 1734 object. 1736 The following properties SHOULD be supported for sorting: 1738 o *size* - The size as returned in the Email object. 1740 o *from* - This is taken to be either the "name" part, or if 1741 "null"/empty then the "email" part, of the *first* EmailAddress 1742 object in the _from_ property. If still none, consider the value 1743 to be the empty string. 1745 o *to* - This is taken to be either the "name" part, or if 1746 "null"/empty then the "email" part, of the *first* EmailAddress 1747 object in the _to_ property. If still none, consider the value to 1748 be the empty string. 1750 o *subject* - This is taken to be the base subject of the email, as 1751 defined in section 2.1 of [RFC5256]. 1753 o *sentAt* - The _sentAt_ property on the Email object. 1755 o *hasKeyword* - This value MUST be considered "true" if the email 1756 has the keyword given as the _keyword_ property on this 1757 _Comparator_ object, or "false" otherwise. 1759 o *allInThreadHaveKeyword* - This value MUST be considered "true" 1760 for the email if *all* of the emails in the same thread 1761 (regardless of mailbox) have the keyword given as the _keyword_ 1762 property on this _Comparator_ object. 1764 o *someInThreadHaveKeyword* - This value MUST be considered "true" 1765 for the email if *any* of the emails in the same thread 1766 (regardless of mailbox) have the keyword given as the _keyword_ 1767 property on this _Comparator_ object. 1769 The server MAY support sorting based on other properties as well. A 1770 client can discover which properties are supported by inspecting the 1771 server's _capabilities_ object (see section 1). 1773 Example sort: 1775 [{ 1776 "property": "someInThreadHaveKeyword", 1777 "keyword": "$flagged", 1778 "isAscending": false, 1779 }, { 1780 "property": "subject", 1781 "collation": "i;ascii-casemap" 1782 }, { 1783 "property": "receivedAt", 1784 "isAscending": false, 1785 }] 1787 This would sort emails in flagged threads first (the thread is 1788 considered flagged if any email within it is flagged), and then in 1789 subject order, then newest first for messages with the same subject. 1790 If two emails have both identical flagged status, subject and date, 1791 the order is server-dependent but must be stable. 1793 4.4.3. Thread collapsing 1795 When "collapseThreads == true", then after filtering and sorting the 1796 email list, the list is further winnowed by removing any emails for a 1797 thread id that has already been seen (when passing through the list 1798 sequentially). A thread will therefore only appear *once* in the 1799 "threadIds" list of the result, at the position of the first email in 1800 the list that belongs to the thread. 1802 4.4.4. Response 1804 The response has the following additional argument: 1806 o *collapseThreads*: "Boolean" The _collapseThreads_ value that was 1807 used when calculating the email list for this call. 1809 4.5. Email/queryChanges 1811 Standard _/queryChanges_ method, with the following additional 1812 arguments: 1814 o *collapseThreads*: "Boolean" (default: "false") The 1815 _collapseThreads_ argument that was used with _Email/query_. 1817 The response has the following additional argument: 1819 o *collapseThreads*: "Boolean" The _collapseThreads_ value that was 1820 used when calculating the email list for this call. 1822 4.6. Email/set 1824 Standard _/set_ method. The _Email/set_ method encompasses: 1826 o Creating a draft 1828 o Changing the keywords of an email (e.g. unread/flagged status) 1830 o Adding/removing an email to/from mailboxes (moving a message) 1832 o Deleting emails 1834 Due to the format of the Email object, when creating an email there 1835 are a number of ways to specify the same information. To ensure that 1836 the RFC5322 email to create is unambiguous, the following constraints 1837 apply to Email objects submitted for creation: 1839 o The _headers_ property MUST NOT be given, on either the top-level 1840 email or an EmailBodyPart - the client must set each header field 1841 as an individual property. 1843 o There MUST NOT be two properties that represent the same header 1844 field (e.g. "header:from" and "from") within the Email or 1845 particular EmailBodyPart. 1847 o Header fields MUST NOT be specified in parsed forms that are 1848 forbidden for that particular field. 1850 o Header fields beginning "Content-" MUST NOT be specified on the 1851 Email object, only on EmailBodyPart objects. 1853 o If a bodyStructure property is given, there MUST NOT be textBody, 1854 htmlBody or attachments properties. 1856 o If given, the bodyStructure EmailBodyPart MUST NOT contain a 1857 property representing a header field that is already defined on 1858 the top-level Email object. 1860 o If given, textBody MUST contain exactly one body part, of type 1861 "text/plain". 1863 o If given, htmlBody MUST contain exactly one body part, of type 1864 "text/html". 1866 o Within an EmailBodyPart: 1868 * The client may specify a partId OR a blobId but not both. If a 1869 partId is given, this partId MUST be present in the bodyValues 1870 property. 1872 * The charset property MUST be omitted if a partId is given (the 1873 part's content is included in bodyValues and the server may 1874 choose any appropriate encoding). 1876 * The size property MUST be omitted if a partId is given. If a 1877 blobId is given, it may be omitted, but otherwise MUST match 1878 the size of the blob. 1880 * A "Content-Transfer-Encoding" header field MUST NOT be given. 1882 o Within an EmailBodyValue object, isEncodingProblem and isTruncated 1883 MUST be either "false" or omitted. 1885 Creation attempts that violate any of this SHOULD be rejected with an 1886 "invalidProperties" error, however a server MAY choose to modify the 1887 Email (e.g. choose between conflicting headers, use a different 1888 content-encoding etc.) to comply with its requirements instead. 1890 The server MAY also choose to set additional headers. If not 1891 included, the server MUST generate and set a "Message-ID" header 1892 field in conformance with [RFC5322] section 3.6.4, and a "Date" 1893 header field in conformance with section 3.6.1. 1895 The final RFC5322 email generated may be invalid. For example, if it 1896 is a half-finished draft, the "To" field may data that does not 1897 currently conform to the required syntax for this header field. The 1898 message will be checked for strict conformance when submitted for 1899 sending (see the EmailSubmission object description). 1901 Destroying an email removes it from all mailboxes to which it 1902 belonged. To just delete an email to trash, simply change the 1903 "mailboxIds" property so it is now in the mailbox with "role == 1904 "trash"", and remove all other mailbox ids. 1906 When emptying the trash, clients SHOULD NOT destroy emails which are 1907 also in a mailbox other than trash. For those emails, they SHOULD 1908 just remove the Trash mailbox from the email. 1910 For successfully created Email objects, the _created_ response MUST 1911 contain the _id_, _blobId_, _threadId_ and _size_ properties of the 1912 object. 1914 The following extra _SetError_ types are defined: 1916 For *create*: 1918 o "blobNotFound": At least one blob id given for an EmailBodyPart 1919 doesn't exist. An extra _notFound_ property of type "String[]" 1920 MUST be included in the error object containing every _blobId_ 1921 referenced by an EmailBodyPart that could not be found on the 1922 server. 1924 For *create* and *update*: 1926 o "tooManyKeywords": The change to the email's keywords would exceed 1927 a server-defined maximum. 1929 o "tooManyMailboxes": The change to the email's mailboxes would 1930 exceed a server-defined maximum. 1932 4.7. Email/import 1934 The _Email/import_ method adds [RFC5322] messages to a user's set of 1935 emails. The messages must first be uploaded as a file using the 1936 standard upload mechanism. It takes the following arguments: 1938 o *accountId*: "String|null" The id of the account to use for this 1939 call. If "null", defaults to the "urn:ietf:params:jmap:mail" 1940 primary account. 1942 o *emails*: "String[EmailImport]" A map of creation id (client 1943 specified) to EmailImport objects 1945 An *EmailImport* object has the following properties: 1947 o *blobId*: "String" The id of the blob containing the raw [RFC5322] 1948 message. 1950 o *mailboxIds* "String[Boolean]" The ids of the mailboxes to assign 1951 this email to. At least one mailbox MUST be given. 1953 o *keywords*: "String[Boolean]" (default: "{}") The keywords to 1954 apply to the email. 1956 o *receivedAt*: "UTCDate" (default: time of import on server) The 1957 _receivedAt_ date to set on the email. 1959 Each email to import is considered an atomic unit which may succeed 1960 or fail individually. Importing successfully creates a new email 1961 object from the data reference by the blobId and applies the given 1962 mailboxes, keywords and receivedAt date. 1964 The server MAY forbid two email objects with the same exact [RFC5322] 1965 content, or even just with the same [RFC5322] Message-ID, to coexist 1966 within an account. In this case, it MUST reject attempts to import 1967 an email considered a duplicate with an "alreadyExists" SetError. An 1968 _emailId_ property of type "String" MUST be included on the error 1969 object with the id of the existing email. 1971 If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid 1972 (e.g. missing, wrong type, id not found), the server MUST reject the 1973 import with an "invalidProperties" SetError. 1975 If the email cannot be imported because it would take the account 1976 over quota, the import should be rejected with a "maxQuotaReached" 1977 SetError. 1979 If the blob referenced is not a valid [RFC5322] message, the server 1980 MAY modify the message to fix errors (such as removing NUL octets or 1981 fixing invalid headers). If it does this, the _blobId_ on the 1982 response MUST represent the new representation and therefore be 1983 different to the _blobId_ on the EmailImport object. Alternatively, 1984 the server MAY reject the import with an "invalidEmail" SetError. 1986 The response has the following arguments: 1988 o *accountId*: "String" The id of the account used for this call. 1990 o *created*: "String[Email]" A map of the creation id to an object 1991 containing the _id_, _blobId_, _threadId_ and _size_ properties 1992 for each successfully imported Email. 1994 o *notCreated*: "String[SetError]" A map of creation id to a 1995 SetError object for each Email that failed to be created. The 1996 possible errors are defined above. 1998 4.8. Email/copy 2000 The only way to move messages *between* two different accounts is to 2001 copy them using the _Email/copy_ method, then once the copy has 2002 succeeded, delete the original. The _onSuccessDestroyOriginal_ 2003 argument allows you to try to do this in one method call, however 2004 note that the two different actions are not atomic, and so it is 2005 possible for the copy to succeed but the original not to be destroyed 2006 for some reason. 2008 The _Email/copy_ method takes the following arguments: 2010 o *fromAccountId*: "String|null" The id of the account to copy 2011 emails from. If "null", defaults to the 2012 "urn:ietf:params:jmap:mail" primary account. 2014 o *toAccountId*: "String|null" The id of the account to copy emails 2015 to. If "null", defaults to the "urn:ietf:params:jmap:mail" 2016 primary account. 2018 o *create*: "String[EmailCopy]" A map of _creation id_ to an 2019 EmailCopy object. 2021 o *onSuccessDestroyOriginal*: "Boolean" (default: "false") If 2022 "true", an attempt will be made to destroy the emails that were 2023 successfully copied: after emitting the _Email/copy_ response, but 2024 before processing the next method, the server MUST make a single 2025 call to _Email/set_ to destroy the original of each successfully 2026 copied message; the output of this is added to the responses as 2027 normal to be returned to the client. 2029 An *EmailCopy* object has the following properties: 2031 o *id*: "String" The id of the email to be copied in the "from" 2032 account. 2034 o *mailboxIds*: "String[Boolean]" The ids of the mailboxes (in the 2035 "to" account) to add the copied email to. At least one mailbox 2036 MUST be given. 2038 o *keywords*: "String[Boolean]" (default: "{}") The _keywords_ 2039 property for the copy. 2041 o *receivedAt*: "UTCDate" (default: _receivedAt_ date of original) 2042 The _receivedAt_ date to set on the copy. 2044 The server MAY forbid two email objects with the same exact [RFC5322] 2045 content, or even just with the same [RFC5322] Message-ID, to coexist 2046 within an account. If duplicates are allowed though, the "from" 2047 account may be the same as the "to" account to copy emails within an 2048 account. 2050 Each email copy is considered an atomic unit which may succeed or 2051 fail individually. Copying successfully MUST create a new email 2052 object, with separate ids and mutable properties (e.g. mailboxes and 2053 keywords) to the original email. 2055 The response has the following arguments: 2057 o *fromAccountId*: "String" The id of the account emails were copied 2058 from. 2060 o *toAccountId*: "String" The id of the account emails were copied 2061 to. 2063 o *created*: "String[Email]|null" A map of the creation id to an 2064 object containing the _id_, _blobId_, _threadId_ and _size_ 2065 properties for each successfully copied Email. 2067 o *notCreated*: "String[SetError]|null" A map of creation id to a 2068 SetError object for each Email that failed to be copied, "null" if 2069 none. 2071 The *SetError* may be any of the standard set errors that may be 2072 returned for a _create_. The following extra _SetError_ type is also 2073 defined: 2075 "alreadyExists": The server forbids duplicates and the email already 2076 exists in the target account. An _emailId_ property of type "String" 2077 MUST be included on the error object with the id of the existing 2078 email. 2080 The following additional errors may be returned instead of the 2081 _Email/copy_ response: 2083 "fromAccountNotFound": A _fromAccountId_ was explicitly included with 2084 the request, but it does not correspond to a valid account; or, 2085 _fromAccountId_ was null but there is no primary account for 2086 "urn:ietf:params:jmap:mail". 2088 "toAccountNotFound": A _toAccountId_ was explicitly included with the 2089 request, but it does not correspond to a valid account; or, 2090 _toAccountId_ was null but there is no primary account for 2091 "urn:ietf:params:jmap:mail". 2093 "fromAccountNotSupportedByMethod": The _fromAccountId_ given 2094 corresponds to a valid account, but does not contain any mail data. 2096 "toAccountNotSupportedByMethod": The _toAccountId_ given corresponds 2097 to a valid account, but does not contain any mail data. 2099 4.9. Email/parse 2101 This method allows you to parse blobs as [RFC5322] messages to get 2102 Email objects. The following metadata properties on the Email 2103 objects will be "null" if requested: 2105 o id 2107 o mailboxIds 2109 o keywords 2111 o receivedAt 2113 The _threadId_ property of the Email MAY be present if the server can 2114 calculate which thread the Email would be assigned to were it to be 2115 imported. Otherwise, this too is "null" if fetched. 2117 The _Email/parse_ method takes the following arguments: 2119 o *accountId*: "String|null" The id of the Account to use. If 2120 "null", the primary account is used. 2122 o *blobIds*: "String[]" The ids of the blobs to parse. 2124 o *properties*: "String[]" If supplied, only the properties listed 2125 in the array are returned for each Email object. If omitted, 2126 defaults to: [ "messageId", "inReplyTo", "references", "sender", 2127 "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", 2128 "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", 2129 "attachments" ] 2131 o *bodyProperties*: "String[]" (optional) A list of properties to 2132 fetch for each EmailBodyPart returned. If omitted, defaults to 2133 the same value as the Email/get "bodyProperties" default argument. 2135 o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the 2136 _bodyValues_ property includes any "text/*" part in the "textBody" 2137 property. 2139 o *fetchHTMLBodyValues*: "Boolean" (default: "false") If "true", the 2140 _bodyValues_ property includes any "text/*" part in the "htmlBody" 2141 property. 2143 o *fetchAllBodyValues*: "Boolean" (default: "false") If "true", the 2144 _bodyValues_ property includes any "text/*" part in the 2145 "bodyStructure" property. 2147 o *maxBodyValueBytes*: "Number" (optional) If supplied by the 2148 client, the value MUST be a positive integer greater than 0. If a 2149 value outside of this range is given, the server MUST reject the 2150 call with an "invalidArguments" error. When given, the _value_ 2151 property of any EmailBodyValue object returned in _bodyValues_ 2152 MUST be truncated if necessary so it does not exceed this number 2153 of octets in size. The server MUST ensure the truncation results 2154 in valid UTF-8 and does not occur mid-codepoint. If the part is 2155 of type "text/html", the server SHOULD NOT truncate inside an HTML 2156 tag. 2158 The response has the following arguments: 2160 o *accountId*: "String" The id of the account used for the call. 2162 o *parsed*: "String[Email]|null" A map of blob id to parsed Email 2163 representation for each successfully parsed blob, or "null" if 2164 none. 2166 o *notParsable*: "String[]|null" A list of ids given that 2167 corresponded to blobs that could not be parsed as emails, or 2168 "null" if none. 2170 o *notFound*: "String[]|null" A list of blob ids given that could 2171 not be found, or "null" if none. 2173 As specified above, parsed forms of headers may only be used on 2174 appropriate header fields. Attempting to fetch a form that is 2175 forbidden (e.g. "header:From:asDate") MUST result in the method call 2176 being rejected with an "invalidArguments" error. 2178 Where a specific header is requested as a property, the 2179 capitalization of the property name in the response MUST be identical 2180 to that used in the request. 2182 5. Identities 2184 An *Identity* object stores information about an email address (or 2185 domain) the user may send from. It has the following properties: 2187 o *id*: "String" (immutable; server-set) The id of the identity. 2189 o *name*: "String" (default: """") The "From" _name_ the client 2190 SHOULD use when creating a new message from this identity. 2192 o *email*: "String" (immutable) The "From" email address the client 2193 MUST use when creating a new message from this identity. The 2194 value MAY alternatively be of the form "*@example.com", in which 2195 case the client may use any valid email address ending in 2196 "@example.com". 2198 o *replyTo*: "EmailAddress[]|null" (default: "null") The Reply-To 2199 value the client SHOULD set when creating a new message from this 2200 identity. 2202 o *bcc*: "EmailAddress[]|null" (default: "null") The Bcc value the 2203 client SHOULD set when creating a new message from this identity. 2205 o *textSignature*: "String" (default: """") Signature the client 2206 SHOULD insert into new plain-text messages that will be sent from 2207 this identity. Clients MAY ignore this and/or combine this with a 2208 client-specific signature preference. 2210 o *htmlSignature*: "String" (default: """") Signature the client 2211 SHOULD insert into new HTML messages that will be sent from this 2212 identity. This text MUST be an HTML snippet to be inserted into 2213 the "" section of the new email. Clients MAY ignore 2214 this and/or combine this with a client-specific signature 2215 preference. 2217 o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete 2218 this identity? Servers may wish to set this to "false" for the 2219 user's username or other default address. 2221 See the "Addresses" header form description in the Email object for 2222 the definition of _EmailAddress_. 2224 Multiple identities with the same email address MAY exist, to allow 2225 for different settings the user wants to pick between (for example 2226 with different names/signatures). 2228 The following JMAP methods are supported: 2230 5.1. Identity/get 2232 Standard _/get_ method. The _ids_ argument may be "null" to fetch 2233 all at once. 2235 5.2. Identity/changes 2237 Standard _/changes_ method. 2239 5.3. Identity/set 2241 Standard _/set_ method. The following extra _SetError_ types are 2242 defined: 2244 For *create*: 2246 o "maxQuotaReached": The user has reached a server-defined limit on 2247 the number of identities. 2249 o "emailNotPermitted": The user is not allowed to send from the 2250 address given as the _email_ property of the identity. 2252 For *destroy*: 2254 o "forbidden": Returned if the identity's _mayDelete_ value is 2255 "false". 2257 5.4. Example 2259 Request: 2261 [ "Identity/get", {}, "0" ] 2263 with response: 2265 [ "Identity/get", { 2266 "accountId": "acme", 2267 "state": "99401312ae-11-333", 2268 "list": [ 2269 { 2270 "id": "3301-222-11_22AAz", 2271 "name": "Joe Bloggs", 2272 "email": "joe@example.com", 2273 "replyTo": null, 2274 "bcc": [{ 2275 "name": null, 2276 "email": "joe+archive@example.com" 2277 }], 2278 "textSignature": "-- \nJoe Bloggs\nMaster of Email", 2279 "htmlSignature": "

Joe Bloggs
Master of Email
", 2280 "mayDelete": false, 2281 }, 2282 { 2283 "id": "9911312-11_22AAz", 2284 "name": "Joe B", 2285 "email": "joebloggs@example.com", 2286 "replyTo": null, 2287 "bcc": null, 2288 "textSignature": "", 2289 "htmlSignature": "", 2290 "mayDelete": true 2291 } 2292 ], 2293 "notFound": [] 2294 }, "0" ] 2296 6. Email submission 2298 An *EmailSubmission* object represents the submission of an email for 2299 delivery to one or more recipients. It has the following properties: 2301 o *id*: "String" (immutable; server-set) The id of the email 2302 submission. 2304 o *identityId*: "String" (immutable) The id of the identity to 2305 associate with this submission. 2307 o *emailId*: "String" (immutable) The id of the email to send. The 2308 email being sent does not have to be a draft, for example when 2309 "redirecting" an existing email to a different address. 2311 o *threadId*: "String" (immutable; server-set) The thread id of the 2312 email to send. This is set by the server to the _threadId_ 2313 property of the email referenced by the _emailId_. 2315 o *envelope*: "Envelope|null" (immutable; default: "null") 2316 Information for use when sending via SMTP. An *Envelope* object 2317 has the following properties: 2319 * *mailFrom*: "Address" The email address to use as the return 2320 address in the SMTP submission, plus any parameters to pass 2321 with the MAIL FROM address. The JMAP server MAY allow the 2322 address to be the empty string. When a JMAP server performs an 2323 SMTP message submission, it MAY use the same id string for the 2324 [RFC3461] ENVID parameter and the EmailSubmission object id. 2325 Servers that do this MAY replace a client-provided value for 2326 ENVID with a server-provided value. 2328 * *rcptTo*: "Address[]" The email addresses to send the message 2329 to, and any RCPT TO parameters to pass with the recipient. 2331 An *Address* object has the following properties: 2333 * *email*: "String" The email address being represented by the 2334 object. This as a "Mailbox" as used in the Reverse-path or 2335 Forward-path of the MAIL FROM or RCPT TO command in [RFC5321]. 2337 * *parameters*: "Object|null" Any parameters to send with the 2338 email (either mail-parameter or rcpt-parameter as appropriate, 2339 as specified in [RFC5321]). If supplied, each key in the 2340 object is a parameter name, and the value either the parameter 2341 value (type "String") or if the parameter does not take a value 2342 then "null". For both name and value, any xtext or unitext 2343 encodings are removed ([RFC3461], [RFC6533]) and JSON string 2344 encoding applied. 2346 If the _envelope_ property is "null" or omitted on creation, the 2347 server MUST generate this from the referenced email as follows: 2349 * *mailFrom*: The email in the _Sender_ header, if present, 2350 otherwise the _From_ header, if present, and no parameters. If 2351 multiple addresses are present in one of these headers, or 2352 there is more than one _Sender_/_From_ header, the server 2353 SHOULD reject the email as invalid but otherwise MUST take the 2354 first address in the last _Sender_/_From_ header in the 2355 [RFC5322] version of the message. If the address found from 2356 this is not allowed by the identity associated with this 2357 submission, the _email_ property from the identity MUST be used 2358 instead. 2360 * *rcptTo*: The deduplicated set of email addresses from the 2361 _To_, _Cc_ and _Bcc_ headers, if present, with no parameters 2362 for any of them. 2364 o *sendAt*: "UTCDate" (immutable; server-set) The date the email 2365 was/will be released for delivery. If the client successfully 2366 used [RFC4865] FUTURERELEASE with the email, this MUST be the time 2367 when the server will release the email; otherwise it MUST be the 2368 time the EmailSubmission was created. 2370 o *undoStatus*: "String" (server-set) This represents whether the 2371 submission may be canceled. This is server set and MUST be one of 2372 the following values: 2374 * "pending": It MAY be possible to cancel this submission. 2376 * "final": The email has been relayed to at least one recipient 2377 in a manner that cannot be recalled. It is no longer possible 2378 to cancel this submission. 2380 * "canceled": The email submission was canceled and will not be 2381 delivered to any recipient. 2383 On systems that do not support unsending, the value of this 2384 property will always be "final". On systems that do support 2385 canceling submission, it will start as "pending", and MAY 2386 transition to "final" when the server knows it definitely cannot 2387 recall the email, but MAY just remain "pending". If in pending 2388 state, a client can attempt to cancel the submission by setting 2389 this property to "canceled"; if the update succeeds, the 2390 submission was successfully canceled and the email has not been 2391 delivered to any of the original recipients. 2393 o *deliveryStatus*: "String[DeliveryStatus]|null" (server-set) This 2394 represents the delivery status for each of the email's recipients, 2395 if known. This property MAY not be supported by all servers, in 2396 which case it will remain "null". Servers that support it SHOULD 2397 update the EmailSubmission object each time the status of any of 2398 the recipients changes, even if some recipients are still being 2399 retried. This value is a map from the email address of each 2400 recipient to a _DeliveryStatus_ object. A *DeliveryStatus* object 2401 has the following properties: 2403 * *smtpReply*: "String" The SMTP reply string returned for this 2404 recipient when the server last tried to relay the email, or in 2405 a later DSN response for the email. This SHOULD be the 2406 response to the RCPT TO stage, unless this was accepted and the 2407 email as a whole rejected at the end of the DATA stage, in 2408 which case the DATA stage reply SHOULD be used instead. Multi- 2409 line SMTP responses should be concatenated to a single string 2410 as follows: 2412 + The hyphen following the SMTP code on all but the last line 2413 is replaced with a space. 2415 + Any prefix in common with the first line is stripped from 2416 lines after the first. 2418 + CRLF is replaced by a space. 2420 For example: 2422 550-5.7.1 Our system has detected that this message is 2423 550 5.7.1 likely spam, sorry. 2425 would become: 2427 550 5.7.1 Our system has detected that this message is likely spam, sorry. 2429 For emails relayed via an alternative to SMTP, the server MAY 2430 generate a synthetic string representing the status instead. 2431 If it does this, the string MUST be of the following form: 2433 + A 3-digit SMTP reply code, as defined in [RFC5321], section 2434 4.2.3. 2436 + Then a single space character. 2438 + Then an SMTP Enhanced Mail System Status Code as defined in 2439 [RFC3463], with a registry defined in [RFC5248]. 2441 + Then a single space character. 2443 + Then an implementation-specific information string with a 2444 human readable explanation of the response. 2446 * *delivered*: "String" Represents whether the email has been 2447 successfully delivered to the recipient. This MUST be one of 2448 the following values: 2450 + "queued": The email is in a local mail queue and status will 2451 change once it exits the local mail queues. The _smtpReply_ 2452 property may still change. 2454 + "yes": The email was successfully delivered to the mailbox 2455 of the recipient. The _smtpReply_ property is final. 2457 + "no": Delivery to the recipient permanently failed. The 2458 _smtpReply_ property is final. 2460 + "unknown": The final delivery status is unknown, (e.g. it 2461 was relayed to an external machine and no further 2462 information is available). The _smtpReply_ property may 2463 still change if a DSN arrives. 2465 Note, successful relaying to an external SMTP server SHOULD NOT 2466 be taken as an indication that the email has successfully 2467 reached the final mailbox. In this case though, the server MAY 2468 receive a DSN response, if requested. If a DSN is received for 2469 the recipient with Action equal to "delivered", as per 2470 [RFC3464] section 2.3.3, then the _delivered_ property SHOULD 2471 be set to "yes"; if the Action equals "failed", the property 2472 SHOULD be set to "no". Receipt of any other DSN SHOULD NOT 2473 affect this property. The server MAY also set this property 2474 based on other feedback channels. 2476 * *displayed*: "String" Represents whether the email has been 2477 displayed to the recipient. This MUST be one of the following 2478 values: 2480 + "unknown": The display status is unknown. This is the 2481 initial value. 2483 + "yes": The recipient's system claims the email content has 2484 been displayed to the recipient. Note, there is no 2485 guarantee that the recipient has noticed, read, or 2486 understood the content. 2488 If an MDN is received for this recipient with Disposition-Type 2489 (as per [RFC3798] section 3.2.6.2) equal to "displayed", this 2490 property SHOULD be set to "yes". The server MAY also set this 2491 property based on other feedback channels. 2493 o *dsnBlobIds*: "String[]" (server-set) A list of blob ids for DSNs 2494 received for this submission, in order of receipt, oldest first. 2496 o *mdnBlobIds*: "String[]" (server-set) A list of blob ids for MDNs 2497 received for this submission, in order of receipt, oldest first. 2499 JMAP servers MAY choose not to expose DSN and MDN responses as Email 2500 objects if they correlate to a EmailSubmission object. It SHOULD 2501 only do this if it exposes them in the _dsnBlobIds_ and _mdnblobIds_ 2502 fields instead, and expects the user to be using clients capable of 2503 fetching and displaying delivery status via the EmailSubmission 2504 object. 2506 For efficiency, a server MAY destroy EmailSubmission objects a 2507 certain amount of time after the email is successfully sent or it has 2508 finished retrying sending the email. For very basic SMTP proxies, 2509 this MAY be immediately after creation, as it has no way to assign a 2510 real id and return the information again if fetched later. 2512 The following JMAP methods are supported: 2514 6.1. EmailSubmission/get 2516 Standard _/get_ method. 2518 6.2. EmailSubmission/changes 2520 Standard _/changes_ method. 2522 6.3. EmailSubmission/query 2524 Standard _/query_ method. 2526 A *FilterCondition* object has the following properties, any of which 2527 may be omitted: 2529 o *emailIds*: "String[]" The EmailSubmission _emailId_ property must 2530 be in this list to match the condition. 2532 o *threadIds*: "String[]" The EmailSubmission _threadId_ property 2533 must be in this list to match the condition. 2535 o *undoStatus*: "String" The EmailSubmission _undoStatus_ property 2536 must be identical to the value given to match the condition. 2538 o *before*: "UTCDate" The _sendAt_ property of the EmailSubmission 2539 object must be before this date to match the condition. 2541 o *after*: "UTCDate" The _sendAt_ property of the EmailSubmission 2542 object must be after this date to match the condition. 2544 A EmailSubmission object matches the filter if and only if all of the 2545 given conditions given match. If zero properties are specified, it 2546 is automatically "true" for all objects. 2548 The following properties MUST be supported for sorting: 2550 o "emailId" 2552 o "threadId" 2553 o "sentAt" 2555 6.4. EmailSubmission/queryChanges 2557 Standard _/queryChanges_ method. 2559 6.5. EmailSubmission/set 2561 Standard _/set_ method, with the following two extra arguments: 2563 o *onSuccessUpdateEmail*: "String[Email]|null" A map of 2564 _EmailSubmission id_ to an object containing properties to update 2565 on the Email object referenced by the EmailSubmission if the 2566 create/update/destroy succeeds. (For references to 2567 EmailSubmission creations, this is equivalent to a back reference 2568 so the id will be the creation id prefixed with a "#".) 2570 o *onSuccessDestroyEmail*: "String[]|null" A list of 2571 _EmailSubmission ids_ for which the email with the corresponding 2572 emailId should be destroyed if the create/update/destroy succeeds. 2573 (For references to EmailSubmission creations, this is equivalent 2574 to a back reference so the id will be the creation id prefixed 2575 with a "#".) 2577 A single implicit _Email/set_ call MUST be made after all 2578 EmailSubmission create/update/destroy requests have been processed to 2579 perform any changes requested in these two arguments. The response 2580 to this MUST be returned after the _EmailSubmission/set_ response. 2582 An email is sent by creating a EmailSubmission object. When 2583 processing each create, the server must check that the email is 2584 valid, and the user has sufficient authorization to send it. If the 2585 creation succeeds, the email will be sent to the recipients given in 2586 the envelope _rcptTo_ parameter. The server MUST remove any _Bcc_ 2587 header present on the email during delivery. The server MAY add or 2588 remove other headers from the submitted email, or make further 2589 alterations in accordance with the server's policy during delivery. 2591 If the referenced email is destroyed at any point after the 2592 EmailSubmission object is created, this MUST NOT change the behaviour 2593 of the email submission (i.e. it does not cancel a future send). 2595 Similarly, destroying a EmailSubmission object MUST NOT affect the 2596 deliveries it represents. It purely removes the record of the email 2597 submission. The server MAY automatically destroy EmailSubmission 2598 objects after a certain time or in response to other triggers, and 2599 MAY forbid the client from manually destroying EmailSubmission 2600 objects. 2602 The following extra _SetError_ types are defined: 2604 For *create*: 2606 o "tooLarge" - The email size is larger than the server supports 2607 sending. A _maxSize_ "Number" property MUST be present on the 2608 SetError specifying the maximum size of an email that may be sent, 2609 in octets. 2611 o "tooManyRecipients" - The envelope (supplied or generated) has 2612 more recipients than the server allows. A _maxRecipients_ 2613 "Number" property MUST be present on the SetError specifying the 2614 maximum number of allowed recipients. 2616 o "noRecipients" - The envelope (supplied or generated) does not 2617 have any rcptTo emails. 2619 o "invalidRecipients" - The _rcptTo_ property of the envelope 2620 (supplied or generated) contains at least one rcptTo value which 2621 is not a valid email for sending to. An _invalidRecipients_ 2622 "String[]" property MUST be present on the SetError, which is a 2623 list of the invalid addresses. 2625 o "forbiddenMailFrom" - The server does not permit the user to send 2626 an email with the [RFC5321] envelope From. 2628 o "forbiddenFrom" - The server does not permit the user to send an 2629 email with the [RFC5322] From header of the email to be sent. 2631 o "forbiddenToSend" - The user does not have permission to send at 2632 all right now for some reason. A _description_ "String" property 2633 MAY be present on the SetError object to display to the user why 2634 they are not permitted. The server MAY choose to localise this 2635 string into the user's preferred language, if known. 2637 o "emailNotFound" - The _emailId_ is not a valid id for an email in 2638 the account. 2640 o "invalidEmail" - The email to be sent is invalid in some way. The 2641 SetError SHOULD contain a property called _properties_ of type 2642 "String[]" that lists *all* the properties of the email that were 2643 invalid. 2645 For *update*: 2647 o "cannotUnsend": The client attempted to update the _undoStatus_ of 2648 a valid EmailSubmission object from "pending" to "canceled", but 2649 the email cannot be unsent. 2651 6.5.1. Example 2653 The following example presumes a draft of the message to be sent has 2654 already been saved, and its Email id is "M7f6ed5bcfd7e2604d1753f6c". 2655 This call then sends the email immediately, and if successful removes 2656 the draft flag and moves it from the Drafts folder (which has Mailbox 2657 id "7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e") to the Sent folder (which 2658 we presume has Mailbox id "73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6"). 2660 [ 2661 "EmailSubmission/set", 2662 { 2663 "accountId": "ue411d190", 2664 "create": { 2665 "k1490": { 2666 "identityId": "64588216", 2667 "emailId": "M7f6ed5bcfd7e2604d1753f6c", 2668 "envelope": { 2669 "mailFrom": { 2670 "email": "john@example.com", 2671 "parameters": null 2672 }, 2673 "rcptTo": [ 2674 { 2675 "email": "jane@example.com", 2676 "parameters": null 2677 } 2678 ] 2679 } 2680 } 2681 }, 2682 "onSuccessUpdateEmail": { 2683 "#k1490": { 2684 "mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null, 2685 "mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true, 2686 "keywords/$draft": null 2687 } 2688 } 2689 }, 2690 "0" 2691 ] 2693 A successful response might look like this. Note there are two 2694 responses due to the implicit Email/set call, but both have the same 2695 tag as they are due to the same call in the request: 2697 [ 2698 "EmailSubmission/set", 2699 { 2700 "accountId": "ue411d190", 2701 "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21, 2702 "newState": "355421f6-8aed-4cf4-a0c4-7377e951af36", 2703 "created": { 2704 "k1490": { 2705 "id": "3bab7f9a-623e-4acf-99a5-2e67facb02a0" 2706 } 2707 }, 2708 "notCreated": null, 2709 "updated": null, 2710 "notUpdated": null, 2711 "destroyed": null, 2712 "notDestroyed": null 2713 }, 2714 "0" 2715 ], 2716 [ 2717 "Email/set", 2718 { 2719 "accountId": "neilj@fastmail.fm", 2720 "oldState": "778193", 2721 "newState": "778197", 2722 "created": null, 2723 "notCreated": null, 2724 "updated": { 2725 "M7f6ed5bcfd7e2604d1753f6c": null 2726 }, 2727 "notUpdated": null, 2728 "destroyed": null, 2729 "notDestroyed": null 2730 }, 2731 "0" 2732 ] 2734 7. Search snippets 2736 When doing a search on a "String" property, the client may wish to 2737 show the relevant section of the body that matches the search as a 2738 preview instead of the beginning of the message, and to highlight any 2739 matching terms in both this and the subject of the email. Search 2740 snippets represent this data. 2742 A *SearchSnippet* object has the following properties: 2744 o *emailId*: "String" The email id the snippet applies to. 2746 o *subject*: "String|null" If text from the filter matches the 2747 subject, this is the subject of the email HTML-escaped, with 2748 matching words/phrases wrapped in "" tags. If it 2749 does not match, this is "null". 2751 o *preview*: "String|null" If text from the filter matches the 2752 plain-text or HTML body, this is the relevant section of the body 2753 (converted to plain text if originally HTML), HTML-escaped, with 2754 matching words/phrases wrapped in "" tags. It MUST 2755 NOT be bigger than 255 octets in size. If it does not match, this 2756 is "null". 2758 o *attachments*: "String|null" If text from the filter matches the 2759 text extracted from an attachment, this is the relevant section of 2760 the attachment (converted to plain text), with matching words/ 2761 phrases wrapped in "" tags. It MUST NOT be bigger 2762 than 255 octets in size. If it does not match, this is "null". 2764 It is server-defined what is a relevant section of the body for 2765 preview. If the server is unable to determine search snippets, it 2766 MUST return "null" for both the _subject_, _preview_ and 2767 _attachments_ properties. 2769 Note, unlike most data types, a SearchSnippet DOES NOT have a 2770 property called "id". 2772 The following JMAP method is supported: 2774 7.1. SearchSnippet/get 2776 To fetch search snippets, make a call to "SearchSnippet/get". It 2777 takes the following arguments: 2779 o *accountId*: "String|null" The id of the account to use for this 2780 call. If "null", defaults to the "urn:ietf:params:jmap:mail" 2781 primary account. 2783 o *filter*: "FilterOperator|FilterCondition|null" The same filter as 2784 passed to Email/query; see the description of this method for 2785 details. 2787 o *emailIds*: "String[]" The list of ids of emails to fetch the 2788 snippets for. 2790 The response has the following arguments: 2792 o *accountId*: "String" The id of the account used for the call. 2794 o *filter*: "FilterOperator|FilterCondition|null" Echoed back from 2795 the call. 2797 o *list*: "SearchSnippet[]" An array of SearchSnippet objects for 2798 the requested email ids. This may not be in the same order as the 2799 ids that were in the request. 2801 o *notFound*: "String[]|null" An array of email ids requested which 2802 could not be found, or "null" if all ids were found. 2804 Since snippets are only based on immutable properties, there is no 2805 state string or update mechanism needed. 2807 The following additional errors may be returned instead of the 2808 _searchSnippets_ response: 2810 "requestTooLarge": Returned if the number of _emailIds_ requested by 2811 the client exceeds the maximum number the server is willing to 2812 process in a single method call. 2814 "unsupportedFilter": Returned if the server is unable to process the 2815 given _filter_ for any reason. 2817 7.2. Example 2819 Here we did an Email/query to search for any email in the account 2820 containing the word "foo", now we are fetching the search snippets 2821 for some of the ids that were returned in the results: 2823 [ 2824 "SearchSnippet/get", 2825 { 2826 "accountId": "ue150411c", 2827 "filter": { 2828 "text": "foo" 2829 }, 2830 "emailIds": [ 2831 "M44200ec123de277c0c1ce69c", 2832 "M7bcbcb0b58d7729686e83d99", 2833 "M28d12783a0969584b6deaac0", 2834 ... 2835 ] 2836 }, 2837 "tag-0" 2838 ] 2840 Example response: 2842 [ 2843 "SearchSnippet/get", { 2844 "accountId": "ue150411c", 2845 "filter": { 2846 "text": "foo" 2847 }, 2848 "list": [{ 2849 "emailId": "M44200ec123de277c0c1ce69c" 2850 "subject": null, 2851 "preview": null 2852 }, { 2853 "emailId": "M7bcbcb0b58d7729686e83d99", 2854 "subject": "The Foosball competition", 2855 "preview": "...year the foosball competition will be held in the Stadium de ..." 2856 }, { 2857 "emailId": "M28d12783a0969584b6deaac0", 2858 "subject": null, 2859 "preview": "...mail Foo/changes results often return current-state-minus-1 rather than new..." 2860 }, 2861 ... 2862 ], 2863 "notFound": null 2864 }, 2865 "0" 2866 ] 2868 8. Vacation response 2870 The *VacationResponse* object represents the state of vacation- 2871 response related settings for an account. It has the following 2872 properties: 2874 o *id*: "String" (immutable) The id of the object. There is only 2875 ever one vacation response object, and its id is ""singleton"". 2877 o *isEnabled* "Boolean" Should a vacation response be sent if an 2878 email arrives between the _fromDate_ and _toDate_? 2880 o *fromDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time 2881 in UTC after which emails that arrive should receive the user's 2882 vacation response. If "null", the vacation response is effective 2883 immediately. 2885 o *toDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time 2886 in UTC after which emails that arrive should no longer receive the 2887 user's vacation response. If "null", the vacation response is 2888 effective indefinitely. 2890 o *subject*: "String|null" The subject that will be used by the 2891 message sent in response to emails when the vacation response is 2892 enabled. If null, an appropriate subject SHOULD be set by the 2893 server. 2895 o *textBody*: "String|null" The plain text part of the message to 2896 send in response to emails when the vacation response is enabled. 2897 If this is "null", when the vacation message is sent a plain-text 2898 body part SHOULD be generated from the _htmlBody_ but the server 2899 MAY choose to send the response as HTML only. 2901 o *htmlBody*: "String|null" The HTML message to send in response to 2902 emails when the vacation response is enabled. If this is "null", 2903 when the vacation message is sent an HTML body part MAY be 2904 generated from the _textBody_, or the server MAY choose to send 2905 the response as plain-text only. 2907 The following JMAP methods are supported: 2909 8.1. VacationResponse/get 2911 Standard _/get_ method. 2913 There MUST only be exactly one VacationResponse object in an account. 2914 It MUST have the id ""singleton"". 2916 8.2. VacationResponse/set 2918 Standard _/set_ method. 2920 9. Security considerations 2922 All security considerations of JMAP {TODO: insert RFC ref} apply to 2923 this specification. 2925 9.1. EmailBodyPart value 2927 Service providers typically perform security filtering on incoming 2928 email and it's important the detection of content-type and charset 2929 for the security filter aligns with the heuristics performed by JMAP 2930 servers. Servers that apply heuristics to determine the content-type 2931 or charset for _EmailBodyValue_ SHOULD document the heuristics and 2932 provide a mechanism to turn them off in the event they are misaligned 2933 with the security filter used at a particular mailbox host. 2935 Automatic conversion of charsets that allow hidden channels for ASCII 2936 text, such as UTF-7, have been problematic for security filters in 2937 the past so server implementations can mitigate this risk by having 2938 such conversions off-by-default and/or separately configurable. 2940 To allow the client to restrict the volume of data it can receive in 2941 response to a request, a maximum length may be requested for the data 2942 returned for a textual body part. However, truncating the data may 2943 change the semantic meaning, for example truncating a URL changes its 2944 location. Servers that scan for links to malicious sites should take 2945 care to either ensure truncation is not at a semantically significant 2946 point, or to rescan the truncated value for malicious content before 2947 returning it. 2949 9.2. HTML email display 2951 HTML message bodies provide richer formatting for emails but present 2952 a number of security challenges, especially when embedded in a 2953 webmail context in combination with interface HTML. Clients that 2954 render HTML email should make careful consideration of the potential 2955 risks, including: 2957 o Embedded JavaScript can rewrite the email to change its content on 2958 subsequent opening, allowing users to be mislead. In webmail 2959 systems, if run in the same origin as the interface it can access 2960 and exfiltrate all private data accessible to the user, including 2961 all other emails and potentially contacts, calendar events, 2962 settings, and credentials. It can also rewrite the interface to 2963 undetectably phish passwords. A compromise is likely to be 2964 persistent, not just for the duration of page load, due to 2965 exfiltration of session credentials or installation of a service 2966 worker that can intercept all subsequent network requests (this 2967 however would only be possible if blob downloads are also 2968 available on the same origin, and the service worker script is 2969 attached to the message). 2971 o HTML documents may load content directly from the internet, rather 2972 than just referencing attached resources. For example you may 2973 have an "" tag with an external "src" attribute. This may 2974 leak to the sender when a message is opened, as well as the IP 2975 address of the recipient. Cookies may also be sent and set by the 2976 server, allowing tracking between different emails and even 2977 website visits and advertising profiles. 2979 o In webmail systems, CSS can break the layout or create phishing 2980 vulnerabilities. For example, the use of "position:fixed" can 2981 allow an email to draw content outside of its normal bounds, 2982 potentially clickjacking a real interface element. 2984 o If in a webmail context and not inside a separate frame, any 2985 styles defined in CSS rules will apply to interface elements as 2986 well if the selector matches, allowing the interface to be 2987 modified. Similarly, any interface styles that match elements in 2988 the email will alter their appearance, potentially breaking the 2989 layout of the email. 2991 o The link text in HTML has no necessary correlation with the actual 2992 target of the link, which can be used to make phishing attacks 2993 more convincing. 2995 o Links opened from an email or embedded external content may leak 2996 private info in the "Referer" header sent by default in most 2997 systems. 2999 o Forms can be used to mimic login boxes, providing a potent 3000 phishing vector if allowed to submit directly from the email 3001 display. 3003 There are a number of ways clients can mitigate these issues, and a 3004 defence-in-depth approach that uses a combination of techniques will 3005 provide the strongest security. 3007 o HTML can be filtered before rendering, stripping potentially 3008 malicious content. Sanitizing HTML correctly is tricky, and 3009 implementers are strongly recommended to use a well-tested library 3010 with a carefully vetted whitelist-only approach. New features 3011 with unexpected security characteristics may be added to HTML 3012 rendering engines in the future; a blacklist approach is likely to 3013 result in security issues. 3015 Subtle differences in parsing of HTML can introduce security flaws: 3016 to filter with 100% accurately you need to use the same parser when 3017 sanitizing that the HTML rendering engine will use. 3019 o Encapsulating the message in an "