idnits 2.17.1 draft-ietf-jmap-mail-14.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 is 1 instance of too long lines in the document, the longest one being 120 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 (January 17, 2019) is 1926 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 4108 -- Looks like a reference, but probably isn't: '2' on line 4111 -- Looks like a reference, but probably isn't: '3' on line 4114 -- Looks like a reference, but probably isn't: '4' on line 4116 -- Possible downref: Non-RFC (?) normative reference: ref. 'HTML' == Outdated reference: A later version (-17) exists of draft-ietf-jmap-core-12 -- Obsolete informational reference (is this intentional?): RFC 3501 (Obsoleted by RFC 9051) Summary: 1 error (**), 0 flaws (~~), 3 warnings (==), 10 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) C. Newman 5 Intended status: Standards Track Oracle 6 Expires: July 21, 2019 January 17, 2019 8 JMAP for Mail 9 draft-ietf-jmap-mail-14 11 Abstract 13 This document specifies a data model for synchronising email data 14 with a server using JMAP. Clients can use this to efficiently 15 search, access, organise and send messages, and get pushed 16 notifications for fast resynchronisation when new messages are 17 delivered or a change is made in another client. 19 Status of This Memo 21 This Internet-Draft is submitted in full conformance with the 22 provisions of BCP 78 and BCP 79. 24 Internet-Drafts are working documents of the Internet Engineering 25 Task Force (IETF). Note that other groups may also distribute 26 working documents as Internet-Drafts. The list of current Internet- 27 Drafts is at https://datatracker.ietf.org/drafts/current/. 29 Internet-Drafts are draft documents valid for a maximum of six months 30 and may be updated, replaced, or obsoleted by other documents at any 31 time. It is inappropriate to use Internet-Drafts as reference 32 material or to cite them other than as "work in progress." 34 This Internet-Draft will expire on July 21, 2019. 36 Copyright Notice 38 Copyright (c) 2019 IETF Trust and the persons identified as the 39 document authors. All rights reserved. 41 This document is subject to BCP 78 and the IETF Trust's Legal 42 Provisions Relating to IETF Documents 43 (https://trustee.ietf.org/license-info) in effect on the date of 44 publication of this document. Please review these documents 45 carefully, as they describe your rights and restrictions with respect 46 to this document. Code Components extracted from this document must 47 include Simplified BSD License text as described in Section 4.e of 48 the Trust Legal Provisions and are provided without warranty as 49 described in the Simplified BSD License. 51 Table of Contents 53 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 4 54 1.1. Notational conventions . . . . . . . . . . . . . . . . . 4 55 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 56 1.3. Additions to the capabilities object . . . . . . . . . . 4 57 1.3.1. urn:ietf:params:jmap:mail . . . . . . . . . . . . . . 4 58 1.3.2. urn:ietf:params:jmap:submission . . . . . . . . . . . 5 59 1.3.3. urn:ietf:params:jmap:vacationresponse . . . . . . . . 6 60 1.4. Data type support in different accounts . . . . . . . . . 6 61 1.5. Push . . . . . . . . . . . . . . . . . . . . . . . . . . 7 62 1.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 7 63 1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 64 2. Mailboxes . . . . . . . . . . . . . . . . . . . . . . . . . . 7 65 2.1. Mailbox/get . . . . . . . . . . . . . . . . . . . . . . . 11 66 2.2. Mailbox/changes . . . . . . . . . . . . . . . . . . . . . 11 67 2.3. Mailbox/query . . . . . . . . . . . . . . . . . . . . . . 11 68 2.4. Mailbox/queryChanges . . . . . . . . . . . . . . . . . . 12 69 2.5. Mailbox/set . . . . . . . . . . . . . . . . . . . . . . . 12 70 2.6. Example . . . . . . . . . . . . . . . . . . . . . . . . . 13 71 3. Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 72 3.1. Thread/get . . . . . . . . . . . . . . . . . . . . . . . 18 73 3.1.1. Example . . . . . . . . . . . . . . . . . . . . . . . 18 74 3.2. Thread/changes . . . . . . . . . . . . . . . . . . . . . 18 75 4. Emails . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 76 4.1. Properties of the Email object . . . . . . . . . . . . . 19 77 4.1.1. Metadata . . . . . . . . . . . . . . . . . . . . . . 20 78 4.1.2. Header fields parsed forms . . . . . . . . . . . . . 22 79 4.1.3. Header fields properties . . . . . . . . . . . . . . 27 80 4.1.4. Body parts . . . . . . . . . . . . . . . . . . . . . 29 81 4.2. Email/get . . . . . . . . . . . . . . . . . . . . . . . . 35 82 4.2.1. Example . . . . . . . . . . . . . . . . . . . . . . . 37 83 4.3. Email/changes . . . . . . . . . . . . . . . . . . . . . . 38 84 4.4. Email/query . . . . . . . . . . . . . . . . . . . . . . . 39 85 4.4.1. Filtering . . . . . . . . . . . . . . . . . . . . . . 39 86 4.4.2. Sorting . . . . . . . . . . . . . . . . . . . . . . . 41 87 4.4.3. Thread collapsing . . . . . . . . . . . . . . . . . . 43 88 4.5. Email/queryChanges . . . . . . . . . . . . . . . . . . . 43 89 4.6. Email/set . . . . . . . . . . . . . . . . . . . . . . . . 43 90 4.7. Email/copy . . . . . . . . . . . . . . . . . . . . . . . 46 91 4.8. Email/import . . . . . . . . . . . . . . . . . . . . . . 46 92 4.9. Email/parse . . . . . . . . . . . . . . . . . . . . . . . 48 93 4.10. Examples . . . . . . . . . . . . . . . . . . . . . . . . 50 94 5. Search snippets . . . . . . . . . . . . . . . . . . . . . . . 57 95 5.1. SearchSnippet/get . . . . . . . . . . . . . . . . . . . . 58 96 5.2. Example . . . . . . . . . . . . . . . . . . . . . . . . . 59 97 6. Identities . . . . . . . . . . . . . . . . . . . . . . . . . 60 98 6.1. Identity/get . . . . . . . . . . . . . . . . . . . . . . 61 99 6.2. Identity/changes . . . . . . . . . . . . . . . . . . . . 61 100 6.3. Identity/set . . . . . . . . . . . . . . . . . . . . . . 61 101 6.4. Example . . . . . . . . . . . . . . . . . . . . . . . . . 62 102 7. Email submission . . . . . . . . . . . . . . . . . . . . . . 62 103 7.1. EmailSubmission/get . . . . . . . . . . . . . . . . . . . 67 104 7.2. EmailSubmission/changes . . . . . . . . . . . . . . . . . 67 105 7.3. EmailSubmission/query . . . . . . . . . . . . . . . . . . 67 106 7.4. EmailSubmission/queryChanges . . . . . . . . . . . . . . 68 107 7.5. EmailSubmission/set . . . . . . . . . . . . . . . . . . . 68 108 7.5.1. Example . . . . . . . . . . . . . . . . . . . . . . . 70 109 8. Vacation response . . . . . . . . . . . . . . . . . . . . . . 73 110 8.1. VacationResponse/get . . . . . . . . . . . . . . . . . . 74 111 8.2. VacationResponse/set . . . . . . . . . . . . . . . . . . 74 112 9. Security considerations . . . . . . . . . . . . . . . . . . . 74 113 9.1. EmailBodyPart value . . . . . . . . . . . . . . . . . . . 74 114 9.2. HTML email display . . . . . . . . . . . . . . . . . . . 74 115 9.3. Email submission . . . . . . . . . . . . . . . . . . . . 77 116 10. IANA considerations . . . . . . . . . . . . . . . . . . . . . 77 117 10.1. JMAP capability registration for "mail" . . . . . . . . 77 118 10.2. JMAP capability registration for "submission" . . . . . 78 119 10.3. JMAP capability registration for "vacationresponse" . . 78 120 10.4. IMAP and JMAP keywords registry . . . . . . . . . . . . 78 121 10.4.1. Registration of JMAP keyword '$draft' . . . . . . . 79 122 10.4.2. Registration of JMAP keyword '$seen' . . . . . . . . 80 123 10.4.3. Registration of JMAP keyword '$flagged' . . . . . . 81 124 10.4.4. Registration of JMAP keyword '$answered' . . . . . . 81 125 10.4.5. Registration of '$recent' keyword . . . . . . . . . 82 126 10.5. Registration of "inbox" role in . . . . . . . . . . . . 83 127 10.6. JMAP Error Codes registry . . . . . . . . . . . . . . . 83 128 10.6.1. mailboxHasChild . . . . . . . . . . . . . . . . . . 83 129 10.6.2. mailboxHasEmail . . . . . . . . . . . . . . . . . . 83 130 10.6.3. blobNotFound . . . . . . . . . . . . . . . . . . . . 84 131 10.6.4. tooManyKeywords . . . . . . . . . . . . . . . . . . 84 132 10.6.5. tooManyMailboxes . . . . . . . . . . . . . . . . . . 84 133 10.6.6. invalidEmail . . . . . . . . . . . . . . . . . . . . 84 134 10.6.7. tooManyRecipients . . . . . . . . . . . . . . . . . 84 135 10.6.8. noRecipients . . . . . . . . . . . . . . . . . . . . 85 136 10.6.9. invalidRecipients . . . . . . . . . . . . . . . . . 85 137 10.6.10. forbiddenMailFrom . . . . . . . . . . . . . . . . . 85 138 10.6.11. forbiddenFrom . . . . . . . . . . . . . . . . . . . 85 139 10.6.12. forbiddenToSend . . . . . . . . . . . . . . . . . . 85 140 11. References . . . . . . . . . . . . . . . . . . . . . . . . . 86 141 11.1. Normative References . . . . . . . . . . . . . . . . . . 86 142 11.2. Informative References . . . . . . . . . . . . . . . . . 89 143 11.3. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 89 145 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 90 147 1. Introduction 149 JMAP ([I-D.ietf-jmap-core]) is a generic protocol for synchronising 150 data, such as mail, calendars or contacts, between a client and a 151 server. It is optimised for mobile and web environments, and aims to 152 provide a consistent interface to different data types. 154 This specification defines a data model for mail over JMAP. 156 1.1. Notational conventions 158 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 159 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 160 document are to be interpreted as described in [RFC2119]. 162 Type signatures, examples and property descriptions in this document 163 follow the conventions established in section 1.1 of 164 [I-D.ietf-jmap-core]. Data types defined in the core specification 165 are also used in this document. 167 1.2. Terminology 169 The same terminology is used in this document as in the core JMAP 170 specification. 172 1.3. Additions to the capabilities object 174 The capabilities object is returned as part of the standard JMAP 175 Session object; see [I-D.ietf-jmap-core], section 2. 177 This document defines three additional capability URIs. 179 1.3.1. urn:ietf:params:jmap:mail 181 This represents support for the Mailbox, Thread, Email, and 182 SearchSnippet data types and associated API methods. The value of 183 this property is an object which MUST contain the following 184 information on server capabilities: 186 o *maxMailboxesPerEmail*: "PositiveInt|null" The maximum number of 187 mailboxes that can be can assigned to a single email. This MUST 188 be an integer >= 1, or "null" for no limit (or rather, the limit 189 is always the number of mailboxes in the account). 191 o *maxMailboxDepth*: "PositiveInt|null" The maximum depth of the 192 mailbox hierarchy (i.e. one more than the maximum number of 193 ancestors a mailbox may have), or "null" for no limit. 195 o *maxSizeMailboxName*: "PositiveInt" The maximum length, in (UTF-8) 196 octets, allowed for the name of a mailbox. This MUST be at least 197 100, although it is recommended servers allow more. 199 o *maxSizeAttachmentsPerEmail*: "PositiveInt" The maximum total size 200 of attachments, in octets, allowed for a single email. A server 201 MAY still reject import or creation of emails with a lower 202 attachment size total (for example, if the body includes several 203 megabytes of text, causing the size of the encoded MIME structure 204 to be over some server-defined limit). Note, this limit is for 205 the sum of unencoded attachment sizes. Users are generally not 206 knowledgeable about encoding overhead etc., nor should they need 207 to be, so marketing and help materials normally tell them the "max 208 size attachments". This is the unencoded size they see on their 209 hard drive, and so this capability matches that and allows the 210 client to consistently enforce what the user understands as the 211 limit. The server may separately have a limit for the total size 212 of the RFC5322 message, which will have attachments Base64 encoded 213 and message headers and bodies too. For example, suppose the 214 server advertises "maxSizeAttachmentsPerEmail: 50000000" (50 MB). 215 The enforced server limit may be for an RFC5322 size of 70000000 216 octets (70 MB). Even with Base64 encoding and a 2 MB HTML body, 217 50 MB attachments would fit under this limit. 219 o *emailsListSortOptions*: "String[]" A list of all the email 220 properties the server supports sorting by. This MAY include 221 properties the client does not recognise (for example custom 222 properties specified in a vendor extension). Clients MUST ignore 223 any unknown properties in the list. 225 1.3.2. urn:ietf:params:jmap:submission 227 This represents support for the Identity and MessageSubmission data 228 types and associated API methods. The value of this property is an 229 object which MUST contain the following information on server 230 capabilities: 232 o *maxDelayedSend*: "PositiveInt" The number in seconds of the 233 maximum delay the server supports in sending (see the 234 EmailSubmission object description). This is "0" if the server 235 does not support delayed send. 237 o *submissionExtensions*: "String[String[]]" A JMAP implementation 238 that talks to a Submission [RFC6409] server SHOULD have a 239 configuration setting that allows an administrator to expose a new 240 submission EHLO capability in this field. This allows a JMAP 241 server to gain access to a new submission extension without code 242 changes. By default, the JMAP server should hide EHLO 243 capabilities that are to do with the transport mechanism and thus 244 are only relevant to the JMAP server (for example PIPELINING, 245 CHUNKING, or STARTTLS). Each key in the object is the _ehlo- 246 name_, and the value is a list of _ehlo-args_. Examples of 247 Submission extensions to include: 249 * FUTURERELEASE ([RFC4865]) 251 * SIZE ([RFC1870]) 253 * DSN ([RFC3461]) 255 * DELIVERYBY ([RFC2852]) 257 * MT-PRIORITY ([RFC6710]) 259 A JMAP server MAY advertise an extension and implement the 260 semantics of that extension locally on the JMAP server even if a 261 submission server used by JMAP doesn't implement it. The full 262 IANA registry of submission extensions can be found at 263 . 266 1.3.3. urn:ietf:params:jmap:vacationresponse 268 This represents support for the VacationResponse data type and 269 associated API methods. The value of this property is an empty 270 object. 272 1.4. Data type support in different accounts 274 The server MUST include the appropriate capability strings in the 275 _hasDataFor_ property of any account with which the user may use the 276 data types represented by that URI. Supported data types may differ 277 between accounts the user has access to. For example, in the user's 278 personal account they may have access to all three sets of data, but 279 in a shared account they may only have data for 280 "urn:ietf:params:jmap:mail". This means they can access 281 Mailbox/Thread/Email data in the shared account but are not allowed 282 to send as that account (and so do not have access to Identity/ 283 MessageSubmission objects) or view/set its vacation response. 285 1.5. Push 287 Servers MUST support the standard JMAP push mechanisms to receive 288 notifications when the state changes for any of the types defined in 289 this specification. 291 In addition, servers MUST support pushing state changes for a type 292 called "EmailDelivery". There are no methods to act on this type; it 293 only exists as part of the push mechanism. The state string for this 294 MUST change whenever a new Email is added to the store, but SHOULD 295 NOT change upon any other change to the Email objects, for example if 296 one is marked as read or deleted. 298 Clients in battery constrained environments may wish to delay 299 fetching changes initiated by the user, but fetch new messages 300 immediately so they can notify the user. To do this, they can 301 register for pushes for the EmailDelivery type rather than the Email 302 type (defined in section 4). 304 1.5.1. Example 306 The client has registered for push notifications (see 307 [I-D.ietf-jmap-core]) just for the "EmailDelivery" type. The user 308 marks an email as read on another device, causing the state string 309 for the "Email" type to change, however as nothing new was added to 310 the store the "EmailDelivery" state does not change and nothing is 311 pushed to the client. A new message arrives in the user's inbox, 312 again causing the "Email" state to change. This time the 313 "EmailDelivery" state also changes, and a StateChange object is 314 pushed to the client with the new state string. The client may then 315 resync to fetch the new message immediately. 317 1.6. Ids 319 If a JMAP Mail server also provides an IMAP interface to the data and 320 supports [RFC8474] IMAP Extension for Object Identifiers, the ids 321 SHOULD be the same for mailbox, thread, and email objects in JMAP. 323 2. Mailboxes 325 A mailbox represents a named set of emails. This is the primary 326 mechanism for organising emails within an account. It is analogous 327 to a folder or a label in other systems. A mailbox may perform a 328 certain role in the system; see below for more details. 330 For compatibility with IMAP, an email MUST belong to one or more 331 mailboxes. The email id does not change if the email changes 332 mailboxes. 334 A *Mailbox* object has the following properties: 336 o *id*: "Id" (immutable; server-set) The id of the mailbox. 338 o *name*: "String" User-visible name for the mailbox, e.g. "Inbox". 339 This may be any Net-Unicode string ([RFC5198]) of at least 1 340 character in length, subject to the maximum size given in the 341 capability object. There MUST NOT be two sibling mailboxes with 342 both the same parent and the same name. Servers MAY reject names 343 that violate server policy (e.g., names containing slash (/) or 344 control characters). 346 o *parentId*: "Id|null" (default: null) The mailbox id for the 347 parent of this mailbox, or "null" if this mailbox is at the top 348 level. Mailboxes form acyclic graphs (forests) directed by the 349 child-to-parent relationship. There MUST NOT be a loop. 351 o *role*: "String|null" (default: null) Identifies mailboxes that 352 have a particular common purpose (e.g. the "inbox"), regardless of 353 the _name_ (which may be localised). This value is shared with 354 IMAP (exposed in IMAP via the [RFC6154] SPECIAL-USE extension). 355 However, unlike in IMAP, a mailbox may only have a single role, 356 and no two mailboxes in the same account may have the same role. 357 The value MUST be one of the mailbox attribute names listed in the 358 IANA IMAP Mailbox Name Attributes Registry [1], as established in 359 [RFC8457], converted to lower-case. New roles may be established 360 here in the future. An account is not required to have mailboxes 361 with any particular roles. 363 o *sortOrder*: "PositiveInt" (default: 0) Defines the sort order of 364 mailboxes when presented in the client's UI, so it is consistent 365 between devices. The number MUST be an integer in the range 0 <= 366 sortOrder < 2^31. A mailbox with a lower order should be 367 displayed before a mailbox with a higher order (that has the same 368 parent) in any mailbox listing in the client's UI. Mailboxes with 369 equal order SHOULD be sorted in alphabetical order by name. The 370 sorting SHOULD take into account locale-specific character order 371 convention. 373 o *totalEmails*: "PositiveInt" (server-set) The number of emails in 374 this mailbox. 376 o *unreadEmails*: "PositiveInt" (server-set) The number of emails in 377 this mailbox that have neither the "$seen" keyword nor the 378 "$draft" keyword. 380 o *totalThreads*: "PositiveInt" (server-set) The number of threads 381 where at least one email in the thread is in this mailbox. 383 o *unreadThreads*: "PositiveInt" (server-set) An indication of the 384 number of "unread" threads in the mailbox. This may be presented 385 by the client as a badge or marker associated with the mailbox. 386 For compatibility with existing implementations, the way "unread 387 threads" is determined is not mandated in this document. The 388 simplest solution to implement is simply the number of threads 389 where at least one email in the thread is both in this mailbox and 390 has neither the "$seen" nor "$draft" keywords. However, a quality 391 implementation will return the number of unread items the user 392 would see if they opened that mailbox. A thread is shown as 393 unread if it contains any unread messages that will be displayed 394 when the thread is opened. Therefore "unreadThreads" should be 395 the number of threads where at least one email in the thread has 396 neither the "$seen" nor the "$draft" keyword AND at least one 397 email in the thread is in this mailbox. Note, the unread email 398 does not need to be the one in this mailbox. In addition, the 399 Trash mailbox (that is a mailbox whose "role" is "trash") is 400 treated specially: 402 1. Emails that are *only* in the Trash (and no other mailbox) are 403 ignored when calculating the "unreadThreads" count of other 404 mailboxes. 406 2. Emails that are *not* in the Trash are ignored when 407 calculating the "unreadThreads" count for the Trash mailbox. 409 The result of this is that emails in the Trash are treated as 410 though they are in a separate thread for the purposes of unread 411 counts. It is expected that clients will hide emails in the Trash 412 when viewing a thread in another mailbox and vice versa. This 413 allows you to delete a single email to the Trash out of a thread. 414 So for example, suppose you have an account where the entire 415 contents is a single thread with 2 emails: an unread email in the 416 Trash and a read email in the Inbox. The "unreadThreads" count 417 would be "1" for the Trash and "0" for the Inbox. 419 o *myRights*: "MailboxRights" (server-set) The set of rights (ACLs) 420 the user has in relation to this mailbox. These are backwards 421 compatible with IMAP ACLs, as defined in [RFC4314]. A 422 _MailboxRights_ object has the following properties: 424 * *mayReadItems*: "Boolean" If true, the user may use this 425 mailbox as part of a filter in a _Email/query_ call and the 426 mailbox may be included in the _mailboxIds_ set of _Email_ 427 objects. If a sub-mailbox is shared but not the parent 428 mailbox, this may be "false". Corresponds to IMAP ACLs "lr". 430 * *mayAddItems*: "Boolean" The user may add mail to this mailbox 431 (by either creating a new email or moving an existing one). 432 Corresponds to IMAP ACL "i". 434 * *mayRemoveItems*: "Boolean" The user may remove mail from this 435 mailbox (by either changing the mailboxes of an email or 436 deleting it). Corresponds to IMAP ACLs "te". 438 * *maySetSeen*: "Boolean" The user may add or remove the "$seen" 439 keyword to/from an email. If an email belongs to multiple 440 mailboxes, the user may only modify "$seen" if *all* of the 441 mailboxes have this permission. Corresponds to IMAP ACL "s". 443 * *maySetKeywords*: "Boolean" The user may add or remove any 444 keyword _other than_ "$seen" to/from an email. If an email 445 belongs to multiple mailboxes, the user may only modify 446 keywords if *all* of the mailboxes have this permission. 447 Corresponds to IMAP ACL "w". 449 * *mayCreateChild*: "Boolean" The user may create a mailbox with 450 this mailbox as its parent. Corresponds to IMAP ACL "k". 452 * *mayRename*: "Boolean" The user may rename the mailbox or make 453 it a child of another mailbox. Corresponds to IMAP ACL "x". 455 * *mayDelete*: "Boolean" The user may delete the mailbox itself. 456 Corresponds to IMAP ACL "x". 458 * *maySubmit*: "Boolean" Messages may be submitted directly to 459 this mailbox. Corresponds to IMAP ACL "p". 461 o *isSubscribed*: "Boolean" Has the user indicated they wish to see 462 this mailbox in their client? This SHOULD default to "false" for 463 mailboxes in shared accounts the user has access to, and "true" 464 for any new mailboxes created by the user themself. This MUST be 465 stored separately per-user where multiple users have access to a 466 shared mailbox. A user may have permission to access a large 467 number of shared accounts, or a shared account with a very large 468 set of mailboxes, but only be interested in the contents of a few 469 of these. Clients may choose only to display mailboxes to the 470 user that have the "isSubscribed" property set to "true", and 471 offer a separate UI to allow the user to see and subscribe/ 472 unsubscribe from the full set of mailboxes. However, clients MAY 473 choose to ignore this property, either entirely for ease of 474 implementation, or just for the primary account (which is normally 475 the user's own, rather than a shared account). This property 476 corresponds to IMAP ([RFC3501]) mailbox subscriptions. 478 For IMAP compatibility, an email in both the Trash and another 479 mailbox SHOULD be treated by the client as existing in both places 480 (i.e. when emptying the trash, the client SHOULD just remove the 481 Trash mailbox and leave it in the other mailbox). 483 The following JMAP methods are supported: 485 2.1. Mailbox/get 487 Standard "/get" method. The _ids_ argument may be "null" to fetch 488 all at once. 490 2.2. Mailbox/changes 492 Standard "/changes" method, but with one extra argument to the 493 response: 495 o *updatedProperties*: "String[]|null" If only the mailbox counts 496 (unread/total emails/threads) have changed since the old state, 497 this will be the list of properties that may have changed, i.e. 498 "["totalEmails", "unreadEmails", "totalThreads", 499 "unreadThreads"]". If the server is unable to tell if only counts 500 have changed, it MUST just be "null". 502 Since counts frequently change but other properties are generally 503 only changed rarely, the server can help the client optimise data 504 transfer by keeping track of changes to email/thread counts 505 separately to other state changes. The _updatedProperties_ array may 506 be used directly via a back-reference in a subsequent Mailbox/get 507 call in the same single request so only these properties are returned 508 if nothing else has changed. 510 2.3. Mailbox/query 512 Standard "/query" method, but with the following additional argument: 514 o *sortAsTree*: "Boolean" (default: false) If "true", when sorting 515 the query results and comparing two mailboxes a and b: 517 * If a is an ancestor of b, it always comes first regardless of 518 the _sort_ comparators. Similarly, if a is descendant of b, 519 then b always comes first. 521 * Otherwise, if a and b do not share a _parentId_, find the 522 nearest ancestors of each that do have the same _parentId_ and 523 compare the sort properties on those mailboxes instead. 525 The result of this is that the mailboxes are sorted as a tree 526 according to the parentId properties, with each set of children 527 with a common parent sorted according to the standard sort 528 comparators. 530 o *filterAsTree*: "Boolean" (default: false) If "true", a mailbox is 531 only included in the query if all its ancestors are also included 532 in the query according to the filter. 534 A *FilterCondition* object has the following properties, any of which 535 may be omitted: 537 o *parentId*: "Id|null" The Mailbox _parentId_ property must match 538 the given value exactly. 540 o *name*: "String" The Mailbox _name_ property contains the given 541 string. 543 o *role*: "String|null" The Mailbox _role_ property must match the 544 given value exactly. 546 o *hasAnyRole*: "Boolean" If "true", a Mailbox matches if it has any 547 non-"null" value for its _role_ property. 549 o *isSubscribed*: "Boolean" The "isSubscribed" property of the 550 mailbox must be identical to the value given to match the 551 condition. 553 A Mailbox object matches the filter if and only if all of the given 554 conditions match. If zero properties are specified, it is 555 automatically "true" for all objects. 557 The following properties MUST be supported for sorting: 559 o "sortOrder" 561 o "name" 563 2.4. Mailbox/queryChanges 565 Standard "/queryChanges" method. 567 2.5. Mailbox/set 569 Standard "/set" method, but with the following additional argument: 571 o *onDestroyRemoveMessages*: "Boolean" (default: false) If "false", 572 any attempt to destroy a mailbox that still has messages in it 573 will be rejected with a "mailboxHasEmail" SetError. If "true", 574 any messages that were in the mailbox will be removed from it, and 575 if in no other mailboxes will be destroyed when the mailbox is 576 destroyed. 578 The following extra _SetError_ types are defined: 580 For *destroy*: 582 o "mailboxHasChild": The mailbox still has at least one child 583 mailbox. The client MUST remove these before it can delete the 584 parent mailbox. 586 o "mailboxHasEmail": The mailbox has at least one message assigned 587 to it and the _onDestroyRemoveMessages_ argument was "false". 589 2.6. Example 591 Fetching all mailboxes in an account: 593 [[ "Mailbox/get", { 594 "accountId": "u33084183", 595 "ids": null 596 }, "0" ]] 598 And response: 600 [[ "Mailbox/get", { 601 "accountId": "u33084183", 602 "state": "78540", 603 "list": [{ 604 "id": "23cfa8094c0f41e6", 605 "name": "Inbox", 606 "parentId": null, 607 "role": "inbox", 608 "sortOrder": 10, 609 "totalEmails": 16307, 610 "unreadEmails": 13905, 611 "totalThreads": 5833, 612 "unreadThreads": 5128, 613 "myRights": { 614 "mayAddItems": true, 615 "mayRename": false, 616 "maySubmit": true, 617 "mayDelete": false, 618 "maySetKeywords": true, 619 "mayRemoveItems": true, 620 "mayCreateChild": true, 621 "maySetSeen": true, 622 "mayReadItems": true 623 }, 624 "isSubscribed": true 625 }, { 626 "id": "674cc24095db49ce", 627 "name": "Important mail", 628 ... 629 }, ... ], 630 "notFound": [] 631 }, "0" ]] 633 Now suppose a message is marked read and we get a push update that 634 the Mailbox state has changed. You might fetch the updates like 635 this: 637 [[ "Mailbox/changes", { 638 "accountId": "u33084183", 639 "sinceState": "78540" 640 }, "0" ], 641 [ "Mailbox/get", { 642 "accountId": "u33084183", 643 "#ids": { 644 "resultOf": "0", 645 "name": "Mailbox/changes", 646 "path": "/created" 647 } 648 }, "1" ], 649 [ "Mailbox/get", { 650 "accountId": "u33084183", 651 "#ids": { 652 "resultOf": "0", 653 "name": "Mailbox/changes", 654 "path": "/updated" 655 }, 656 "#properties": { 657 "resultOf": "0", 658 "name": "Mailbox/changes", 659 "path": "/updatedProperties" 660 } 661 }, "2" ]] 663 This fetches the list of ids for created/updated/destroyed mailboxes, 664 then using back-references fetches the data for just the created/ 665 updated mailboxes in the same request. The response may look 666 something like this: 668 [[ "Mailbox/changes", { 669 "accountId": "u33084183", 670 "oldState": "78541", 671 "newState": "78542", 672 "hasMoreChanges": false, 673 "updatedProperties": [ 674 "totalEmails", "unreadEmails", 675 "totalThreads", "unreadThreads" 676 ], 677 "created": [], 678 "updated": ["23cfa8094c0f41e6"], 679 "destroyed": [] 680 }, "0" ], 681 [ "Mailbox/get", { 682 "accountId": "u33084183", 683 "state": "78542", 684 "list": [], 685 "notFound": [] 686 }, "1" ], 687 [ "Mailbox/get", { 688 "accountId": "u33084183", 689 "state": "78542", 690 "list": [{ 691 "id": "23cfa8094c0f41e6", 692 "totalEmails": 16307, 693 "unreadEmails": 13903, 694 "totalThreads": 5833, 695 "unreadThreads": 5127 696 }], 697 "notFound": [] 698 }, "2" ]] 700 Here's an example where we try to rename one mailbox and destroy 701 another: 703 [[ "Mailbox/set", { 704 "accountId": "u33084183", 705 "ifInState": "78542", 706 "update": { 707 "674cc24095db49ce": { 708 "name": "Maybe important mail" 709 } 710 }, 711 "destroy": [ "23cfa8094c0f41e6" ] 712 }, "0" ]] 714 Suppose the rename succeeds, but we don't have permission to destroy 715 the mailbox we tried to destroy, we might get back: 717 [[ "Mailbox/set", { 718 "accountId": "u33084183", 719 "oldState": "78542", 720 "newState": "78549", 721 "updated": { 722 "674cc24095db49ce": null 723 }, 724 "notDestroyed": { 725 "23cfa8094c0f41e6": { 726 "type": "forbidden" 727 } 728 } 729 }, "0" ]] 731 3. Threads 733 Replies are grouped together with the original message to form a 734 thread. In JMAP, a thread is simply a flat list of emails, ordered 735 by date. Every email MUST belong to a thread, even if it is the only 736 email in the thread. 738 The exact algorithm for determining whether two emails belong to the 739 same thread is not mandated in this spec to allow for compatibility 740 with different existing systems. For new implementations, it is 741 suggested that two messages belong in the same thread if both of the 742 following conditions apply: 744 1. An identical RFC5322 message id appears in both messages in any 745 of the Message-Id, In-Reply-To and References headers. 747 2. After stripping automatically added prefixes such as "Fwd:", 748 "Re:", "[List-Tag]" etc. and ignoring whitespace, the subjects 749 are the same. This avoids the situation where a person replies 750 to an old message as a convenient way of finding the right 751 recipient to send to, but changes the subject and starts a new 752 conversation. 754 If emails are delivered out of order for some reason, a user may 755 receive two emails in the same thread but without headers that 756 associate them with each other. The arrival of a third email in the 757 thread may provide the missing references to join them all together 758 into a single thread. Since the _threadId_ of an email is immutable, 759 if the server wishes to merge the threads, it MUST handle this by 760 deleting and reinserting (with a new email id) the emails that change 761 threadId. 763 A *Thread* object has the following properties: 765 o *id*: "Id" (immutable; server-set) The id of the thread. 767 o *emailIds*: "Id[]" (server-set) The ids of the emails in the 768 thread, sorted by the _receivedAt_ date of the email, oldest 769 first. If two emails have an identical date, the sort is server- 770 dependent but MUST be stable (sorting by id is recommended). 772 The following JMAP methods are supported: 774 3.1. Thread/get 776 Standard "/get" method. 778 3.1.1. Example 780 Request: 782 [[ "Thread/get", { 783 "accountId": "acme", 784 "ids": ["f123u4", "f41u44"] 785 }, "#1" ]] 787 with response: 789 [[ "Thread/get", { 790 "accountId": "acme", 791 "state": "f6a7e214", 792 "list": [ 793 { 794 "id": "f123u4", 795 "emailIds": [ "eaa623", "f782cbb"] 796 }, 797 { 798 "id": "f41u44", 799 "emailIds": [ "82cf7bb" ] 800 } 801 ], 802 "notFound": [] 803 }, "#1" ]] 805 3.2. Thread/changes 807 Standard "/changes" method. 809 4. Emails 811 The *Email* object is a representation of an [RFC5322] message, which 812 allows clients to avoid the complexities of MIME parsing, transfer 813 encoding and character encoding. 815 4.1. Properties of the Email object 817 Broadly, a message consists of two parts: a list of header fields, 818 then a body. The JMAP Email object provides a way to access the full 819 structure, or to use simplified properties and avoid some complexity 820 if this is sufficient for the client application. 822 While raw headers can be fetched and set, the vast majority of 823 clients should use an appropriate parsed form for each of the headers 824 it wants to process, as this allows it to avoid the complexities of 825 various encodings that are required in a valid RFC5322 message. 827 The body of a message is normally a MIME-encoded set of documents in 828 a tree structure. This may be arbitrarily nested, but the majority 829 of email clients present a flat model of an email body (normally 830 plain text or HTML), with a set of attachments. Flattening the MIME 831 structure to form this model can be difficult, and causes 832 inconsistency between clients. Therefore in addition to the 833 _bodyStructure_ property, which gives the full tree, the Email object 834 contains 3 alternate properties with flat lists of body parts: 836 o _textBody_/_htmlBody_: These provide a list of parts that should 837 be rendered sequentially as the "body" of the message. This is a 838 list rather than a single part as messages may have headers and/or 839 footers appended/prepended as separate parts as they are 840 transmitted, and some clients send text and images intended to be 841 displayed inline in the body (or even videos and sound clips) as 842 multiple parts rather than a single HTML part with referenced 843 images. 845 Because MIME allows for multiple representations of the same data 846 (using "multipart/alternative"), there is a textBody property (which 847 prefers a plain text representation) and an htmlBody property (which 848 prefers an HTML representation) to accommodate the two most common 849 client requirements. The same part may appear in both lists where 850 there is no alternative between the two. 852 o _attachments_: This provides a list of parts that should be 853 presented as "attachments" to the message. Some images may be 854 solely there for embedding within an HTML body part; clients may 855 wish to not present these as attachments in the user interface if 856 they are displaying the HTML with the embedded images directly. 858 Some parts may also be in htmlBody/textBody; again, clients may 859 wish to not present these as attachments in the user interface if 860 rendered as part of the body. 862 The _bodyValues_ property allows for clients to fetch the value of 863 text parts directly without having to do a second request for the 864 blob, and have the server handle decoding the charset into unicode. 865 This data is in a separate property rather than on the EmailBodyPart 866 object to avoid duplication of large amounts of data, as the same 867 part may be included twice if the client fetches more than one of 868 bodyStructure, textBody and htmlBody. 870 Due to the number of properties involved, the set of _Email_ 871 properties is specified over the following three sub-sections. 873 4.1.1. Metadata 875 These properties represent metadata about the [RFC5322] message, and 876 are not derived from parsing the message itself. 878 o *id*: "Id" (immutable; server-set) The id of the Email object. 879 Note, this is the JMAP object id, NOT the [RFC5322] Message-ID 880 header field value. 882 o *blobId*: "Id" (immutable; server-set) The id representing the raw 883 octets of the [RFC5322] message. This may be used to download the 884 raw original message, or to attach it directly to another Email 885 etc. 887 o *threadId*: "Id" (immutable; server-set) The id of the Thread to 888 which this Email belongs. 890 o *mailboxIds*: "Id[Boolean]" The set of Mailbox ids this email 891 belongs to. An email MUST belong to one or more mailboxes at all 892 times (until it is deleted). The set is represented as an object, 893 with each key being a _Mailbox id_. The value for each key in the 894 object MUST be "true". 896 o *keywords*: "String[Boolean]" (default: ) A set of keywords that 897 apply to the email. The set is represented as an object, with the 898 keys being the _keywords_. The value for each key in the object 899 MUST be "true". Keywords are shared with IMAP. The six system 900 keywords from IMAP are treated specially. The following four 901 keywords have their first character changed from "\" in IMAP to 902 "$" in JMAP and have particular semantic meaning: 904 * "$draft": The email is a draft the user is composing. 906 * "$seen": The email has been read. 908 * "$flagged": The email has been flagged for urgent/special 909 attention. 911 * "$answered": The email has been replied to. 913 The IMAP "\Recent" keyword is not exposed via JMAP. The IMAP 914 "\Deleted" keyword is also not present: IMAP uses a delete+expunge 915 model, which JMAP does not. Any message with the "\Deleted" 916 keyword MUST NOT be visible via JMAP (including as part of any 917 mailbox counts). Users may add arbitrary keywords to an email. 918 For compatibility with IMAP, a keyword is a case-insensitive 919 string of 1-255 characters in the ASCII subset %x21-%x7e (excludes 920 control chars and space), and MUST NOT include any of these 921 characters: "( ) { ] % * " \" Because JSON is case-sensitive, 922 servers MUST return keywords in lower-case. The IANA Keyword 923 Registry [2] as established in [RFC5788] assigns semantic meaning 924 to some other keywords in common use. New keywords may be 925 established here in the future. In particular, note: 927 * "$forwarded": The email has been forwarded. 929 * "$phishing": The email is highly likely to be phishing. 930 Clients SHOULD warn users to take care when viewing this email 931 and disable links and attachments. 933 * "$junk": The email is definitely spam. Clients SHOULD set this 934 flag when users report spam to help train automated spam- 935 detection systems. 937 * "$notjunk": The email is definitely not spam. Clients SHOULD 938 set this flag when users indicate an email is legitimate, to 939 help train automated spam-detection systems. 941 o *size*: "PositiveInt" (immutable; server-set) The size, in octets, 942 of the raw data for the [RFC5322] message (as referenced by the 943 _blobId_, i.e. the number of octets in the file the user would 944 download). 946 o *receivedAt*: "UTCDate" (immutable; default: time of creation on 947 server) The date the email was received by the message store. 948 This is the _internal date_ in IMAP ([RFC3501]). 950 4.1.2. Header fields parsed forms 952 Header field properties are derived from the [RFC5322] and [RFC6532] 953 message header fields. All header fields may be fetched in a raw 954 form. Some headers may also be fetched in a parsed form. The 955 structured form that may be fetched depends on the header. The 956 following forms are defined: 958 4.1.2.1. Raw 960 Type: "String" 962 The raw octets of the header field value from the first octet 963 following the header field name terminating colon, up to but 964 excluding the header field terminating CRLF. Any standards-compliant 965 message MUST be either ASCII (RFC5322) or UTF-8 (RFC6532), however 966 other encodings exist in the wild. A server SHOULD replace any octet 967 or octet run with the high bit set that violates UTF-8 syntax with 968 the unicode replacement character (U+FFFD). Any NUL octet MUST be 969 dropped. 971 This form will typically have a leading space, as most generated 972 messages insert a space after the colon that terminates the header 973 field name. 975 4.1.2.2. Text 977 Type: "String" 979 The header field value with: 981 1. White space unfolded (as defined in [RFC5322] section 2.2.3). 983 2. The terminating CRLF at the end of the value removed. 985 3. Any SP characters at the beginning of the value removed. 987 4. Any syntactically correct [RFC2047] encoded sections with a known 988 character set decoded. Any [RFC2047] encoded NUL octets or 989 control characters are dropped from the decoded value. Any text 990 that looks like [RFC2047] syntax but violates [RFC2047] placement 991 or whitespace rules MUST NOT be decoded. 993 5. The resulting unicode converted to NFC form. 995 If any decodings fail, the parser SHOULD insert a unicode replacement 996 character (U+FFFD) and attempt to continue as much as possible. 998 To prevent obviously nonsense behaviour, which can lead to 999 interoperability issues, this form may only be fetched or set for the 1000 following header fields: 1002 o Subject 1004 o Comments 1006 o Keywords 1008 o List-Id 1010 o Any header not defined in [RFC5322] or [RFC2369] 1012 4.1.2.3. Addresses 1014 Type: "EmailAddress[]" 1016 The header is parsed as an "address-list" value, as specified in 1017 [RFC5322] section 3.4, into the "EmailAddress[]" type. There is an 1018 EmailAddress item for each "mailbox" parsed from the "address-list". 1019 Group and comment information is discarded. 1021 The *EmailAddress* object has the following properties: 1023 o *name*: "String|null" The _display-name_ of the [RFC5322] 1024 _mailbox_, or "null" if none. If this is a _quoted-string_: 1026 1. The surrounding DQUOTE characters are removed. 1028 2. Any _quoted-pair_ is decoded. 1030 3. White-space is unfolded, and then any leading and trailing 1031 white-space is removed. 1033 o *email*: "String" The _addr-spec_ of the [RFC5322] _mailbox_. 1035 Any syntactically correct [RFC2047] encoded sections with a known 1036 encoding MUST be decoded, following the same rules as for the _Text_ 1037 form. 1039 Parsing SHOULD be best-effort in the face of invalid structure to 1040 accommodate invalid messages and semi-complete drafts. EmailAddress 1041 objects MAY have an _email_ property that does not conform to the 1042 _addr-spec_ form (for example, may not contain an @ symbol). 1044 For example, the following "address-list" string: 1046 " James Smythe" , Friends: 1047 jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= 1048 ; 1050 would be parsed as: 1052 [ 1053 { "name": "James Smythe", "email": "james@example.com" }, 1054 { "name": null, "email": "jane@example.com" }, 1055 { "name": "John Smith", "email": "john@example.com" } 1056 ] 1058 To prevent obviously nonsense behaviour, which can lead to 1059 interoperability issues, this form may only be fetched or set for the 1060 following header fields: 1062 o From 1064 o Sender 1066 o Reply-To 1068 o To 1070 o Cc 1072 o Bcc 1074 o Resent-From 1076 o Resent-Sender 1078 o Resent-Reply-To 1080 o Resent-To 1082 o Resent-Cc 1084 o Resent-Bcc 1086 o Any header not defined in [RFC5322] or [RFC2369] 1088 4.1.2.4. GroupedAddresses 1090 Type: "EmailAddressGroup[]" 1092 This is similar to the Addresses form but preserves group 1093 information. The header is parsed as an "address-list" value, as 1094 specified in [RFC5322] section 3.4, into the "GroupedAddresses[]" 1095 type. Consecutive mailboxes that are not part of a group are still 1096 collected under an EmailAddressGroup object to provide a uniform 1097 type. 1099 The *EmailAddressGroup* object has the following properties: 1101 o *name*: "String|null" The _display-name_ of the [RFC5322] _group_, 1102 or "null" if the addresses are not part of a group. If this is a 1103 _quoted-string_ it is processed the same as the _name_ in the 1104 _EmailAddress_ type. 1106 o *addresses*: "EmailAddress[]" The _mailbox_es that belong to this 1107 group, represented as EmailAddress objects. 1109 Any syntactically correct [RFC2047] encoded sections with a known 1110 encoding MUST be decoded, following the same rules as for the _Text_ 1111 form. 1113 Parsing SHOULD be best-effort in the face of invalid structure to 1114 accommodate invalid messages and semi-complete drafts. 1116 For example, the following "address-list" string: 1118 " James Smythe" , Friends: 1119 jane@example.com, =?UTF-8?Q?John_Sm=C3=AEth?= 1120 ; 1122 would be parsed as: 1124 [ 1125 { "name": null, "addresses": [ 1126 { "name": "James Smythe", "email": "james@example.com" } 1127 ]}, 1128 { "name": "Friends", "addresses": [ 1129 { "name": null, "email": "jane@example.com" }, 1130 { "name": "John Smith", "email": "john@example.com" } 1131 ]} 1132 ] 1134 To prevent obviously nonsense behaviour, which can lead to 1135 interoperability issues, this form may only be fetched or set for the 1136 same header fields as the _Addresses_ form. 1138 4.1.2.5. MessageIds 1140 Type: "String[]|null" 1142 The header is parsed as a list of "msg-id" values, as specified in 1143 [RFC5322] section 3.6.4, into the "String[]" type. CFWS and 1144 surrounding angle brackets ("<>") are removed. If parsing fails, the 1145 value is "null". 1147 To prevent obviously nonsense behaviour, which can lead to 1148 interoperability issues, this form may only be fetched or set for the 1149 following header fields: 1151 o Message-ID 1153 o In-Reply-To 1155 o References 1157 o Resent-Message-ID 1159 o Any header not defined in [RFC5322] or [RFC2369] 1161 4.1.2.6. Date 1163 Type: "Date|null" 1165 The header is parsed as a "date-time" value, as specified in 1166 [RFC5322] section 3.3, into the "Date" type. If parsing fails, the 1167 value is "null". 1169 To prevent obviously nonsense behaviour, which can lead to 1170 interoperability issues, this form may only be fetched or set for the 1171 following header fields: 1173 o Date 1175 o Resent-Date 1177 o Any header not defined in [RFC5322] or [RFC2369] 1179 4.1.2.7. URLs 1181 Type: "String[]|null" 1183 The header is parsed as a list of URLs, as described in [RFC2369], 1184 into the "String[]" type. Values do not include the surrounding 1185 angle brackets or any comments in the header with the URLs. If 1186 parsing fails, the value is "null". 1188 To prevent obviously nonsense behaviour, which can lead to 1189 interoperability issues, this form may only be fetched or set for the 1190 following header fields: 1192 o List-Help 1194 o List-Unsubscribe 1196 o List-Subscribe 1198 o List-Post 1200 o List-Owner 1202 o List-Archive 1204 o Any header not defined in [RFC5322] or [RFC2369] 1206 4.1.3. Header fields properties 1208 The following low-level *Email* property is specified for complete 1209 access to the header data of the message: 1211 o *headers*: "EmailHeader[]" (immutable) This is a list of all 1212 [RFC5322] header fields, in the same order they appear in the 1213 message. An *EmailHeader* object has the following properties: 1215 * *name*: "String" The header _field name_ as defined in 1216 [RFC5322], with the same capitalization that it has in the 1217 message. 1219 * *value*: "String" The header _field value_ as defined in 1220 [RFC5322], in _Raw_ form. 1222 In addition, the client may request/send properties representing 1223 individual header fields of the form: 1225 header:{header-field-name} 1227 Where "{header-field-name}" means any series of one or more printable 1228 ASCII characters (i.e. characters that have values between 33 and 1229 126, inclusive), except colon. The property may also have the 1230 following suffixes: 1232 o *:as{header-form}* This means the value is in a parsed form, where 1233 "{header-form}" is one of the parsed-form names specified above. 1234 If not given, the value is in _Raw_ form. 1236 o *:all* This means the value is an array, with the items 1237 corresponding to each instance of the header field, in the order 1238 they appear in the message. If this suffix is not used, the 1239 result is the value of the *last* instance of the header field 1240 (i.e. identical to the *last* item in the array if :all is used), 1241 or "null" if none. 1243 If both suffixes are used, they MUST be specified in the order above. 1244 Header field names are matched case-insensitively. The value is 1245 typed according to the requested form, or an array of that type if 1246 :all is used. If no header fields exist in the message with the 1247 requested name, the value is "null" if fetching a single instance, or 1248 the empty array if requesting :all. 1250 As a simple example, if the client requests a property called 1251 "header:subject", this means find the _last_ header field in the 1252 message named "subject" (matched case-insensitively) and return the 1253 value in _Raw_ form, or "null" if no header of this name is found. 1255 For a more complex example, consider the client requesting a property 1256 called "header:Resent-To:asAddresses:all". This means: 1258 1. Find _all_ header fields named Resent-To (matched case- 1259 insensitively). 1261 2. For each instance parse the header field value in the _Addresses_ 1262 form. 1264 3. The result is of type "EmailAddress[][]" - each item in the array 1265 corresponds to the parsed value (which is itself an array) of the 1266 Resent-To header field instance. 1268 The following convenience properties are also specified for the 1269 *Email* object: 1271 o *messageId*: "String[]|null" (immutable) The value is identical to 1272 the value of _header:Message-ID:asMessageIds_. For messages 1273 conforming to RFC5322 this will be an array with a single entry. 1275 o *inReplyTo*: "String[]|null" (immutable) The value is identical to 1276 the value of _header:In-Reply-To:asMessageIds_. 1278 o *references*: "String[]|null" (immutable) The value is identical 1279 to the value of _header:References:asMessageIds_. 1281 o *sender*: "EmailAddress[]|null" (immutable) The value is identical 1282 to the value of _header:Sender:asAddresses_. 1284 o *from*: "EmailAddress[]|null" (immutable) The value is identical 1285 to the value of _header:From:asAddresses_. 1287 o *to*: "EmailAddress[]|null" (immutable) The value is identical to 1288 the value of _header:To:asAddresses_. 1290 o *cc*: "EmailAddress[]|null" (immutable) The value is identical to 1291 the value of _header:Cc:asAddresses_. 1293 o *bcc*: "EmailAddress[]|null" (immutable) The value is identical to 1294 the value of _header:Bcc:asAddresses_. 1296 o *replyTo*: "EmailAddress[]|null" (immutable) The value is 1297 identical to the value of _header:Reply-To:asAddresses_. 1299 o *subject*: "String|null" (immutable) The value is identical to the 1300 value of _header:Subject:asText_. 1302 o *sentAt*: "Date|null" (immutable; default on creation: current 1303 server time) The value is identical to the value of 1304 _header:Date:asDate_. 1306 4.1.4. Body parts 1308 These properties are derived from the [RFC5322] message body and its 1309 [RFC2045] MIME entities. 1311 A *EmailBodyPart* object has the following properties: 1313 o *partId*: "String|null" Identifies this part uniquely within the 1314 Email. This is scoped to the _emailId_ and has no meaning outside 1315 of the JMAP Email object representation. This is "null" if, and 1316 only if, the part is of type "multipart/*". 1318 o *blobId*: "Id|null" The id representing the raw octets of the 1319 contents of the part, after decoding any known _Content-Transfer- 1320 Encoding_ (as defined in [RFC2045]), or "null" if, and only if, 1321 the part is of type "multipart/*". Note, two parts may be 1322 transfer-encoded differently but have the same blob id if their 1323 decoded octets are identical and the server is using a secure hash 1324 of the data for the blob id. If the transfer encoding is unknown, 1325 it is treated as though it had no transfer-encoding. 1327 o *size*: "PositiveInt" The size, in octets, of the raw data after 1328 content transfer decoding (as referenced by the _blobId_, i.e. the 1329 number of octets in the file the user would download). 1331 o *headers*: "EmailHeader[]" This is a list of all header fields in 1332 the part, in the order they appear in the message. The values are 1333 in _Raw_ form. 1335 o *name*: "String|null" This is the [RFC2231] decoded _filename_ 1336 parameter of the _Content-Disposition_ header field, or (for 1337 compatibility with existing systems) if not present then the 1338 [RFC2047] decoded _name_ parameter of the _Content-Type_ header 1339 field. 1341 o *type*: "String" The value of the _Content-Type_ header field of 1342 the part, if present, otherwise the implicit type as per the MIME 1343 standard ("text/plain", or "message/rfc822" if inside a 1344 "multipart/digest"). CFWS is removed and any parameters are 1345 stripped. 1347 o *charset*: "String|null" The value of the charset parameter of the 1348 _Content-Type_ header field, if present, or "null" if the header 1349 field is present but not of type "text/*". If there is no 1350 _Content-Type_ header field, or it exists and is of type "text/*" 1351 but has no charset parameter, this is the implicit charset as per 1352 the MIME standard: "us-ascii". 1354 o *disposition*: "String|null" The value of the _Content- 1355 Disposition_ header field of the part, if present, otherwise 1356 "null". CFWS is removed and any parameters are stripped. 1358 o *cid*: "String|null" The value of the _Content-Id_ header field of 1359 the part, if present, otherwise "null". CFWS and surrounding 1360 angle brackets ("<>") are removed. This may be used to reference 1361 the content from within an [HTML] body part using the "cid:" 1362 protocol, as defined in [RFC2392]. 1364 o *language*: "String[]|null" The list of language tags, as defined 1365 in [RFC3282], in the _Content-Language_ header field of the part, 1366 if present. 1368 o *location*: "String|null" The URI, as defined in [RFC2557], in the 1369 _Content-Location_ header field of the part, if present. 1371 o *subParts*: "EmailBodyPart[]|null" If type is "multipart/*", this 1372 contains the body parts of each child. 1374 In addition, the client may request/send EmailBodyPart properties 1375 representing individual header fields, following the same syntax and 1376 semantics as for the Email object, e.g. "header:Content-Type". 1378 The following *Email* properties are specified for access to the body 1379 data of the message: 1381 o *bodyStructure*: "EmailBodyPart" (immutable) This is the full MIME 1382 structure of the message body, represented as an array of the 1383 message's top-level MIME parts, without recursing into "message/ 1384 rfc822" or "message/global" parts. Note that EmailBodyParts may 1385 have subParts if they are of type "multipart/*". 1387 o *bodyValues*: "String[EmailBodyValue]" (immutable) This is a map 1388 of _partId_ to an *EmailBodyValue* object for none, some or all 1389 "text/*" parts. Which parts are included and whether the value is 1390 truncated is determined by various arguments to _Email/get_ and 1391 _Email/parse_. An *EmailBodyValue* object has the following 1392 properties: 1394 * *value*: "String" The value of the body part after decoding 1395 _Content-Transfer-Encoding_ and decoding the _Content-Type_ 1396 charset, if both known to the server, and with any CRLF 1397 replaced with a single LF. The server MAY use heuristics to 1398 determine the charset to use for decoding if the charset is 1399 unknown, or if no charset is given, or if it believes the 1400 charset given is incorrect. Decoding is best-effort and SHOULD 1401 insert the unicode replacement character (U+FFFD) and continue 1402 when a malformed section is encountered. Note that due to the 1403 charset decoding and line ending normalisation, the length of 1404 this string will probably not be exactly the same as the _size_ 1405 property on the corresponding EmailBodyPart. 1407 * *isEncodingProblem*: "Boolean" (default: false) This is "true" 1408 if malformed sections were found while decoding the charset, or 1409 the charset was unknown, or the content-trasfer-encoding was 1410 unknown. 1412 * *isTruncated*: "Boolean" (default: false) This is "true" if the 1413 _value_ has been truncated. 1415 See the security considerations section for issues related to 1416 truncation and heuristic determination of content-type and 1417 charset. 1419 o *textBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", 1420 "text/html", "image/*", "audio/*" and/or "video/*" parts to 1421 display (sequentially) as the message body, with a preference for 1422 "text/plain" when alternative versions are available. 1424 o *htmlBody*: "EmailBodyPart[]" (immutable) A list of "text/plain", 1425 "text/html", "image/*", "audio/*" and/or "video/*" parts to 1426 display (sequentially) as the message body, with a preference for 1427 "text/html" when alternative versions are available. 1429 o *attachments*: "EmailBodyPart[]" (immutable) A list of all parts 1430 in _bodyStructure_, traversing depth-first, which satisfy either 1431 of the following conditions: 1433 * not of type "multipart/*" and not included in _textBody_ or 1434 _htmlBody_ 1436 * of type "image/*", "audio/*" or "video/*" and not in both 1437 _textBody_ and _htmlBody_ 1439 None of these parts include subParts, including "message/*" types. 1440 Attached messages may be fetched using the Email/parse method and 1441 the blobId. Note, an [HTML] body part may reference image parts 1442 in attachments using "cid:" links to reference the _Content-Id_, 1443 as defined in [RFC2392], or by referencing the _Content-Location_. 1445 o *hasAttachment*: "Boolean" (immutable; server-set) This is "true" 1446 if there are one or more parts in the message that a client UI 1447 should offer as downloadable. A server SHOULD set hasAttachment 1448 to "true" if the _attachments_ list contains at least one item 1449 that does not have "Content-Disposition: inline". The server MAY 1450 ignore parts in this list that are processed automatically in some 1451 way, or are referenced as embedded images in one of the "text/ 1452 html" parts of the message. The server MAY set hasAttachment 1453 based on implementation-defined or site configurable heuristics. 1455 o *preview*: "String" (immutable; server-set) A plain text fragment 1456 of the message body. This is intended to be shown as a preview 1457 line on a mailbox listing, and may be truncated when shown. The 1458 server may choose which part of the message to include in the 1459 preview; skipping quoted sections and salutations and collapsing 1460 white-space can result in a more useful preview. This MUST NOT be 1461 more than 256 characters in length. As this is derived from the 1462 message content by the server, and the algorithm for doing so 1463 could change over time, fetching this for an email a second time 1464 MAY return a different result. However, the previous value is not 1465 considered incorrect, and the change SHOULD NOT cause the Email 1466 object to be considered as changed by the server. 1468 The exact algorithm for decomposing bodyStructure into textBody, 1469 htmlBody and attachments part lists is not mandated, as this is a 1470 quality-of-service implementation issue and likely to require 1471 workarounds for malformed content discovered over time. However, the 1472 following algorithm (expressed here in JavaScript) is suggested as a 1473 starting point, based on real-world experience: 1475 function isInlineMediaType ( type ) { 1476 return type.startsWith( 'image/' ) || 1477 type.startsWith( 'audio/' ) || 1478 type.startsWith( 'video/' ); 1479 } 1481 function parseStructure ( parts, multipartType, inAlternative, 1482 htmlBody, textBody, attachments ) { 1484 // For multipartType == alternative 1485 let textLength = textBody ? textBody.length : -1; 1486 let htmlLength = htmlBody ? htmlBody.length : -1; 1488 for ( let i = 0; i < parts.length; i += 1 ) { 1489 let part = parts[i]; 1490 let isMultipart = part.type.startsWith( 'multipart/' ); 1491 // Is this a body part rather than an attachment 1492 let isInline = part.disposition != "attachment" && 1493 // Must be one of the allowed body types 1494 ( part.type == "text/plain" || 1495 part.type == "text/html" || 1496 isInlineMediaType( part.type ) ) && 1497 // If multipart/related, only the first part can be inline 1498 // If a text part with a filename, and not the first item 1499 // in the multipart, assume it is an attachment 1500 ( i === 0 || 1501 ( multipartType != "related" && 1502 ( isInlineMediaType( part.type ) || !part.name ) ) ); 1504 if ( isMultipart ) { 1505 let subMultiType = part.type.split( '/' )[1]; 1506 parseStructure( part.subParts, subMultiType, 1507 inAlternative || ( subMultiType == 'alternative' ), 1508 htmlBody, textBody, attachments ); 1509 } else if ( isInline ) { 1510 if ( multipartType == 'alternative' ) { 1511 switch ( part.type ) { 1512 case 'text/plain': 1513 textBody.push( part ); 1514 break; 1515 case 'text/html': 1517 htmlBody.push( part ); 1518 break; 1519 default: 1520 attachments.push( part ); 1521 break; 1522 } 1523 continue; 1524 } else if ( inAlternative ) { 1525 if ( part.type == 'text/plain' ) { 1526 htmlBody = null; 1527 } 1528 if ( part.type == 'text/html' ) { 1529 textBody = null; 1530 } 1531 } 1532 if ( textBody ) { 1533 textBody.push( part ); 1534 } 1535 if ( htmlBody ) { 1536 htmlBody.push( part ); 1537 } 1538 if ( ( !textBody || !htmlBody ) && 1539 isInlineMediaType( part.type ) ) { 1540 attachments.push( part ); 1541 } 1542 } else { 1543 attachments.push( part ); 1544 } 1545 } 1547 if ( multipartType == 'alternative' && textBody && htmlBody ) { 1548 // Found HTML part only 1549 if ( textLength == textBody.length && 1550 htmlLength != htmlBody.length ) { 1551 for ( let i = htmlLength; i < htmlBody.length; i += 1 ) { 1552 textBody.push( htmlBody[i] ); 1553 } 1554 } 1555 // Found plain text part only 1556 if ( htmlLength == htmlBody.length && 1557 textLength != textBody.length ) { 1558 for ( let i = textLength; i < textBody.length; i += 1 ) { 1559 htmlBody.push( textBody[i] ); 1560 } 1561 } 1562 } 1563 } 1564 // Usage: 1565 let htmlBody = []; 1566 let textBody = []; 1567 let attachments = []; 1569 parseStructure( [ bodyStructure ], 'mixed', false, 1570 htmlBody, textBody, attachments ); 1572 For instance, consider a message with both text and HTML versions 1573 that's then gone through a list software manager that attaches a 1574 header/footer. It might have a MIME structure something like: 1576 multipart/mixed 1577 text/plain, content-disposition=inline - A 1578 multipart/mixed 1579 multipart/alternative 1580 multipart/mixed 1581 text/plain, content-disposition=inline - B 1582 image/jpeg, content-disposition=inline - C 1583 text/plain, content-disposition=inline - D 1584 multipart/related 1585 text/html - E 1586 image/jpeg - F 1587 image/jpeg, content-disposition=attachment - G 1588 application/x-excel - H 1589 message/rfc822 - J 1590 text/plain, content-disposition=inline - K 1592 In this case, the above algorithm would decompose this to: 1594 textBody => [ A, B, C, D, K ] 1595 htmlBody => [ A, E, K ] 1596 attachments => [ C, F, G, H, J ] 1598 4.2. Email/get 1600 Standard "/get" method, with the following additional arguments: 1602 o *bodyProperties*: "String[]" A list of properties to fetch for 1603 each EmailBodyPart returned. If omitted, this defaults to: 1605 [ "partId", "blobId", "size", "name", "type", "charset", 1606 "disposition", "cid", "language", "location" ] 1608 o *fetchTextBodyValues*: "Boolean" (default: false) If "true", the 1609 _bodyValues_ property includes any "text/*" part in the "textBody" 1610 property. 1612 o *fetchHTMLBodyValues*: "Boolean" (default: false) If "true", the 1613 _bodyValues_ property includes any "text/*" part in the "htmlBody" 1614 property. 1616 o *fetchAllBodyValues*: "Boolean" (default: false) If "true", the 1617 _bodyValues_ property includes any "text/*" part in the 1618 "bodyStructure" property. 1620 o *maxBodyValueBytes*: "PositiveInt" (default: 0) If greater than 1621 zero, the _value_ property of any EmailBodyValue object returned 1622 in _bodyValues_ MUST be truncated if necessary so it does not 1623 exceed this number of octets in size. If "0" (the default), no 1624 truncation occurs. The server MUST ensure the truncation results 1625 in valid UTF-8 and does not occur mid-codepoint. If the part is 1626 of type "text/html", the server SHOULD NOT truncate inside an HTML 1627 tag, e.g. in the middle of "". 1628 There is no requirement for the truncated form to be a balanced 1629 tree or valid HTML (indeed, the original source may well be 1630 neither of these things). 1632 If the standard _properties_ argument is omitted or "null", the 1633 following default MUST be used instead of "all" properties: 1635 [ "id", "blobId", "threadId", "mailboxIds", "keywords", "size", 1636 "receivedAt", "messageId", "inReplyTo", "references", "sender", "from", 1637 "to", "cc", "bcc", "replyTo", "subject", "sentAt", "hasAttachment", 1638 "preview", "bodyValues", "textBody", "htmlBody", "attachments" ] 1640 The following properties are expected to be fast to fetch in a 1641 quality implementation: 1643 o id 1645 o blobId 1647 o threadId 1649 o mailboxIds 1651 o keywords 1653 o size 1655 o receivedAt 1657 o messageId 1659 o inReplyTo 1660 o sender 1662 o from 1664 o to 1666 o cc 1668 o bcc 1670 o replyTo 1672 o subject 1674 o sentAt 1676 o hasAttachment 1678 o preview 1680 Clients SHOULD take care when fetching any other properties, as there 1681 may be significantly longer latency in fetching and returning the 1682 data. 1684 As specified above, parsed forms of headers may only be used on 1685 appropriate header fields. Attempting to fetch a form that is 1686 forbidden (e.g. "header:From:asDate") MUST result in the method call 1687 being rejected with an "invalidArguments" error. 1689 Where a specific header is requested as a property, the 1690 capitalization of the property name in the response MUST be identical 1691 to that used in the request. 1693 4.2.1. Example 1695 Request: 1697 [[ "Email/get", { 1698 "ids": [ "f123u456", "f123u457" ], 1699 "properties": [ "threadId", "mailboxIds", "from", "subject", 1700 "receivedAt", "header:List-POST:asURLs", 1701 "htmlBody", "bodyValues" ], 1702 "bodyProperties": [ "partId", "blobId", "size", "type" ], 1703 "fetchHTMLBodyValues": true, 1704 "maxBodyValueBytes": 256 1705 }, "#1" ]] 1707 and response: 1709 [[ "Email/get", { 1710 "accountId": "abc", 1711 "state": "41234123231", 1712 "list": [ 1713 { 1714 "id": "f123u457", 1715 "threadId": "ef1314a", 1716 "mailboxIds": { "f123": true }, 1717 "from": [{ "name": "Joe Bloggs", "email": "joe@example.com" }], 1718 "subject": "Dinner on Thursday?", 1719 "receivedAt": "2013-10-13T14:12:00Z", 1720 "header:List-POST:asURLs": [ 1721 "mailto:partytime@lists.example.com" 1722 ], 1723 "htmlBody": [{ 1724 "partId": "1", 1725 "blobId": "841623871", 1726 "size": 283331, 1727 "type": "text/html" 1728 }, { 1729 "partId": "2", 1730 "blobId": "319437193", 1731 "size": 10343, 1732 "type": "text/plain" 1733 }], 1734 "bodyValues": { 1735 "1": { 1736 "isEncodingProblem": false, 1737 "isTruncated": true, 1738 "value": "

Hello ..." 1739 }, 1740 "2": { 1741 "isEncodingProblem": false, 1742 "isTruncated": false, 1743 "value": "-- Sent by your friendly mailing list ..." 1744 } 1745 } 1746 } 1747 ], 1748 "notFound": [ "f123u456" ] 1749 }, "#1" ]] 1751 4.3. Email/changes 1753 Standard "/changes" method. If generating intermediate states for a 1754 large set of changes, it is recommended that newer changes are 1755 returned first, as these are generally of more interest to users. 1757 4.4. Email/query 1759 Standard "/query" method, but with the following additional 1760 arguments: 1762 o *collapseThreads*: "Boolean" (default: false) If "true", emails in 1763 the same thread as a previous email in the list (given the filter 1764 and sort order) will be removed from the list. This means only 1765 one email at most will be included in the list for any given 1766 thread. 1768 In quality implementations, the query "total" property is expected to 1769 be fast to calculate when the filter consists solely of a single 1770 "inMailbox" property, as it is the same as the totalEmails or 1771 totalThreads properties (depending on whether collapseThreads is 1772 true) of the associated Mailbox object. 1774 4.4.1. Filtering 1776 A *FilterCondition* object has the following properties, any of which 1777 may be omitted: 1779 o *inMailbox*: "Id" A mailbox id. An email must be in this mailbox 1780 to match the condition. 1782 o *inMailboxOtherThan*: "Id[]" A list of mailbox ids. An email must 1783 be in at least one mailbox not in this list to match the 1784 condition. This is to allow messages solely in trash/spam to be 1785 easily excluded from a search. 1787 o *before*: "UTCDate" The _receivedAt_ date-time of the email must 1788 be before this date-time to match the condition. 1790 o *after*: "UTCDate" The _receivedAt_ date-time of the email must be 1791 the same or after this date-time to match the condition. 1793 o *minSize*: "PositiveInt" The _size_ of the email in octets must be 1794 equal to or greater than this number to match the condition. 1796 o *maxSize*: "PositiveInt" The _size_ of the email in octets must be 1797 less than this number to match the condition. 1799 o *allInThreadHaveKeyword*: "String" All emails (including this one) 1800 in the same thread as this email must have the given keyword to 1801 match the condition. 1803 o *someInThreadHaveKeyword*: "String" At least one email (possibly 1804 this one) in the same thread as this email must have the given 1805 keyword to match the condition. 1807 o *noneInThreadHaveKeyword*: "String" All emails (including this 1808 one) in the same thread as this email must *not* have the given 1809 keyword to match the condition. 1811 o *hasKeyword*: "String" This email must have the given keyword to 1812 match the condition. 1814 o *notKeyword*: "String" This email must not have the given keyword 1815 to match the condition. 1817 o *hasAttachment*: "Boolean" The "hasAttachment" property of the 1818 email must be identical to the value given to match the condition. 1820 o *text*: "String" Looks for the text in emails. The server SHOULD 1821 look up text in the _from_, _to_, _cc_, _bcc_, _subject_ header 1822 fields of the message, and inside any "text/*" or other body parts 1823 that may be converted to text by the server. The server MAY 1824 extend the search to any additional textual property. 1826 o *from*: "String" Looks for the text in the _From_ header field of 1827 the message. 1829 o *to*: "String" Looks for the text in the _To_ header field of the 1830 message. 1832 o *cc*: "String" Looks for the text in the _Cc_ header field of the 1833 message. 1835 o *bcc*: "String" Looks for the text in the _Bcc_ header field of 1836 the message. 1838 o *subject*: "String" Looks for the text in the _subject_ property 1839 of the email. 1841 o *body*: "String" Looks for the text in one of the body parts of 1842 the email. The server MAY exclude MIME body parts with content 1843 media types other than "text/_" and "message/_" from consideration 1844 in search matching. Care should be taken to match based on the 1845 text content actually presented to an end-user by viewers for that 1846 media type, or otherwise identified as appropriate for search 1847 indexing. Matching document metadata uninteresting to an end-user 1848 (e.g., markup tag and attribute names) is undesirable. 1850 o *header*: "String[]" The array MUST contain either one or two 1851 elements. The first element is the name of the header field to 1852 match against. The second (optional) element is the text to look 1853 for in the header field value. If not supplied, the message 1854 matches simply if it _has_ a header field of the given name. 1856 If zero properties are specified on the FilterCondition, the 1857 condition MUST always evaluate to "true". If multiple properties are 1858 specified, ALL must apply for the condition to be "true" (it is 1859 equivalent to splitting the object into one-property conditions and 1860 making them all the child of an AND filter operator). 1862 The exact semantics for matching "String" fields is *deliberately not 1863 defined* to allow for flexibility in indexing implementation, subject 1864 to the following: 1866 o Any syntactically correct [RFC2047] encoded sections of header 1867 fields with a known encoding SHOULD be decoded before attempting 1868 to match text. 1870 o When searching inside a "text/html" body part, any text considered 1871 markup rather than content SHOULD be ignored, including HTML tags 1872 and most attributes, anything inside the "" tag, CSS and 1873 JavaScript. Attribute content intended for presentation to the 1874 user such as "alt" and "title" SHOULD be considered in the search. 1876 o Text SHOULD be matched in a case-insensitive manner. 1878 o Text contained in either (but matched) single or double quotes 1879 SHOULD be treated as a *phrase search*, that is a match is 1880 required for that exact word or sequence of words, excluding the 1881 surrounding quotation marks. Use "\"", "\'" and "\\" to match a 1882 literal """, "'" and "\" respectively in a phrase. 1884 o Outside of a phrase, white-space SHOULD be treated as dividing 1885 separate tokens that may be searched for separately, but MUST all 1886 be present for the email to match the filter. 1888 o Tokens MAY be matched on a whole-word basis using stemming (so for 1889 example a text search for "bus" would match "buses" but not 1890 "business"). 1892 4.4.2. Sorting 1894 The following properties MUST be supported for sorting: 1896 o *receivedAt* - The _receivedAt_ date as returned in the Email 1897 object. 1899 The following properties SHOULD be supported for sorting: 1901 o *size* - The _size_ as returned in the Email object. 1903 o *from* - This is taken to be either the "name" part, or if 1904 "null"/empty then the "email" part, of the *first* EmailAddress 1905 object in the _from_ property. If still none, consider the value 1906 to be the empty string. 1908 o *to* - This is taken to be either the "name" part, or if 1909 "null"/empty then the "email" part, of the *first* EmailAddress 1910 object in the _to_ property. If still none, consider the value to 1911 be the empty string. 1913 o *subject* - This is taken to be the base subject of the email, as 1914 defined in section 2.1 of [RFC5256]. 1916 o *sentAt* - The _sentAt_ property on the Email object. 1918 o *hasKeyword* - This value MUST be considered "true" if the email 1919 has the keyword given as an additional _keyword_ property on the 1920 _Comparator_ object, or "false" otherwise. 1922 o *allInThreadHaveKeyword* - This value MUST be considered "true" 1923 for the email if *all* of the emails in the same thread 1924 (regardless of mailbox) have the keyword given as an additional 1925 _keyword_ property on the _Comparator_ object. 1927 o *someInThreadHaveKeyword* - This value MUST be considered "true" 1928 for the email if *any* of the emails in the same thread 1929 (regardless of mailbox) have the keyword given as an additional 1930 _keyword_ property on the _Comparator_ object. 1932 The server MAY support sorting based on other properties as well. A 1933 client can discover which properties are supported by inspecting the 1934 server's _capabilities_ object (see section 1.3). 1936 Example sort: 1938 [{ 1939 "property": "someInThreadHaveKeyword", 1940 "keyword": "$flagged", 1941 "isAscending": false 1942 }, { 1943 "property": "subject", 1944 "collation": "i;ascii-casemap" 1945 }, { 1946 "property": "receivedAt", 1947 "isAscending": false 1948 }] 1950 This would sort emails in flagged threads first (the thread is 1951 considered flagged if any email within it is flagged), and then in 1952 subject order, then newest first for messages with the same subject. 1953 If two emails have both identical flagged status, subject and date, 1954 the order is server-dependent but must be stable. 1956 4.4.3. Thread collapsing 1958 When _collapseThreads_ is "true", then after filtering and sorting 1959 the email list, the list is further winnowed by removing any emails 1960 for a thread id that has already been seen (when passing through the 1961 list sequentially). A thread will therefore only appear *once* in 1962 the result, at the position of the first email in the list that 1963 belongs to the thread (given the current sort/filter). 1965 4.5. Email/queryChanges 1967 Standard "/queryChanges" method, with the following additional 1968 arguments: 1970 o *collapseThreads*: "Boolean" (default: false) The 1971 _collapseThreads_ argument that was used with _Email/query_. 1973 4.6. Email/set 1975 Standard "/set" method. The _Email/set_ method encompasses: 1977 o Creating a draft 1979 o Changing the keywords of an email (e.g. unread/flagged status) 1981 o Adding/removing an email to/from mailboxes (moving a message) 1983 o Deleting emails 1984 The format of the keywords/mailboxIds properties means that when 1985 updating an email you can either replace the entire set of keywords/ 1986 mailboxes (by setting the full value of the property) or add/remove 1987 individual ones using the JMAP patch syntax (see 1988 [I-D.ietf-jmap-core], section 5.3 for the specification and section 1989 5.7 for an example). 1991 Due to the format of the Email object, when creating an email there 1992 are a number of ways to specify the same information. To ensure that 1993 the RFC5322 email to create is unambiguous, the following constraints 1994 apply to Email objects submitted for creation: 1996 o The _headers_ property MUST NOT be given, on either the top-level 1997 email or an EmailBodyPart - the client must set each header field 1998 as an individual property. 2000 o There MUST NOT be two properties that represent the same header 2001 field (e.g. "header:from" and "from") within the Email or 2002 particular EmailBodyPart. 2004 o Header fields MUST NOT be specified in parsed forms that are 2005 forbidden for that particular field. 2007 o Header fields beginning "Content-" MUST NOT be specified on the 2008 Email object, only on EmailBodyPart objects. 2010 o If a bodyStructure property is given, there MUST NOT be textBody, 2011 htmlBody or attachments properties. 2013 o If given, the bodyStructure EmailBodyPart MUST NOT contain a 2014 property representing a header field that is already defined on 2015 the top-level Email object. 2017 o If given, textBody MUST contain exactly one body part, of type 2018 "text/plain". 2020 o If given, htmlBody MUST contain exactly one body part, of type 2021 "text/html". 2023 o Within an EmailBodyPart: 2025 * The client may specify a partId OR a blobId but not both. If a 2026 partId is given, this partId MUST be present in the bodyValues 2027 property. 2029 * The charset property MUST be omitted if a partId is given (the 2030 part's content is included in bodyValues and the server may 2031 choose any appropriate encoding). 2033 * The size property MUST be omitted if a partId is given. If a 2034 blobId is given, it may be included but is ignored by the 2035 server (the size is actually calculated from the blob content 2036 itself). 2038 * A "Content-Transfer-Encoding" header field MUST NOT be given. 2040 o Within an EmailBodyValue object, isEncodingProblem and isTruncated 2041 MUST be either "false" or omitted. 2043 Creation attempts that violate any of this SHOULD be rejected with an 2044 "invalidProperties" error, however a server MAY choose to modify the 2045 Email (e.g. choose between conflicting headers, use a different 2046 content-encoding etc.) to comply with its requirements instead. 2048 The server MAY also choose to set additional headers. If not 2049 included, the server MUST generate and set a "Message-ID" header 2050 field in conformance with [RFC5322] section 3.6.4, and a "Date" 2051 header field in conformance with section 3.6.1. 2053 The final RFC5322 email generated may be invalid. For example, if it 2054 is a half-finished draft, the "To" field may have a value that does 2055 not conform to the required syntax for this header field. The 2056 message will be checked for strict conformance when submitted for 2057 sending (see the EmailSubmission object description). 2059 Destroying an email removes it from all mailboxes to which it 2060 belonged. To just delete an email to trash, simply change the 2061 "mailboxIds" property so it is now in the mailbox with "role == 2062 "trash"", and remove all other mailbox ids. 2064 When emptying the trash, clients SHOULD NOT destroy emails which are 2065 also in a mailbox other than trash. For those emails, they SHOULD 2066 just remove the Trash mailbox from the email. 2068 For successfully created Email objects, the _created_ response 2069 contains the _id_, _blobId_, _threadId_ and _size_ properties of the 2070 object. 2072 The following extra _SetError_ types are defined: 2074 For *create*: 2076 o "blobNotFound": At least one blob id given for an EmailBodyPart 2077 doesn't exist. An extra _notFound_ property of type "Id[]" MUST 2078 be included in the error object containing every _blobId_ 2079 referenced by an EmailBodyPart that could not be found on the 2080 server. 2082 For *create* and *update*: 2084 o "tooManyKeywords": The change to the email's keywords would exceed 2085 a server-defined maximum. 2087 o "tooManyMailboxes": The change to the email's mailboxes would 2088 exceed a server-defined maximum. 2090 4.7. Email/copy 2092 Standard "/copy" method, except only the _mailboxIds_, _keywords_ and 2093 _receivedAt_ properties may be set during the copy. This method 2094 cannot modify the RFC5322 representation of an email. 2096 The server MAY forbid two email objects with the same exact [RFC5322] 2097 content, or even just with the same [RFC5322] Message-ID, to coexist 2098 within an account; if the target account already has the email the 2099 copy will be rejected with a standard "alreadyExists" error. 2101 For successfully copied Email objects, the _created_ response 2102 contains the _id_, _blobId_, _threadId_ and _size_ properties of the 2103 new object. 2105 4.8. Email/import 2107 The _Email/import_ method adds [RFC5322] messages to the set of 2108 emails in an account. The server MUST support messages with 2109 [RFC6532] EAI headers. The messages must first be uploaded as blobs 2110 using the standard upload mechanism. It takes the following 2111 arguments: 2113 o *accountId*: "Id" The id of the account to use. 2115 o *ifInState*: "String|null" This is a state string as returned by 2116 the _Email/get_ method. If supplied, the string must match the 2117 current state of the account referenced by the accountId, 2118 otherwise the method will be aborted and a "stateMismatch" error 2119 returned. If "null", any changes will be applied to the current 2120 state. 2122 o *emails*: "Id[EmailImport]" A map of creation id (client 2123 specified) to EmailImport objects 2125 An *EmailImport* object has the following properties: 2127 o *blobId*: "Id" The id of the blob containing the raw [RFC5322] 2128 message. 2130 o *mailboxIds*: "Id[Boolean]" The ids of the mailboxes to assign 2131 this email to. At least one mailbox MUST be given. 2133 o *keywords*: "String[Boolean]" (default: ) The keywords to apply to 2134 the email. 2136 o *receivedAt*: "UTCDate" (default: time of most recent Received 2137 header, or time of import on server if none) The _receivedAt_ date 2138 to set on the email. 2140 Each email to import is considered an atomic unit which may succeed 2141 or fail individually. Importing successfully creates a new email 2142 object from the data referenced by the blobId and applies the given 2143 mailboxes, keywords and receivedAt date. 2145 The server MAY forbid two email objects with the same exact [RFC5322] 2146 content, or even just with the same [RFC5322] Message-ID, to coexist 2147 within an account. In this case, it MUST reject attempts to import 2148 an email considered a duplicate with an "alreadyExists" SetError. An 2149 _existingId_ property of type "Id" MUST be included on the error 2150 object with the id of the existing email. If duplicates are allowed, 2151 the newly created Email object MUST have a separate id and 2152 independent mutable properties to the existing object. 2154 If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid 2155 (e.g. missing, wrong type, id not found), the server MUST reject the 2156 import with an "invalidProperties" SetError. 2158 If the email cannot be imported because it would take the account 2159 over quota, the import should be rejected with an "overQuota" 2160 SetError. 2162 If the blob referenced is not a valid [RFC5322] message, the server 2163 MAY modify the message to fix errors (such as removing NUL octets or 2164 fixing invalid headers). If it does this, the _blobId_ on the 2165 response MUST represent the new representation and therefore be 2166 different to the _blobId_ on the EmailImport object. Alternatively, 2167 the server MAY reject the import with an "invalidEmail" SetError. 2169 The response has the following arguments: 2171 o *accountId*: "Id" The id of the account used for this call. 2173 o *oldState*: "String|null" The state string that would have been 2174 returned by _Email/get_ on this account before making the 2175 requested changes, or "null" if the server doesn't know what the 2176 previous state string was. 2178 o *newState*: "String" The state string that will now be returned by 2179 _Email/get_ on this account. 2181 o *created*: "Id[Email]|null" A map of the creation id to an object 2182 containing the _id_, _blobId_, _threadId_ and _size_ properties 2183 for each successfully imported Email, or "null" if none. 2185 o *notCreated*: "Id[SetError]|null" A map of creation id to a 2186 SetError object for each Email that failed to be created, or 2187 "null" if all successful. The possible errors are defined above. 2189 The following additional errors may be returned instead of the 2190 _Email/import_ response: 2192 "stateMismatch": An "ifInState" argument was supplied and it does not 2193 match the current state. 2195 4.9. Email/parse 2197 This method allows you to parse blobs as [RFC5322] messages to get 2198 Email objects. The server MUST support messages with [RFC6532] EAI 2199 headers. This can be used to parse and display attached emails 2200 without having to import them as top-level email objects in the mail 2201 store in their own right. 2203 The following metadata properties on the Email objects will be "null" 2204 if requested: 2206 o id 2208 o mailboxIds 2210 o keywords 2212 o receivedAt 2214 The _threadId_ property of the Email MAY be present if the server can 2215 calculate which thread the Email would be assigned to were it to be 2216 imported. Otherwise, this too is "null" if fetched. 2218 The _Email/parse_ method takes the following arguments: 2220 o *accountId*: "Id" The id of the account to use. 2222 o *blobIds*: "Id[]" The ids of the blobs to parse. 2224 o *properties*: "String[]" If supplied, only the properties listed 2225 in the array are returned for each Email object. If omitted, 2226 defaults to: [ "messageId", "inReplyTo", "references", "sender", 2227 "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", 2228 "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", 2229 "attachments" ] 2231 o *bodyProperties*: "String[]" A list of properties to fetch for 2232 each EmailBodyPart returned. If omitted, defaults to the same 2233 value as the Email/get "bodyProperties" default argument. 2235 o *fetchTextBodyValues*: "Boolean" (default: false) If "true", the 2236 _bodyValues_ property includes any "text/*" part in the "textBody" 2237 property. 2239 o *fetchHTMLBodyValues*: "Boolean" (default: false) If "true", the 2240 _bodyValues_ property includes any "text/*" part in the "htmlBody" 2241 property. 2243 o *fetchAllBodyValues*: "Boolean" (default: false) If "true", the 2244 _bodyValues_ property includes any "text/*" part in the 2245 "bodyStructure" property. 2247 o *maxBodyValueBytes*: "PositiveInt" (default: 0) If greater than 2248 zero, the _value_ property of any EmailBodyValue object returned 2249 in _bodyValues_ MUST be truncated if necessary so it does not 2250 exceed this number of octets in size. If "0" (the default), no 2251 truncation occurs. The server MUST ensure the truncation results 2252 in valid UTF-8 and does not occur mid-codepoint. If the part is 2253 of type "text/html", the server SHOULD NOT truncate inside an HTML 2254 tag, e.g. in the middle of "". 2255 There is no requirement for the truncated form to be a balanced 2256 tree or valid HTML (indeed, the original source may well be 2257 neither of these things). 2259 The response has the following arguments: 2261 o *accountId*: "Id" The id of the account used for the call. 2263 o *parsed*: "Id[Email]|null" A map of blob id to parsed Email 2264 representation for each successfully parsed blob, or "null" if 2265 none. 2267 o *notParsable*: "Id[]|null" A list of ids given that corresponded 2268 to blobs that could not be parsed as emails, or "null" if none. 2270 o *notFound*: "Id[]|null" A list of blob ids given that could not be 2271 found, or "null" if none. 2273 As specified above, parsed forms of headers may only be used on 2274 appropriate header fields. Attempting to fetch a form that is 2275 forbidden (e.g. "header:From:asDate") MUST result in the method call 2276 being rejected with an "invalidArguments" error. 2278 Where a specific header is requested as a property, the 2279 capitalization of the property name in the response MUST be identical 2280 to that used in the request. 2282 4.10. Examples 2284 A client logs in for the first time. It first fetches the set of 2285 mailboxes. Now it will display the inbox to the user, which we will 2286 presume has mailbox id "fb666a55". The inbox may be (very!) large, 2287 but the user's screen is only so big, so the client will just load 2288 the start and then can load in more as necessary. The client sends 2289 this request: 2291 [[ "Email/query",{ 2292 "accountId": "ue150411c", 2293 "filter": { 2294 "inMailbox": "fb666a55" 2295 }, 2296 "sort": [{ 2297 "isAscending": false, 2298 "property": "receivedAt" 2299 }], 2300 "collapseThreads": true, 2301 "position": 0, 2302 "limit": 30, 2303 "calculateTotal": true 2304 }, "0" ], 2305 [ "Email/get", { 2306 "accountId": "ue150411c", 2307 "#ids": { 2308 "resultOf": "0", 2309 "name": "Email/query", 2310 "path": "/ids" 2311 }, 2312 "properties": [ 2313 "threadId" 2314 ] 2315 }, "1" ], 2316 [ "Thread/get", { 2317 "accountId": "ue150411c", 2318 "#ids": { 2319 "resultOf": "1", 2320 "name": "Email/get", 2321 "path": "/list/*/threadId" 2322 } 2323 }, "2" ], 2324 [ "Email/get", { 2325 "accountId": "ue150411c", 2326 "#ids": { 2327 "resultOf": "2", 2328 "name": "Thread/get", 2329 "path": "/list/*/emailIds" 2330 }, 2331 "properties": [ 2332 "threadId", 2333 "mailboxIds", 2334 "keywords", 2335 "hasAttachment", 2336 "from", 2337 "subject", 2338 "receivedAt", 2339 "size", 2340 "preview" 2341 ] 2342 }, "3" ]] 2344 Let's break down the 4 method calls to see what they're doing: 2346 "0": This asks the server for the ids of the first 30 Email objects 2347 in the inbox, sorted newest first, ignoring messages from the same 2348 thread as a newer message in the mailbox (i.e. it is the first 30 2349 unique threads). 2351 "1": Now we use a back-reference to fetch the thread ids for each of 2352 these email ids. 2354 "2": Another back-reference fetches the Thread object for each of 2355 these thread ids. 2357 "3": Finally, we fetch the information we need to display the mailbox 2358 listing (but no more!) for every message in each of these 30 threads. 2359 The client may aggregate this data for display, for example showing 2360 the thread as "flagged" if any of the messages in it contain the 2361 "$flagged" keyword. 2363 The response from the server may look something like this: 2365 [[ "Email/query", { 2366 "accountId": "ue150411c", 2367 "queryState": "09aa9a075588-780599:0", 2368 "canCalculateChanges": true, 2369 "position": 0, 2370 "total": 115, 2371 "ids": [ "Ma783e5cdf5f2deffbc97930a", 2372 "M9bd17497e2a99cb345fc1d0a", ... ] 2373 }, "0" ], 2374 [ "Email/get", { 2375 "accountId": "ue150411c", 2376 "state": "780599", 2377 "list": [{ 2378 "id": "Ma783e5cdf5f2deffbc97930a", 2379 "threadId": "T36703c2cfe9bd5ed" 2380 }, { 2381 "id": "M9bd17497e2a99cb345fc1d0a", 2382 "threadId": "T0a22ad76e9c097a1" 2383 }, ... ], 2384 "notFound": [] 2385 }, "1" ], 2386 [ "Thread/get", { 2387 "accountId": "ue150411c", 2388 "state": "22a8728b", 2389 "list": [{ 2390 "id": "T36703c2cfe9bd5ed", 2391 "emailIds": [ "Ma783e5cdf5f2deffbc97930a" ] 2392 }, { 2393 "id": "T0a22ad76e9c097a1", 2394 "emailIds": [ "M3b568670a63e5d100f518fa5", 2395 "M9bd17497e2a99cb345fc1d0a" ] 2396 }, ... ], 2397 "notFound": [] 2398 }, "2" ], 2399 [ "Email/get", { 2400 "accountId": "ue150411c", 2401 "state": "780599", 2402 "list": [{ 2403 "id": "Ma783e5cdf5f2deffbc97930a", 2404 "threadId": "T36703c2cfe9bd5ed", 2405 "mailboxIds": { 2406 "fb666a55": true 2407 }, 2408 "keywords": { 2409 "$seen": true, 2410 "$flagged": true 2411 }, 2412 "hasAttachment": true, 2413 "from": [{ 2414 "email": "jdoe@example.com", 2415 "name": "Jane Doe" 2416 }], 2417 "subject": "The Big Reveal", 2418 "receivedAt": "2018-06-27T00:20:35Z", 2419 "size": 175047, 2420 "preview": "As you may be aware, we are required to prepare a 2421 presentation where we wow a panel of 5 random members of the 2422 public, on or before 30 June each year. We have drafted ..." 2423 }, 2424 ... 2425 ], 2426 "notFound": [] 2427 }, "3" ]] 2429 Now, on another device the user marks the first message as unread, 2430 sending this API request: 2432 [[ "Email/set", { 2433 "accountId": "ue150411c", 2434 "update": { 2435 "Ma783e5cdf5f2deffbc97930a": { 2436 "keywords/$seen": null 2437 } 2438 } 2439 }, "0" ]] 2441 The server applies this and sends the success response: 2443 [[ "Email/set", { 2444 "accountId": "ue150411c", 2445 "oldState": "780605", 2446 "newState": "780606", 2447 "updated": { 2448 "Ma783e5cdf5f2deffbc97930a": null 2449 }, 2450 ... 2451 }, "0" ]] 2453 The user also deletes a few messages, and then a new message arrives. 2455 Back on our original machine, we receive a push update that the state 2456 string for Email is now "780800". As this does not match the 2457 client's current state, it issues a request for the changes: 2459 [[ "Email/changes", { 2460 "accountId": "ue150411c", 2461 "sinceState": "780605", 2462 "maxChanges": 50 2463 }, "3" ], 2464 [ "Email/queryChanges", { 2465 "accountId": "ue150411c", 2466 "filter": { 2467 "inMailbox": "fb666a55" 2468 }, 2469 "sort": [{ 2470 "property": "receivedAt", 2471 "isAscending": false 2472 }], 2473 "collapseThreads": true, 2474 "sinceQueryState": "09aa9a075588-780599:0", 2475 "upToId": "Mc2781d5e856a908d8a35a564", 2476 "maxChanges": 25, 2477 "calculateTotal": true 2478 }, "11" ]] 2480 The response: 2482 [[ "Email/changes", { 2483 "accountId": "ue150411c", 2484 "oldState": "780605", 2485 "newState": "780800", 2486 "hasMoreChanges": false, 2487 "created": [ "Me8de6c9f6de198239b982ea2" ], 2488 "updated": [ "Ma783e5cdf5f2deffbc97930a" ], 2489 "destroyed": [ "M9bd17497e2a99cb345fc1d0a", ... ] 2490 }, "3" ], 2491 [ "Email/queryChanges", { 2492 "accountId": "ue150411c", 2493 "oldQueryState": "09aa9a075588-780599:0", 2494 "newQueryState": "e35e9facf117-780615:0", 2495 "added": [{ 2496 "id": "Me8de6c9f6de198239b982ea2", 2497 "index": 0 2498 }], 2499 "removed": [ "M9bd17497e2a99cb345fc1d0a" ], 2500 "total": 115 2501 }, "11" ]] 2503 The client can update its local cache of the query results by 2504 removing "M9bd17497e2a99cb345fc1d0a" and then splicing in 2505 "Me8de6c9f6de198239b982ea2" at position 0. As it does not have the 2506 data for this new email, it will then fetch it (it also could have 2507 done this in the same request using back-references). 2509 It knows something has changed about "Ma783e5cdf5f2deffbc97930a", so 2510 it will refetch the mailboxes and keywords (the only mutable 2511 properties) for this email too. 2513 The user composes a new message and saves a draft. The client sends: 2515 [[ "Email/set", { 2516 "accountId": "ue150411c", 2517 "create": { 2518 "k1546": { 2519 "mailboxIds": { 2520 "2ea1ca41b38e": true 2521 }, 2522 "keywords": { 2523 "$seen": true, 2524 "$draft": true 2525 }, 2526 "from": [{ 2527 "name": "Joe Bloggs", 2528 "email": "joe@example.com" 2529 }], 2530 "to": [{ 2531 "name": "John", 2532 "email": "john@example.com" 2533 }], 2534 "subject": "World domination", 2535 "receivedAt": "2018-07-10T01:05:08Z", 2536 "sentAt": "2018-07-10T11:05:08+10:00", 2537 "bodyStructure": { 2538 "type": "multipart/alternative", 2539 "subParts": [{ 2540 "partId": "49db", 2541 "type": "text/html" 2542 }, { 2543 "partId": "bd48", 2544 "type": "text/plain" 2545 }] 2546 }, 2547 "bodyValues": { 2548 "bd48": { 2549 "value": "I have the most brilliant plan. Let me tell you 2550 all about it. What we do is, we", 2551 "isTruncated": false 2552 }, 2553 "49db": { 2554 "value": " 2555 2556

", 2558 "isTruncated": false 2559 } 2560 } 2561 } 2562 } 2563 }, "0" ]] 2565 The server creates the message and sends the success response: 2567 [[ "Email/set", { 2568 "accountId": "ue150411c", 2569 "oldState": "780823", 2570 "newState": "780839", 2571 "created": { 2572 "k1546": { 2573 "id": "Md45b47b4877521042cec0938", 2574 "blobId": "Ge8de6c9f6de198239b982ea214e0f3a704e4af74", 2575 "threadId": "Td957e72e89f516dc", 2576 "size": 11721 2577 } 2578 }, 2579 ... 2580 }, "0" ]] 2582 The client moves this draft to a different account. The only way to 2583 do this is via the "/copy" method. It MUST set a new mailboxIds 2584 property, since the current value will not be valid mailbox ids in 2585 the destination account: 2587 [[ "Email/copy", { 2588 "fromAccountId": "ue150411c", 2589 "accountId": "6c6c41ac", 2590 "create": { 2591 "k45": { 2592 "id": "Md45b47b4877521042cec0938", 2593 "mailboxIds": { 2594 "75a4c956": true 2595 } 2596 } 2597 }, 2598 "onSuccessDestroyOriginal": true 2599 }, "0" ]] 2601 The server successfully copies the email and deletes the original. 2602 Due to the implicit call to "Email/set", there are two responses to 2603 the single method call, both with the same client id: 2605 [[ "Email/copy", { 2606 "fromAccountId": "ue150411c", 2607 "accountId": "6c6c41ac", 2608 "oldState": "7ee7e9263a6d", 2609 "newState": "5a0d2447ed26", 2610 "created": { 2611 "k45": { 2612 "id": "M138f9954a5cd2423daeafa55", 2613 "blobId": "G6b9fb047cba722c48c611e79233d057c6b0b74e8", 2614 "threadId": "T2f242ea424a4079a", 2615 "size": 11721 2616 } 2617 }, 2618 "notCreated": null 2619 }, "0" ], 2620 [ "Email/set", { 2621 "accountId": "ue150411c", 2622 "oldState": "780839", 2623 "newState": "780871", 2624 "destroyed": [ "Md45b47b4877521042cec0938" ], 2625 ... 2626 }, "0" ]] 2628 5. Search snippets 2630 When doing a search on a "String" property, the client may wish to 2631 show the relevant section of the body that matches the search as a 2632 preview instead of the beginning of the message, and to highlight any 2633 matching terms in both this and the subject of the email. Search 2634 snippets represent this data. 2636 A *SearchSnippet* object has the following properties: 2638 o *emailId*: "Id" The email id the snippet applies to. 2640 o *subject*: "String|null" If text from the filter matches the 2641 subject, this is the subject of the email with the following 2642 transformations: 2644 1. Any instance of the following three characters MUST be 2645 replaced by an appropriate [HTML] entity: & (ampersand), < 2646 (less-than sign), and > (greater-than sign). Other characters 2647 MAY also be replaced with an HTML entity form. 2649 2. The matching words/phrases from the filter are wrapped in HTML 2650 "" tags. 2652 If the subject does not match text from the filter, this property 2653 is "null". 2655 o *preview*: "String|null" If text from the filter matches the 2656 plain-text or HTML body, this is the relevant section of the body 2657 (converted to plain text if originally HTML), with the same 2658 transformations as the _subject_ property. It MUST NOT be bigger 2659 than 255 octets in size. If the body does not contain a match for 2660 the text from the filter, this property is "null". 2662 It is server-defined what is a relevant section of the body for 2663 preview. If the server is unable to determine search snippets, it 2664 MUST return "null" for both the _subject_ and _preview_ properties. 2666 Note, unlike most data types, a SearchSnippet DOES NOT have a 2667 property called "id". 2669 The following JMAP method is supported: 2671 5.1. SearchSnippet/get 2673 To fetch search snippets, make a call to "SearchSnippet/get". It 2674 takes the following arguments: 2676 o *accountId*: "Id" The id of the account to use. 2678 o *filter*: "FilterOperator|FilterCondition|null" The same filter as 2679 passed to Email/query; see the description of this method in 2680 section 4.4 for details. 2682 o *emailIds*: "Id[]" The ids of the emails to fetch snippets for. 2684 The response has the following arguments: 2686 o *accountId*: "Id" The id of the account used for the call. 2688 o *list*: "SearchSnippet[]" An array of SearchSnippet objects for 2689 the requested email ids. This may not be in the same order as the 2690 ids that were in the request. 2692 o *notFound*: "Id[]|null" An array of email ids requested which 2693 could not be found, or "null" if all ids were found. 2695 As the search snippets are derived from the message content and the 2696 algorithm for doing so could change over time, fetching the same 2697 snippets a second time MAY return a different result. However, the 2698 previous value is not considered incorrect, so there is no state 2699 string or update mechanism needed. 2701 The following standard errors may be returned instead of the 2702 _searchSnippets_ response: 2704 "requestTooLarge": The number of _emailIds_ requested by the client 2705 exceeds the maximum number the server is willing to process in a 2706 single method call. 2708 "unsupportedFilter": The server is unable to process the given 2709 _filter_ for any reason. 2711 5.2. Example 2713 Here we did an Email/query to search for any email in the account 2714 containing the word "foo", now we are fetching the search snippets 2715 for some of the ids that were returned in the results: 2717 [[ "SearchSnippet/get", { 2718 "accountId": "ue150411c", 2719 "filter": { 2720 "text": "foo" 2721 }, 2722 "emailIds": [ 2723 "M44200ec123de277c0c1ce69c", 2724 "M7bcbcb0b58d7729686e83d99", 2725 "M28d12783a0969584b6deaac0", 2726 ... 2727 ] 2728 }, "0" ]] 2730 Example response: 2732 [[ "SearchSnippet/get", { 2733 "accountId": "ue150411c", 2734 "list": [{ 2735 "emailId": "M44200ec123de277c0c1ce69c", 2736 "subject": null, 2737 "preview": null 2738 }, { 2739 "emailId": "M7bcbcb0b58d7729686e83d99", 2740 "subject": "The Foosball competition", 2741 "preview": "...year the foosball competition will 2742 be held in the Stadium de ..." 2743 }, { 2744 "emailId": "M28d12783a0969584b6deaac0", 2745 "subject": null, 2746 "preview": "...the Foo/bar method results often 2747 returns <1 widget rather than the complete..." 2748 }, 2749 ... 2750 ], 2751 "notFound": null 2752 }, "0" ]] 2754 6. Identities 2756 An *Identity* object stores information about an email address (or 2757 domain) the user may send from. It has the following properties: 2759 o *id*: "Id" (immutable; server-set) The id of the identity. 2761 o *name*: "String" (default: "") The "From" _name_ the client SHOULD 2762 use when creating a new message from this identity. 2764 o *email*: "String" (immutable) The "From" email address the client 2765 MUST use when creating a new message from this identity. The 2766 value MAY alternatively be of the form "*@example.com", in which 2767 case the client may use any valid email address ending in 2768 "@example.com". 2770 o *replyTo*: "EmailAddress[]|null" (default: null) The Reply-To 2771 value the client SHOULD set when creating a new message from this 2772 identity. 2774 o *bcc*: "EmailAddress[]|null" (default: null) The Bcc value the 2775 client SHOULD set when creating a new message from this identity. 2777 o *textSignature*: "String" (default: "") Signature the client 2778 SHOULD insert into new plain-text messages that will be sent from 2779 this identity. Clients MAY ignore this and/or combine this with a 2780 client-specific signature preference. 2782 o *htmlSignature*: "String" (default: "") Signature the client 2783 SHOULD insert into new HTML messages that will be sent from this 2784 identity. This text MUST be an HTML snippet to be inserted into 2785 the "" section of the new email. Clients MAY ignore 2786 this and/or combine this with a client-specific signature 2787 preference. 2789 o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete 2790 this identity? Servers may wish to set this to "false" for the 2791 user's username or other default address. Attempts to destroy an 2792 identity with "mayDelete: false" will be rejected with a standard 2793 "forbidden" SetError. 2795 See the "Addresses" header form description in the Email object for 2796 the definition of _EmailAddress_. 2798 Multiple identities with the same email address MAY exist, to allow 2799 for different settings the user wants to pick between (for example 2800 with different names/signatures). 2802 The following JMAP methods are supported: 2804 6.1. Identity/get 2806 Standard "/get" method. The _ids_ argument may be "null" to fetch 2807 all at once. 2809 6.2. Identity/changes 2811 Standard "/changes" method. 2813 6.3. Identity/set 2815 Standard "/set" method. The following extra _SetError_ types are 2816 defined: 2818 For *create*: 2820 o "forbiddenFrom": The user is not allowed to send from the address 2821 given as the _email_ property of the identity. 2823 6.4. Example 2825 Request: 2827 [ "Identity/get", { 2828 "accountId": "acme" 2829 }, "0" ] 2831 with response: 2833 [ "Identity/get", { 2834 "accountId": "acme", 2835 "state": "99401312ae-11-333", 2836 "list": [ 2837 { 2838 "id": "3301-222-11_22AAz", 2839 "name": "Joe Bloggs", 2840 "email": "joe@example.com", 2841 "replyTo": null, 2842 "bcc": [{ 2843 "name": null, 2844 "email": "joe+archive@example.com" 2845 }], 2846 "textSignature": "-- \nJoe Bloggs\nMaster of Email", 2847 "htmlSignature": "
Joe Bloggs
2848
Master of Email
", 2849 "mayDelete": false 2850 }, 2851 { 2852 "id": "9911312-11_22AAz", 2853 "name": "Joe B", 2854 "email": "*@example.com", 2855 "replyTo": null, 2856 "bcc": null, 2857 "textSignature": "", 2858 "htmlSignature": "", 2859 "mayDelete": true 2860 } 2861 ], 2862 "notFound": [] 2863 }, "0" ] 2865 7. Email submission 2867 An *EmailSubmission* object represents the submission of an email for 2868 delivery to one or more recipients. It has the following properties: 2870 o *id*: "Id" (immutable; server-set) The id of the email submission. 2872 o *identityId*: "Id" (immutable) The id of the identity to associate 2873 with this submission. 2875 o *emailId*: "Id" (immutable) The id of the email to send. The 2876 email being sent does not have to be a draft, for example when 2877 "redirecting" an existing email to a different address. 2879 o *threadId*: "Id" (immutable; server-set) The thread id of the 2880 email to send. This is set by the server to the _threadId_ 2881 property of the email referenced by the _emailId_. 2883 o *envelope*: "Envelope|null" (immutable) Information for use when 2884 sending via SMTP. An *Envelope* object has the following 2885 properties: 2887 * *mailFrom*: "Address" The email address to use as the return 2888 address in the SMTP submission, plus any parameters to pass 2889 with the MAIL FROM address. The JMAP server MAY allow the 2890 address to be the empty string. When a JMAP server performs an 2891 SMTP message submission, it MAY use the same id string for the 2892 [RFC3461] ENVID parameter and the EmailSubmission object id. 2893 Servers that do this MAY replace a client-provided value for 2894 ENVID with a server-provided value. 2896 * *rcptTo*: "Address[]" The email addresses to send the message 2897 to, and any RCPT TO parameters to pass with the recipient. 2899 An *Address* object has the following properties: 2901 * *email*: "String" The email address being represented by the 2902 object. This is a "Mailbox" as used in the Reverse-path or 2903 Forward-path of the MAIL FROM or RCPT TO command in [RFC5321]. 2905 * *parameters*: "Object|null" Any parameters to send with the 2906 email (either mail-parameter or rcpt-parameter as appropriate, 2907 as specified in [RFC5321]). If supplied, each key in the 2908 object is a parameter name, and the value either the parameter 2909 value (type "String") or if the parameter does not take a value 2910 then "null". For both name and value, any xtext or unitext 2911 encodings are removed ([RFC3461], [RFC6533]) and JSON string 2912 encoding applied. 2914 If the _envelope_ property is "null" or omitted on creation, the 2915 server MUST generate this from the referenced email as follows: 2917 * *mailFrom*: The email in the _Sender_ header, if present, 2918 otherwise the _From_ header, if present, and no parameters. If 2919 multiple addresses are present in one of these headers, or 2920 there is more than one _Sender_/_From_ header, the server 2921 SHOULD reject the email as invalid but otherwise MUST take the 2922 first address in the last _Sender_/_From_ header in the 2923 [RFC5322] version of the message. If the address found from 2924 this is not allowed by the identity associated with this 2925 submission, the _email_ property from the identity MUST be used 2926 instead. 2928 * *rcptTo*: The deduplicated set of email addresses from the 2929 _To_, _Cc_ and _Bcc_ headers, if present, with no parameters 2930 for any of them. 2932 o *sendAt*: "UTCDate" (immutable; server-set) The date the email 2933 was/will be released for delivery. If the client successfully 2934 used [RFC4865] FUTURERELEASE with the email, this MUST be the time 2935 when the server will release the email; otherwise it MUST be the 2936 time the EmailSubmission was created. 2938 o *undoStatus*: "String" This represents whether the submission may 2939 be canceled. This is server set and MUST be one of the following 2940 values: 2942 * "pending": It MAY be possible to cancel this submission. 2944 * "final": The email has been relayed to at least one recipient 2945 in a manner that cannot be recalled. It is no longer possible 2946 to cancel this submission. 2948 * "canceled": The email submission was canceled and will not be 2949 delivered to any recipient. 2951 On systems that do not support unsending, the value of this 2952 property will always be "final". On systems that do support 2953 canceling submission, it will start as "pending", and MAY 2954 transition to "final" when the server knows it definitely cannot 2955 recall the email, but MAY just remain "pending". If in pending 2956 state, a client can attempt to cancel the submission by setting 2957 this property to "canceled"; if the update succeeds, the 2958 submission was successfully canceled and the email has not been 2959 delivered to any of the original recipients. 2961 o *deliveryStatus*: "String[DeliveryStatus]|null" (server-set) This 2962 represents the delivery status for each of the email's recipients, 2963 if known. This property MAY not be supported by all servers, in 2964 which case it will remain "null". Servers that support it SHOULD 2965 update the EmailSubmission object each time the status of any of 2966 the recipients changes, even if some recipients are still being 2967 retried. This value is a map from the email address of each 2968 recipient to a _DeliveryStatus_ object. A *DeliveryStatus* object 2969 has the following properties: 2971 * *smtpReply*: "String" The SMTP reply string returned for this 2972 recipient when the server last tried to relay the email, or in 2973 a later DSN (Delivery Status Notification, as defined in 2974 [RFC3464]) response for the email. This SHOULD be the response 2975 to the RCPT TO stage, unless this was accepted and the email as 2976 a whole rejected at the end of the DATA stage, in which case 2977 the DATA stage reply SHOULD be used instead. Multi-line SMTP 2978 responses should be concatenated to a single string as follows: 2980 + The hyphen following the SMTP code on all but the last line 2981 is replaced with a space. 2983 + Any prefix in common with the first line is stripped from 2984 lines after the first. 2986 + CRLF is replaced by a space. 2988 For example: 2990 550-5.7.1 Our system has detected that this message is 2991 550 5.7.1 likely spam. 2993 would become: 2995 550 5.7.1 Our system has detected that this message is likely spam. 2997 For emails relayed via an alternative to SMTP, the server MAY 2998 generate a synthetic string representing the status instead. 2999 If it does this, the string MUST be of the following form: 3001 + A 3-digit SMTP reply code, as defined in [RFC5321], section 3002 4.2.3. 3004 + Then a single space character. 3006 + Then an SMTP Enhanced Mail System Status Code as defined in 3007 [RFC3463], with a registry defined in [RFC5248]. 3009 + Then a single space character. 3011 + Then an implementation-specific information string with a 3012 human readable explanation of the response. 3014 * *delivered*: "String" Represents whether the email has been 3015 successfully delivered to the recipient. This MUST be one of 3016 the following values: 3018 + "queued": The email is in a local mail queue and status will 3019 change once it exits the local mail queues. The _smtpReply_ 3020 property may still change. 3022 + "yes": The email was successfully delivered to the mailbox 3023 of the recipient. The _smtpReply_ property is final. 3025 + "no": Delivery to the recipient permanently failed. The 3026 _smtpReply_ property is final. 3028 + "unknown": The final delivery status is unknown, (e.g. it 3029 was relayed to an external machine and no further 3030 information is available). The _smtpReply_ property may 3031 still change if a DSN arrives. 3033 Note, successful relaying to an external SMTP server SHOULD NOT 3034 be taken as an indication that the email has successfully 3035 reached the final mailbox. In this case though, the server may 3036 receive a DSN response, if requested. If a DSN is received for 3037 the recipient with Action equal to "delivered", as per 3038 [RFC3464] section 2.3.3, then the _delivered_ property SHOULD 3039 be set to "yes"; if the Action equals "failed", the property 3040 SHOULD be set to "no". Receipt of any other DSN SHOULD NOT 3041 affect this property. The server MAY also set this property 3042 based on other feedback channels. 3044 * *displayed*: "String" Represents whether the email has been 3045 displayed to the recipient. This MUST be one of the following 3046 values: 3048 + "unknown": The display status is unknown. This is the 3049 initial value. 3051 + "yes": The recipient's system claims the email content has 3052 been displayed to the recipient. Note, there is no 3053 guarantee that the recipient has noticed, read, or 3054 understood the content. 3056 If an MDN is received for this recipient with Disposition-Type 3057 (as per [RFC8098] section 3.2.6.2) equal to "displayed", this 3058 property SHOULD be set to "yes". The server MAY also set this 3059 property based on other feedback channels. 3061 o *dsnBlobIds*: "Id[]" (server-set) A list of blob ids for Delivery 3062 Status Notifications ([RFC3464]) received for this submission, in 3063 order of receipt, oldest first. The blob is the whole MIME 3064 message (with a top-level content-type of multipart/report), as 3065 received. 3067 o *mdnBlobIds*: "Id[]" (server-set) A list of blob ids for Message 3068 Disposition Notifications ([RFC8098]) received for this 3069 submission, in order of receipt, oldest first. The blob is the 3070 whole MIME message (with a top-level content-type of multipart/ 3071 report), as received. 3073 JMAP servers MAY choose not to expose DSN and MDN responses as Email 3074 objects if they correlate to an EmailSubmission object. It SHOULD 3075 only do this if it exposes them in the _dsnBlobIds_ and _mdnblobIds_ 3076 fields instead, and expects the user to be using clients capable of 3077 fetching and displaying delivery status via the EmailSubmission 3078 object. 3080 For efficiency, a server MAY destroy EmailSubmission objects a 3081 certain amount of time after the email is successfully sent or it has 3082 finished retrying sending the email. For very basic SMTP proxies, 3083 this MAY be immediately after creation, as it has no way to assign a 3084 real id and return the information again if fetched later. 3086 The following JMAP methods are supported: 3088 7.1. EmailSubmission/get 3090 Standard "/get" method. 3092 7.2. EmailSubmission/changes 3094 Standard "/changes" method. 3096 7.3. EmailSubmission/query 3098 Standard "/query" method. 3100 A *FilterCondition* object has the following properties, any of which 3101 may be omitted: 3103 o *emailIds*: "Id[]" The EmailSubmission _emailId_ property must be 3104 in this list to match the condition. 3106 o *threadIds*: "Id[]" The EmailSubmission _threadId_ property must 3107 be in this list to match the condition. 3109 o *undoStatus*: "String" The EmailSubmission _undoStatus_ property 3110 must be identical to the value given to match the condition. 3112 o *before*: "UTCDate" The _sendAt_ property of the EmailSubmission 3113 object must be before this date-time to match the condition. 3115 o *after*: "UTCDate" The _sendAt_ property of the EmailSubmission 3116 object must be the same as or after this date-time to match the 3117 condition. 3119 An EmailSubmission object matches the filter if and only if all of 3120 the given conditions match. If zero properties are specified, it is 3121 automatically "true" for all objects. 3123 The following properties MUST be supported for sorting: 3125 o "emailId" 3127 o "threadId" 3129 o "sentAt" 3131 7.4. EmailSubmission/queryChanges 3133 Standard "/queryChanges" method. 3135 7.5. EmailSubmission/set 3137 Standard "/set" method, with the following two extra arguments: 3139 o *onSuccessUpdateEmail*: "Id[Email]|null" A map of _EmailSubmission 3140 id_ to an object containing properties to update on the Email 3141 object referenced by the EmailSubmission if the create/update/ 3142 destroy succeeds. (For references to EmailSubmission creations, 3143 this is equivalent to a back-reference so the id will be the 3144 creation id prefixed with a "#".) 3146 o *onSuccessDestroyEmail*: "Id[]|null" A list of _EmailSubmission 3147 ids_ for which the email with the corresponding emailId should be 3148 destroyed if the create/update/destroy succeeds. (For references 3149 to EmailSubmission creations, this is equivalent to a back- 3150 reference so the id will be the creation id prefixed with a "#".) 3152 A single implicit _Email/set_ call MUST be made after all 3153 EmailSubmission create/update/destroy requests have been processed to 3154 perform any changes requested in these two arguments. The response 3155 to this MUST be returned after the _EmailSubmission/set_ response. 3157 An email is sent by creating an EmailSubmission object. When 3158 processing each create, the server must check that the email is 3159 valid, and the user has sufficient authorization to send it. If the 3160 creation succeeds, the email will be sent to the recipients given in 3161 the envelope _rcptTo_ parameter. The server MUST remove any _Bcc_ 3162 header present on the email during delivery. The server MAY add or 3163 remove other headers from the submitted email, or make further 3164 alterations in accordance with the server's policy during delivery. 3166 If the referenced email is destroyed at any point after the 3167 EmailSubmission object is created, this MUST NOT change the behaviour 3168 of the email submission (i.e. it does not cancel a future send). 3170 Similarly, destroying an EmailSubmission object MUST NOT affect the 3171 deliveries it represents. It purely removes the record of the email 3172 submission. The server MAY automatically destroy EmailSubmission 3173 objects after a certain time or in response to other triggers, and 3174 MAY forbid the client from manually destroying EmailSubmission 3175 objects. 3177 If the email to be sent is larger than the server supports sending, a 3178 standard "tooLarge" SetError MUST be returned. A _maxSize_ 3179 "PositiveInt" property MUST be present on the SetError specifying the 3180 maximum size of an email that may be sent, in octets. 3182 If the email or identity id given cannot be found, the submission 3183 creation is rejected with a standard "invalidProperties" SetError. 3185 The following extra _SetError_ types are defined: 3187 For *create*: 3189 o "invalidEmail" - The email to be sent is invalid in some way. The 3190 SetError SHOULD contain a property called _properties_ of type 3191 "String[]" that lists *all* the properties of the email that were 3192 invalid. 3194 o "tooManyRecipients" - The envelope (supplied or generated) has 3195 more recipients than the server allows. A _maxRecipients_ 3196 "PositiveInt" property MUST also be present on the SetError 3197 specifying the maximum number of allowed recipients. 3199 o "noRecipients" - The envelope (supplied or generated) does not 3200 have any rcptTo emails. 3202 o "invalidRecipients" - The _rcptTo_ property of the envelope 3203 (supplied or generated) contains at least one rcptTo value which 3204 is not a valid email for sending to. An _invalidRecipients_ 3205 "String[]" property MUST also be present on the SetError, which is 3206 a list of the invalid addresses. 3208 o "forbiddenMailFrom" - The server does not permit the user to send 3209 an email with the [RFC5321] envelope From. 3211 o "forbiddenFrom" - The server does not permit the user to send an 3212 email with the [RFC5322] From header of the email to be sent. 3214 o "forbiddenToSend" - The user does not have permission to send at 3215 all right now for some reason. A _description_ "String" property 3216 MAY be present on the SetError object to display to the user why 3217 they are not permitted. 3219 For *update*: 3221 o "cannotUnsend": The client attempted to update the _undoStatus_ of 3222 a valid EmailSubmission object from "pending" to "canceled", but 3223 the email cannot be unsent. 3225 7.5.1. Example 3227 The following example presumes a draft of the message to be sent has 3228 already been saved, and its Email id is "M7f6ed5bcfd7e2604d1753f6c". 3229 This call then sends the email immediately, and if successful removes 3230 the draft flag and moves it from the Drafts folder (which has Mailbox 3231 id "7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e") to the Sent folder (which 3232 we presume has Mailbox id "73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6"). 3234 [[ "EmailSubmission/set", { 3235 "accountId": "ue411d190", 3236 "create": { 3237 "k1490": { 3238 "identityId": "64588216", 3239 "emailId": "M7f6ed5bcfd7e2604d1753f6c", 3240 "envelope": { 3241 "mailFrom": { 3242 "email": "john@example.com", 3243 "parameters": null 3244 }, 3245 "rcptTo": [{ 3246 "email": "jane@example.com", 3247 "parameters": null 3248 }, 3249 ... 3250 ] 3251 } 3252 } 3253 }, 3254 "onSuccessUpdateEmail": { 3255 "#k1490": { 3256 "mailboxIds/7cb4e8ee-df87-4757-b9c4-2ea1ca41b38e": null, 3257 "mailboxIds/73dbcb4b-bffc-48bd-8c2a-a2e91ca672f6": true, 3258 "keywords/$draft": null 3259 } 3260 } 3261 }, "0" ]] 3263 A successful response might look like this. Note there are two 3264 responses due to the implicit Email/set call, but both have the same 3265 client id as they are due to the same call in the request: 3267 [[ "EmailSubmission/set", { 3268 "accountId": "ue411d190", 3269 "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", 3270 "newState": "355421f6-8aed-4cf4-a0c4-7377e951af36", 3271 "created": { 3272 "k1490": { 3273 "id": "3bab7f9a-623e-4acf-99a5-2e67facb02a0" 3274 } 3275 } 3276 }, "0" ], 3277 [ "Email/set", { 3278 "accountId": "ue411d190", 3279 "oldState": "778193", 3280 "newState": "778197", 3281 "updated": { 3282 "M7f6ed5bcfd7e2604d1753f6c": null 3283 } 3284 }, "0" ]] 3286 Suppose instead an admin has removed sending rights for the user, and 3287 so the email submission is rejected with a "forbiddenToSend" error. 3288 The description argument of the error is intended for display to the 3289 user, so should be localised appropriately. Let's suppose the 3290 request was sent with an Accept-Language header like this: 3292 Accept-Language: de;q=0.9,en;q=0.8 3294 The server should attempt to choose the best localisation from those 3295 it has available based on the Accept-Language header, as described in 3296 [I-D.ietf-jmap-core], section 3.7. If the server has English, French 3297 and German translations it would choose German as the preferred 3298 language and return a response like this: 3300 [[ "EmailSubmission/set", { 3301 "accountId": "ue411d190", 3302 "oldState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", 3303 "newState": "012421s6-8nrq-4ps4-n0p4-9330r951ns21", 3304 "notCreated": { 3305 "k1490": { 3306 "type": "forbiddenToSend", 3307 "description": "Verzeihung, wegen verdaechtiger Aktivitaeten Ihres Benutzerkontos haben wir den Versand von Nachrichten gesperrt. Bitte wenden Sie sich fuer Hilfe an unser Support Team." 3308 } 3309 } 3310 }, "0" ]] 3311 8. Vacation response 3313 A vacation response automatically sends a reply to messages sent to a 3314 particular account, to inform the original sender that their message 3315 may not be read for some time. Automated message sending can produce 3316 undesirable behaviour. To avoid this, implementors MUST follow the 3317 recommendations set forth in [RFC3834]. 3319 The *VacationResponse* object represents the state of vacation- 3320 response related settings for an account. It has the following 3321 properties: 3323 o *id*: "Id" (immutable; server-set) The id of the object. There is 3324 only ever one vacation response object, and its id is 3325 ""singleton"". 3327 o *isEnabled*: "Boolean" Should a vacation response be sent if an 3328 email arrives between the _fromDate_ and _toDate_? 3330 o *fromDate*: "UTCDate|null" If _isEnabled_ is "true" emails that 3331 arrive on or after this date-time should receive the user's 3332 vacation response. If "null", the vacation response is effective 3333 immediately. 3335 o *toDate*: "UTCDate|null" If _isEnabled_ is "true", emails that 3336 arrive before this date-time should receive the user's vacation 3337 response. If "null", the vacation response is effective 3338 indefinitely. 3340 o *subject*: "String|null" The subject that will be used by the 3341 message sent in response to emails when the vacation response is 3342 enabled. If "null", an appropriate subject SHOULD be set by the 3343 server. 3345 o *textBody*: "String|null" The plain text body to send in response 3346 to emails when the vacation response is enabled. If this is 3347 "null", when the vacation message is sent a plain-text body part 3348 SHOULD be generated from the _htmlBody_ but the server MAY choose 3349 to send the response as HTML only. If both _textBody_ and 3350 _htmlBody_ are "null", an appropriate default body SHOULD be 3351 generated for responses by the server. 3353 o *htmlBody*: "String|null" The HTML body to send in response to 3354 emails when the vacation response is enabled. If this is "null", 3355 when the vacation message is sent an HTML body part MAY be 3356 generated from the _textBody_, or the server MAY choose to send 3357 the response as plain-text only. 3359 The following JMAP methods are supported: 3361 8.1. VacationResponse/get 3363 Standard "/get" method. 3365 There MUST only be exactly one VacationResponse object in an account. 3366 It MUST have the id "singleton". 3368 8.2. VacationResponse/set 3370 Standard "/set" method. 3372 9. Security considerations 3374 All security considerations of JMAP ([I-D.ietf-jmap-core]) apply to 3375 this specification. 3377 9.1. EmailBodyPart value 3379 Service providers typically perform security filtering on incoming 3380 email and it's important that the detection of content-type and 3381 charset for the security filter aligns with the heuristics performed 3382 by JMAP servers. Servers that apply heuristics to determine the 3383 content-type or charset for _EmailBodyValue_ SHOULD document the 3384 heuristics and provide a mechanism to turn them off in the event they 3385 are misaligned with the security filter used at a particular mailbox 3386 host. 3388 Automatic conversion of charsets that allow hidden channels for ASCII 3389 text, such as UTF-7, have been problematic for security filters in 3390 the past so server implementations can mitigate this risk by having 3391 such conversions off-by-default and/or separately configurable. 3393 To allow the client to restrict the volume of data it can receive in 3394 response to a request, a maximum length may be requested for the data 3395 returned for a textual body part. However, truncating the data may 3396 change the semantic meaning, for example truncating a URL changes its 3397 location. Servers that scan for links to malicious sites should take 3398 care to either ensure truncation is not at a semantically significant 3399 point, or to rescan the truncated value for malicious content before 3400 returning it. 3402 9.2. HTML email display 3404 HTML message bodies provide richer formatting for emails but present 3405 a number of security challenges, especially when embedded in a 3406 webmail context in combination with interface HTML. Clients that 3407 render HTML email should make careful consideration of the potential 3408 risks, including: 3410 o Embedded JavaScript can rewrite the email to change its content on 3411 subsequent opening, allowing users to be mislead. In webmail 3412 systems, if run in the same origin as the interface it can access 3413 and exfiltrate all private data accessible to the user, including 3414 all other emails and potentially contacts, calendar events, 3415 settings, and credentials. It can also rewrite the interface to 3416 undetectably phish passwords. A compromise is likely to be 3417 persistent, not just for the duration of page load, due to 3418 exfiltration of session credentials or installation of a service 3419 worker that can intercept all subsequent network requests (this 3420 however would only be possible if blob downloads are also 3421 available on the same origin, and the service worker script is 3422 attached to the message). 3424 o HTML documents may load content directly from the internet, rather 3425 than just referencing attached resources. For example you may 3426 have an "" tag with an external "src" attribute. This may 3427 leak to the sender when a message is opened, as well as the IP 3428 address of the recipient. Cookies may also be sent and set by the 3429 server, allowing tracking between different emails and even 3430 website visits and advertising profiles. 3432 o In webmail systems, CSS can break the layout or create phishing 3433 vulnerabilities. For example, the use of "position:fixed" can 3434 allow an email to draw content outside of its normal bounds, 3435 potentially clickjacking a real interface element. 3437 o If in a webmail context and not inside a separate frame, any 3438 styles defined in CSS rules will apply to interface elements as 3439 well if the selector matches, allowing the interface to be 3440 modified. Similarly, any interface styles that match elements in 3441 the email will alter their appearance, potentially breaking the 3442 layout of the email. 3444 o The link text in HTML has no necessary correlation with the actual 3445 target of the link, which can be used to make phishing attacks 3446 more convincing. 3448 o Links opened from an email or embedded external content may leak 3449 private info in the "Referer" header sent by default in most 3450 systems. 3452 o Forms can be used to mimic login boxes, providing a potent 3453 phishing vector if allowed to submit directly from the email 3454 display. 3456 There are a number of ways clients can mitigate these issues, and a 3457 defence-in-depth approach that uses a combination of techniques will 3458 provide the strongest security. 3460 o HTML can be filtered before rendering, stripping potentially 3461 malicious content. Sanitizing HTML correctly is tricky, and 3462 implementers are strongly recommended to use a well-tested library 3463 with a carefully vetted whitelist-only approach. New features 3464 with unexpected security characteristics may be added to HTML 3465 rendering engines in the future; a blacklist approach is likely to 3466 result in security issues. 3468 Subtle differences in parsing of HTML can introduce security flaws: 3469 to filter with 100% accuracy you need to use the same parser when 3470 sanitizing that the HTML rendering engine will use. 3472 o Encapsulating the message in an "