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

Hello ..." 1367 }, 1368 "2": { 1369 "isEncodingProblem": false, 1370 "isTruncated": false, 1371 "value": "-- \nSent by your friendly mailing list ..." 1372 } 1373 } 1374 } 1375 ], 1376 notFound: [ "f123u456" ] 1377 }, "#1"] 1379 4.3. Email/changes 1381 Standard _/changes_ method. 1383 4.4. Email/query 1385 Standard _/query_ method, but with the following additional 1386 arguments: 1388 o *collapseThreads*: "Boolean" (default: "false") If "true", emails 1389 in the same thread as a previous email in the list (given the 1390 filter and sort order) will be removed from the list. This means 1391 at most only one email will be included in the list for any given 1392 thread. 1394 4.4.1. Filtering 1396 A *FilterCondition* object has the following properties, any of which 1397 may be omitted: 1399 o *inMailbox*: "String" A mailbox id. An email must be in this 1400 mailbox to match the condition. 1402 o *inMailboxOtherThan*: "String[]" A list of mailbox ids. An email 1403 must be in at least one mailbox not in this list to match the 1404 condition. This is to allow messages solely in trash/spam to be 1405 easily excluded from a search. 1407 o *before*: "UTCDate" The _receivedAt_ date of the email must be 1408 before this date to match the condition. 1410 o *after*: "UTCDate" The _receivedAt_ date of the email must be on 1411 or after this date to match the condition. 1413 o *minSize*: "Number" The _size_ of the email in octets must be 1414 equal to or greater than this number to match the condition. 1416 o *maxSize*: "Number" The size of the email in octets must be less 1417 than this number to match the condition. 1419 o *allInThreadHaveKeyword*: "String" All emails (including this one) 1420 in the same thread as this email must have the given keyword to 1421 match the condition. 1423 o *someInThreadHaveKeyword*: "String" At least one email (possibly 1424 this one) in the same thread as this email must have the given 1425 keyword to match the condition. 1427 o *noneInThreadHaveKeyword*: "String" All emails (including this 1428 one) in the same thread as this email must *not* have the given 1429 keyword to match the condition. 1431 o *hasKeyword*: "String" This email must have the given keyword to 1432 match the condition. 1434 o *notKeyword*: "String" This email must not have the given keyword 1435 to match the condition. 1437 o *hasAttachment*: "Boolean" The "hasAttachment" property of the 1438 email must be identical to the value given to match the condition. 1440 o *text*: "String" Looks for the text in emails. The server SHOULD 1441 look up text in the _from_, _to_, _cc_, _bcc_, _subject_ header 1442 fields of the message, and inside any "text/*" or other body parts 1443 that may converted to text by the server. The server MAY extend 1444 the search to any additional textual property. 1446 o *from*: "String" Looks for the text in the _From_ header field of 1447 the message. 1449 o *to*: "String" Looks for the text in the _To_ header field of the 1450 message. 1452 o *cc*: "String" Looks for the text in the _Cc_ header field of the 1453 message. 1455 o *bcc*: "String" Looks for the text in the _Bcc_ header field of 1456 the message. 1458 o *subject*: "String" Looks for the text in the _subject_ property 1459 of the email. 1461 o *body*: "String" Looks for the text in one of the "text/*" body 1462 parts of the email. 1464 o *attachments*: "String" Looks for the text in the attachments of 1465 the email. Server MAY handle text extraction when possible for 1466 the different kinds of media. 1468 o *header*: "String[]" The array MUST contain either one or two 1469 elements. The first element is the name of the header field to 1470 match against. The second (optional) element is the text to look 1471 for in the header field value. If not supplied, the message 1472 matches simply if it _has_ a header field of the given name. 1474 If zero properties are specified on the FilterCondition, the 1475 condition MUST always evaluate to "true". If multiple properties are 1476 specified, ALL must apply for the condition to be "true" (it is 1477 equivalent to splitting the object into one-property conditions and 1478 making them all the child of an AND filter operator). 1480 The exact semantics for matching "String" fields is *deliberately not 1481 defined* to allow for flexibility in indexing implementation, subject 1482 to the following: 1484 o Any syntactically correct [RFC2047] encoded sections of header 1485 fields with a known encoding SHOULD be decoded before attempting 1486 to match text. 1488 o When searching inside a "text/html" body part, any text considered 1489 markup rather than content SHOULD be ignored, including HTML tags 1490 and most attributes, anything inside the "" tag, CSS and 1491 JavaScript. Attribute content intended for presentation to the 1492 user such as "alt" and "title" SHOULD be considered in the search. 1494 o Text SHOULD be matched in a case-insensitive manner. 1496 o Text contained in either (but matched) single or double quotes 1497 SHOULD be treated as a *phrase search*, that is a match is 1498 required for that exact word or sequence of words, excluding the 1499 surrounding quotation marks. Use "\"", "\'" and "\\" to match a 1500 literal """, "'" and "\" respectively in a phrase. 1502 o Outside of a phrase, white-space SHOULD be treated as dividing 1503 separate tokens that may be searched for separately, but MUST all 1504 be present for the email to match the filter. 1506 o Tokens MAY be matched on a whole-word basis using stemming (so for 1507 example a text search for "bus" would match "buses" but not 1508 "business"). 1510 4.4.2. Sorting 1512 The following properties MUST be supported for sorting: 1514 o *receivedAt* - The _receivedAt_ date as returned in the Email 1515 object. 1517 The following properties SHOULD be supported for sorting: 1519 o *size* - The size as returned in the Email object. 1521 o *from* - This is taken to be either the "name" part, or if 1522 "null"/empty then the "email" part, of the *first* EmailAddress 1523 object in the _from_ property. If still none, consider the value 1524 to be the empty string. 1526 o *to* - This is taken to be either the "name" part, or if 1527 "null"/empty then the "email" part, of the *first* EmailAddress 1528 object in the _to_ property. If still none, consider the value to 1529 be the empty string. 1531 o *subject* - This is taken to be the base subject of the email, as 1532 defined in section 2.1 of [RFC5256]. 1534 o *sentAt* - The _sentAt_ property on the Email object. 1536 o *hasKeyword* - This value MUST be considered "true" if the email 1537 has the keyword given as the _keyword_ property on this 1538 _Comparator_ object, or "false" otherwise. 1540 o *allInThreadHaveKeyword* - This value MUST be considered "true" 1541 for the email if *all* of the emails in the same thread 1542 (regardless of mailbox) have the keyword given as the _keyword_ 1543 property on this _Comparator_ object. 1545 o *someInThreadHaveKeyword* - This value MUST be considered "true" 1546 for the email if *any* of the emails in the same thread 1547 (regardless of mailbox) have the keyword given as the _keyword_ 1548 property on this _Comparator_ object. 1550 The server MAY support sorting based on other properties as well. A 1551 client can discover which properties are supported by inspecting the 1552 server's _capabilities_ object (see section 1). 1554 Example sort: 1556 [{ 1557 "property": "someInThreadHaveKeyword", 1558 "keyword": "$flagged", 1559 "isAscending": false, 1560 }, { 1561 "property": "subject", 1562 "collation": "i;ascii-casemap" 1563 }, { 1564 "property": "receivedAt", 1565 "isAscending": false, 1566 }] 1568 This would sort emails in flagged threads first (the thread is 1569 considered flagged if any email within it is flagged), and then in 1570 subject order, then newest first for messages with the same subject. 1571 If two emails have both identical flagged status, subject and date, 1572 the order is server-dependent but must be stable. 1574 4.4.3. Thread collapsing 1576 When "collapseThreads == true", then after filtering and sorting the 1577 email list, the list is further winnowed by removing any emails for a 1578 thread id that has already been seen (when passing through the list 1579 sequentially). A thread will therefore only appear *once* in the 1580 "threadIds" list of the result, at the position of the first email in 1581 the list that belongs to the thread. 1583 4.4.4. Response 1585 The response has the following additional argument: 1587 o *collapseThreads*: "Boolean" The _collapseThreads_ value that was 1588 used when calculating the email list for this call. 1590 4.5. Email/queryChanges 1592 Standard _/queryChanges_ method, with the following additional 1593 arguments: 1595 o *collapseThreads*: "Boolean" (default: "false") The 1596 _collapseThreads_ argument that was used with _Email/query_. 1598 The response has the following additional argument: 1600 o *collapseThreads*: "Boolean" The _collapseThreads_ value that was 1601 used when calculating the email list for this call. 1603 4.6. Email/set 1605 Standard _/set_ method. The _Email/set_ method encompasses: 1607 o Creating a draft 1609 o Changing the keywords of an email (e.g. unread/flagged status) 1611 o Adding/removing an email to/from mailboxes (moving a message) 1613 o Deleting emails 1615 Due to the format of the Email object, when creating an email there 1616 are a number of ways to specify the same information. To ensure that 1617 the RFC5322 email to create is unambiguous, the following constraints 1618 apply to Email objects submitted for creation: 1620 o The _headers_ property MUST NOT be given, on either the top-level 1621 email or an EmailBodyPart - the client must set each header field 1622 as an individual property. 1624 o There MUST NOT be two properties that represent the same header 1625 field (e.g. "header:from" and "from") within the Email or 1626 particular EmailBodyPart. 1628 o Header fields MUST NOT be specified in parsed forms that are 1629 forbidden for that particular field. 1631 o Header fields beginning "Content-" MUST NOT be specified on the 1632 Email object, only on EmailBodyPart objects. 1634 o If a bodyStructure property is given, there MUST NOT be textBody, 1635 htmlBody, attachedFiles or attachedEmails properties. 1637 o If given, the bodyStructure EmailBodyPart MUST NOT contain a 1638 property representing a header field that is already defined on 1639 the top-level Email object. 1641 o If given, textBody MUST contain exactly one body part, of type 1642 "text/plain". 1644 o If given, htmlBody MUST contain exactly one body part, of type 1645 "text/html". 1647 o Within an EmailBodyPart: 1649 * The client may specify a partId OR a blobId but not both. If a 1650 partId is given, this partId MUST be present in the bodyValues 1651 property. 1653 * The charset property MUST be omitted if a partId is given (the 1654 part's content is included in bodyValues and the server may 1655 choose any appropriate encoding). 1657 * The size property MUST be omitted if a partId is given. If a 1658 blobId is given, it may be omitted, but otherwise MUST match 1659 the size of the blob. 1661 * A "Content-Transfer-Encoding" header field MUST NOT be given. 1663 o Within an EmailBodyValue object, isEncodingProblem and isTruncated 1664 MUST be either "false" or omitted. 1666 Creation attempts that violate any of this SHOULD be rejected with an 1667 "invalidProperties" error, however a server MAY choose to modify the 1668 Email (e.g. choose between conflicting headers, use a different 1669 content-encoding etc.) to comply with its requirements instead. 1671 The server MAY also choose to set additional headers. If not 1672 included, the server MUST generate and set a "Message-ID" header 1673 field in conformance with [RFC5322] section 3.6.4, and a "Date" 1674 header field in conformance with section 3.6.1. 1676 The final RFC5322 email generated may be invalid. For example, if it 1677 is a half-finished draft, the "To" field may data that does not 1678 currently conform to the required syntax for this header field. The 1679 message will be checked for strict conformance when submitted for 1680 sending (see the EmailSubmission object description). 1682 Destroying an email removes it from all mailboxes to which it 1683 belonged. To just delete an email to trash, simply change the 1684 "mailboxIds" property so it is now in the mailbox with "role == 1685 "trash"", and remove all other mailbox ids. 1687 When emptying the trash, clients SHOULD NOT destroy emails which are 1688 also in a mailbox other than trash. For those emails, they SHOULD 1689 just remove the Trash mailbox from the email. 1691 For successfully created Email objects, the _created_ response MUST 1692 contain the _id_, _blobId_, _threadId_ and _size_ properties of the 1693 object. 1695 The following extra _SetError_ types are defined: 1697 For *create*: 1699 o "blobNotFound": At least one blob id given for an EmailBodyPart 1700 doesn't exist. An extra _notFound_ property of type "String[]" 1701 MUST be included in the error object containing every _blobId_ 1702 referenced by an EmailBodyPart that could not be found on the 1703 server. 1705 For *create* and *update*: 1707 o "tooManyKeywords": The change to the email's keywords would exceed 1708 a server-defined maximum. 1710 o "tooManyMailboxes": The change to the email's mailboxes would 1711 exceed a server-defined maximum. 1713 4.7. Email/import 1715 The _Email/import_ method adds [RFC5322] messages to a user's set of 1716 emails. The messages must first be uploaded as a file using the 1717 standard upload mechanism. It takes the following arguments: 1719 o *accountId*: "String|null" The id of the account to use for this 1720 call. If "null", defaults to the primary account. 1722 o *emails*: "String[EmailImport]" A map of creation id (client 1723 specified) to EmailImport objects 1725 An *EmailImport* object has the following properties: 1727 o *blobId*: "String" The id of the blob containing the raw [RFC5322] 1728 message. 1730 o *mailboxIds* "String[Boolean]" The ids of the mailbox(es) to 1731 assign this email to. At least one mailbox MUST be given. 1733 o *keywords*: "String[Boolean]" (default: "{}") The keywords to 1734 apply to the email. 1736 o *receivedAt*: "UTCDate" (default: time of import on server) The 1737 _receivedAt_ date to set on the email. 1739 Each email to import is considered an atomic unit which may succeed 1740 or fail individually. Importing successfully creates a new email 1741 object from the data reference by the blobId and applies the given 1742 mailboxes, keywords and receivedAt date. 1744 The server MAY forbid two email objects with the same exact [RFC5322] 1745 content, or even just with the same [RFC5322] Message-ID, to coexist 1746 within an account. In this case, it MUST reject attempts to import 1747 an email considered a duplicate with an "alreadyExists" SetError. An 1748 _emailId_ property of type "String" MUST be included on the error 1749 object with the id of the existing email. 1751 If the _blobId_, _mailboxIds_, or _keywords_ properties are invalid 1752 (e.g. missing, wrong type, id not found), the server MUST reject the 1753 import with an "invalidProperties" SetError. 1755 If the email cannot be imported because it would take the account 1756 over quota, the import should be rejected with a "maxQuotaReached" 1757 SetError. 1759 If the blob referenced is not a valid [RFC5322] message, the server 1760 MAY modify the message to fix errors (such as removing NUL octets or 1761 fixing invalid headers). If it does this, the _blobId_ on the 1762 response MUST represent the new representation and therefore be 1763 different to the _blobId_ on the EmailImport object. Alternatively, 1764 the server MAY reject the import with an "invalidEmail" SetError. 1766 The response has the following arguments: 1768 o *accountId*: "String" The id of the account used for this call. 1770 o *created*: "String[Email]" A map of the creation id to an object 1771 containing the _id_, _blobId_, _threadId_ and _size_ properties 1772 for each successfully imported Email. 1774 o *notCreated*: "String[SetError]" A map of creation id to a 1775 SetError object for each Email that failed to be created. The 1776 possible errors are defined above. 1778 4.8. Email/copy 1780 The only way to move messages *between* two different accounts is to 1781 copy them using the _Email/copy_ method, then once the copy has 1782 succeeded, delete the original. The _onSuccessDestroyOriginal_ 1783 argument allows you to try to do this in one method call, however 1784 note that the two different actions are not atomic, and so it is 1785 possible for the copy to succeed but the original not to be destroyed 1786 for some reason. 1788 The _Email/copy_ method takes the following arguments: 1790 o *fromAccountId*: "String|null" The id of the account to copy 1791 emails from. If "null", defaults to the primary account. 1793 o *toAccountId*: "String|null" The id of the account to copy emails 1794 to. If "null", defaults to the primary account. 1796 o *create*: "String[EmailCopy]" A map of _creation id_ to an 1797 EmailCopy object. 1799 o *onSuccessDestroyOriginal*: "Boolean" (default: "false") If 1800 "true", an attempt will be made to destroy the emails that were 1801 successfully copied: after emitting the _Email/copy_ response, but 1802 before processing the next method, the server MUST make a single 1803 call to _Email/set_ to destroy the original of each successfully 1804 copied message; the output of this is added to the responses as 1805 normal to be returned to the client. 1807 An *EmailCopy* object has the following properties: 1809 o *id*: "String" The id of the email to be copied in the "from" 1810 account. 1812 o *mailboxIds*: "String[Boolean]" The ids of the mailboxes (in the 1813 "to" account) to add the copied email to. At least one mailbox 1814 MUST be given. 1816 o *keywords*: "String[Boolean]" (default: "{}") The _keywords_ 1817 property for the copy. 1819 o *receivedAt*: "UTCDate" (default: _receivedAt_ date of original) 1820 The _receivedAt_ date to set on the copy. 1822 The server MAY forbid two email objects with the same exact [RFC5322] 1823 content, or even just with the same [RFC5322] Message-ID, to coexist 1824 within an account. If duplicates are allowed though, the "from" 1825 account may be the same as the "to" account to copy emails within an 1826 account. 1828 Each email copy is considered an atomic unit which may succeed or 1829 fail individually. Copying successfully MUST create a new email 1830 object, with separate ids and mutable properties (e.g. mailboxes and 1831 keywords) to the original email. 1833 The response has the following arguments: 1835 o *fromAccountId*: "String" The id of the account emails were copied 1836 from. 1838 o *toAccountId*: "String" The id of the account emails were copied 1839 to. 1841 o *created*: "String[Email]|null" A map of the creation id to an 1842 object containing the _id_, _blobId_, _threadId_ and _size_ 1843 properties for each successfully copied Email. 1845 o *notCreated*: "String[SetError]|null" A map of creation id to a 1846 SetError object for each Email that failed to be copied, "null" if 1847 none. 1849 The *SetError* may be any of the standard set errors that may be 1850 returned for a _create_. The following extra _SetError_ type is also 1851 defined: 1853 "alreadyExists": The server forbids duplicates and the email already 1854 exists in the target account. An _emailId_ property of type "String" 1855 MUST be included on the error object with the id of the existing 1856 email. 1858 The following additional errors may be returned instead of the 1859 _Email/copy_ response: 1861 "fromAccountNotFound": A _fromAccountId_ was explicitly included with 1862 the request, but it does not correspond to a valid account. 1864 "toAccountNotFound": A _toAccountId_ was explicitly included with the 1865 request, but it does not correspond to a valid account. 1867 "fromAccountNotSupportedByMethod": The _fromAccountId_ given 1868 corresponds to a valid account, but does not contain any mail data. 1870 "toAccountNotSupportedByMethod": The _toAccountId_ given corresponds 1871 to a valid account, but does not contain any mail data. 1873 4.9. Email/parse 1875 This method allows you to parse blobs as [RFC5322] messages to get 1876 Email objects. The following metadata properties on the Email 1877 objects will be "null" if requested: 1879 o id 1881 o mailboxIds 1883 o keywords 1885 o receivedAt 1887 The _threadId_ property of the Email MAY be present if the server can 1888 calculate which thread the Email would be assigned to were it to be 1889 imported. Otherwise, this too is "null" if fetched. 1891 The _Email/parse_ method takes the following arguments: 1893 o *accountId*: "String|null" The id of the Account to use. If 1894 "null", the primary account is used. 1896 o *blobIds*: "String[]" The ids of the blobs to parse. 1898 o *properties*: "String[]" If supplied, only the properties listed 1899 in the array are returned for each Email object. If omitted, 1900 defaults to: [ "messageId", "inReplyTo", "references", "sender", 1901 "from", "to", "cc", "bcc", "replyTo", "subject", "sentAt", 1902 "hasAttachment", "preview", "bodyValues", "textBody", "htmlBody", 1903 "attachedFiles", "attachedEmails" ] 1905 o *bodyProperties*: "String[]" (optional) A list of properties to 1906 fetch for each EmailBodyPart returned. If omitted, defaults to 1907 the same value as the Email/get "bodyProperties" default argument. 1909 o *fetchTextBodyValues*: "Boolean" (default: "false") If "true", the 1910 _bodyValues_ property includes any "text/*" part in the "textBody" 1911 property. 1913 o *fetchHTMLBodyValues*: "Boolean" (default: "false") If "true", the 1914 _bodyValues_ property includes any "text/*" part in the "htmlBody" 1915 property. 1917 o *fetchAllBodyValues*: "Boolean" (default: "false") If "true", the 1918 _bodyValues_ property includes any "text/*" part in the 1919 "bodyStructure" property. 1921 o *maxBodyValueBytes*: "Number" (optional) If supplied by the 1922 client, the value MUST be a positive integer greater than 0. If a 1923 value outside of this range is given, the server MUST reject the 1924 call with an "invalidArguments" error. When given, the _value_ 1925 property of any EmailBodyValue object returned in _bodyValues_ 1926 MUST be truncated if necessary so it does not exceed this number 1927 of octets in size. The server MUST ensure the truncation results 1928 in valid UTF-8 and does not occur mid-codepoint. If the part is 1929 of type "text/html", the server SHOULD NOT truncate inside an HTML 1930 tag. 1932 The response has the following arguments: 1934 o *accountId*: "String" The id of the account used for the call. 1936 o *parsed*: "String[Email]|null" A map of blob id to parsed Email 1937 representation for each successfully parsed blob, or "null" if 1938 none. 1940 o *notParsable*: "String[]|null" A list of ids given that 1941 corresponded to blobs that could not be parsed as emails, or 1942 "null" if none. 1944 o *notFound*: "String[]|null" A list of blob ids given that could 1945 not be found, or "null" if none. 1947 As specified above, parsed forms of headers may only be used on 1948 appropriate header fields. Attempting to fetch a form that is 1949 forbidden (e.g. "header:From:asDate") MUST result in the method call 1950 being rejected with an "invalidArguments" error. 1952 Where a specific header is requested as a property, the 1953 capitalization of the property name in the response MUST be identical 1954 to that used in the request. 1956 5. Email submission 1958 An *EmailSubmission* object represents the submission of an email for 1959 delivery to one or more recipients. It has the following properties: 1961 o *id*: "String" (immutable; server-set) The id of the email 1962 submission. 1964 o *identityId*: "String" (immutable) The id of the identity to 1965 associate with this submission. 1967 o *emailId*: "String" (immutable) The id of the email to send. The 1968 email being sent does not have to be a draft, for example when 1969 "redirecting" an existing email to a different address. 1971 o *threadId*: "String" (immutable; server-set) The thread id of the 1972 email to send. This is set by the server to the _threadId_ 1973 property of the email referenced by the _emailId_. 1975 o *envelope*: "Envelope|null" (immutable; default: "null") 1976 Information for use when sending via SMTP. An *Envelope* object 1977 has the following properties: 1979 * *mailFrom*: "Address" The email address to use as the return 1980 address in the SMTP submission, plus any parameters to pass 1981 with the MAIL FROM address. The JMAP server MAY allow the 1982 address to be the empty string. When a JMAP server performs an 1983 SMTP message submission, it MAY use the same id string for the 1984 [RFC3461] ENVID parameter and the EmailSubmission object id. 1985 Servers that do this MAY replace a client-provided value for 1986 ENVID with a server-provided value. 1988 * *rcptTo*: "Address[]" The email addresses to send the message 1989 to, and any RCPT TO parameters to pass with the recipient. 1991 An *Address* object has the following properties: 1993 * *email*: "String" The email address being represented by the 1994 object. This as a "Mailbox" as used in the Reverse-path or 1995 Foward-path of the MAIL FROM or RCPT TO command in [RFC5321]. 1997 * *parameters*: "Object|null" Any parameters to send with the 1998 email (either mail-parameter or rcpt-parameter as appropriate, 1999 as specified in [RFC5321]). If supplied, each key in the 2000 object is a parameter name, and the value either the parameter 2001 value (type "String") or if the parameter does not take a value 2002 then "null". For both name and value, any xtext or unitext 2003 encodings are removed ([RFC3461], [RFC6533]) and JSON string 2004 encoding applied. 2006 If the _envelope_ property is "null" or omitted on creation, the 2007 server MUST generate this from the referenced email as follows: 2009 * *mailFrom*: The email in the _Sender_ header, if present, 2010 otherwise the _From_ header, if present, and no parameters. If 2011 multiple addresses are present in one of these headers, or 2012 there is more than one _Sender_/_From_ header, the server 2013 SHOULD reject the email as invalid but otherwise MUST take the 2014 first address in the last _Sender_/_From_ header in the 2015 [RFC5322] version of the message. If the address found from 2016 this is not allowed by the identity associated with this 2017 submission, the _email_ property from the identity MUST be used 2018 instead. 2020 * *rcptTo*: The deduplicated set of email addresses from the 2021 _To_, _Cc_ and _Bcc_ headers, if present, with no parameters 2022 for any of them. 2024 o *sendAt*: "UTCDate" (immutable; server-set) The date the email 2025 was/will be released for delivery. If the client successfully 2026 used [RFC4865] FUTURERELEASE with the email, this MUST be the time 2027 when the server will release the email; otherwise it MUST be the 2028 time the EmailSubmission was created. 2030 o *undoStatus*: "String" (server-set) This represents whether the 2031 submission may be canceled. This is server set and MUST be one of 2032 the following values: 2034 * "pending": It MAY be possible to cancel this submission. 2036 * "final": The email has been relayed to at least one recipient 2037 in a manner that cannot be recalled. It is no longer possible 2038 to cancel this submission. 2040 * "canceled": The email submission was canceled and will not be 2041 delivered to any recipient. 2043 On systems that do not support unsending, the value of this 2044 property will always be "final". On systems that do support 2045 canceling submission, it will start as "pending", and MAY 2046 transition to "final" when the server knows it definitely cannot 2047 recall the email, but MAY just remain "pending". If in pending 2048 state, a client can attempt to cancel the submission by setting 2049 this property to "canceled"; if the update succeeds, the 2050 submission was successfully canceled and the email has not been 2051 delivered to any of the original recipients. 2053 o *deliveryStatus*: "String[DeliveryStatus]|null" (server-set) This 2054 represents the delivery status for each of the email's recipients, 2055 if known. This property MAY not be supported by all servers, in 2056 which case it will remain "null". Servers that support it SHOULD 2057 update the EmailSubmission object each time the status of any of 2058 the recipients changes, even if some recipients are still being 2059 retried. This value is a map from the email address of each 2060 recipient to a _DeliveryStatus_ object. A *DeliveryStatus* object 2061 has the following properties: 2063 * *smtpReply*: "String" The SMTP reply string returned for this 2064 recipient when the server last tried to relay the email, or in 2065 a later DSN response for the email. This SHOULD be the 2066 response to the RCPT TO stage, unless this was accepted and the 2067 email as a whole rejected at the end of the DATA stage, in 2068 which case the DATA stage reply SHOULD be used instead. Multi- 2069 line SMTP responses should be concatenated to a single string 2070 as follows: 2072 + The hyphen following the SMTP code on all but the last line 2073 is replaced with a space. 2075 + Any prefix in common with the first line is stripped from 2076 lines after the first. 2078 + CRLF is replaced by a space. 2080 For example: 2082 550-5.7.1 Our system has detected that this message is 2083 550 5.7.1 likely spam, sorry. 2085 would become: 2087 550 5.7.1 Our system has detected that this message is likely spam, sorry. 2089 For emails relayed via an alternative to SMTP, the server MAY 2090 generate a synthetic string representing the status instead. 2091 If it does this, the string MUST be of the following form: 2093 + A 3-digit SMTP reply code, as defined in [RFC5321], section 2094 4.2.3. 2096 + Then a single space character. 2098 + Then an SMTP Enhanced Mail System Status Code as defined in 2099 [RFC3463], with a registry defined in [RFC5248]. 2101 + Then a single space character. 2103 + Then an implementation-specific information string with a 2104 human readable explanation of the response. 2106 * *delivered*: "String" Represents whether the email has been 2107 successfully delivered to the recipient. This MUST be one of 2108 the following values: 2110 + "queued": The email is in a local mail queue and status will 2111 change once it exits the local mail queues. The _smtpReply_ 2112 property may still change. 2114 + "yes": The email was successfully delivered to the mailbox 2115 of the recipient. The _smtpReply_ property is final. 2117 + "no": Delivery to the recipient permanently failed. The 2118 _smtpReply_ property is final. 2120 + "unknown": The final delivery status is unknown, (e.g. it 2121 was relayed to an external machine and no further 2122 information is available). The _smtpReply_ property may 2123 still change if a DSN arrives. 2125 Note, successful relaying to an external SMTP server SHOULD NOT 2126 be taken as an indication that the email has successfully 2127 reached the final mailbox. In this case though, the server MAY 2128 receive a DSN response, if requested. If a DSN is received for 2129 the recipient with Action equal to "delivered", as per 2130 [RFC3464] section 2.3.3, then the _delivered_ property SHOULD 2131 be set to "yes"; if the Action equals "failed", the property 2132 SHOULD be set to "no". Receipt of any other DSN SHOULD NOT 2133 affect this property. The server MAY also set this property 2134 based on other feedback channels. 2136 * *displayed*: "String" Represents whether the email has been 2137 displayed to the recipient. This MUST be one of the following 2138 values: 2140 + "unknown": The display status is unknown. This is the 2141 initial value. 2143 + "yes": The recipient's system claims the email content has 2144 been displayed to the recipient. Note, there is no 2145 guarantee that the recipient has noticed, read, or 2146 understood the content. 2148 If an MDN is received for this recipient with Disposition-Type 2149 (as per [RFC3798] section 3.2.6.2) equal to "displayed", this 2150 property SHOULD be set to "yes". The server MAY also set this 2151 property based on other feedback channels. 2153 o *dsnBlobIds*: "String[]" (server-set) A list of blob ids for DSNs 2154 received for this submission, in order of receipt, oldest first. 2156 o *mdnBlobIds*: "String[]" (server-set) A list of blob ids for MDNs 2157 received for this submission, in order of receipt, oldest first. 2159 JMAP servers MAY choose not to expose DSN and MDN responses as Email 2160 objects if they correlate to a EmailSubmission object. It SHOULD 2161 only do this if it exposes them in the _dsnBlobIds_ and _mdnblobIds_ 2162 fields instead, and expects the user to be using clients capable of 2163 fetching and displaying delivery status via the EmailSubmission 2164 object. 2166 For efficiency, a server MAY destroy EmailSubmission objects a 2167 certain amount of time after the email is successfully sent or it has 2168 finished retrying sending the email. For very basic SMTP proxies, 2169 this MAY be immediately after creation, as it has no way to assign a 2170 real id and return the information again if fetched later. 2172 The following JMAP methods are supported: 2174 5.1. EmailSubmission/get 2176 Standard _/get_ method. 2178 5.2. EmailSubmission/changes 2180 Standard _/changes_ method. 2182 5.3. EmailSubmission/query 2184 Standard _/query_ method. 2186 A *FilterCondition* object has the following properties, any of which 2187 may be omitted: 2189 o *emailIds*: "String[]" The EmailSubmission _emailId_ property must 2190 be in this list to match the condition. 2192 o *threadIds*: "String[]" The EmailSubmission _threadId_ property 2193 must be in this list to match the condition. 2195 o *undoStatus*: "String" The EmailSubmission _undoStatus_ property 2196 must be identical to the value given to match the condition. 2198 o *before*: "UTCDate" The _sendAt_ property of the EmailSubmission 2199 object must be before this date to match the condition. 2201 o *after*: "UTCDate" The _sendAt_ property of the EmailSubmission 2202 object must be after this date to match the condition. 2204 A EmailSubmission object matches the filter if and only if all of the 2205 given conditions given match. If zero properties are specified, it 2206 is automatically "true" for all objects. 2208 The following properties MUST be supported for sorting: 2210 o "emailId" 2212 o "threadId" 2214 o "sentAt" 2216 5.4. EmailSubmission/queryChanges 2218 Standard _/queryChanges_ method. 2220 5.5. EmailSubmission/set 2222 Standard _/set_ method, with the following two extra arguments: 2224 o *onSuccessUpdateEmail*: "String[Email]|null" A map of 2225 _EmailSubmission id_ to an object containing properties to update 2226 on the Email object referenced by the EmailSubmission if the 2227 create/update/destroy succeeds. (For references to 2228 EmailSubmission creations, this is equivalent to a back reference 2229 so the id will be the creation id prefixed with a "#".) 2231 o *onSuccessDestroyEmail*: "String[]|null" A list of 2232 _EmailSubmission ids_ for which the email with the corresponding 2233 emailId should be destroyed if the create/update/destroy succeeds. 2234 (For references to EmailSubmission creations, this is equivalent 2235 to a back reference so the id will be the creation id prefixed 2236 with a "#".) 2238 A single implicit _Email/set_ call MUST be made after all 2239 EmailSubmission create/update/destroy requests have been processed to 2240 perform any changes requested in these two arguments. The response 2241 to this MUST be returned after the _EmailSubmission/set_ response. 2243 An email is sent by creating a EmailSubmission object. When 2244 processing each create, the server must check that the email is 2245 valid, and the user has sufficient authorization to send it. If the 2246 creation succeeds, the email will be sent to the recipients given in 2247 the envelope _rcptTo_ parameter. The server MUST remove any _Bcc_ 2248 header present on the email during delivery. The server MAY add or 2249 remove other headers from the submitted email, or make further 2250 alterations in accordance with the server's policy during delivery. 2252 If the referenced email is destroyed at any point after the 2253 EmailSubmission object is created, this MUST NOT change the behaviour 2254 of the email submission (i.e. it does not cancel a future send). 2256 Similarly, destroying a EmailSubmission object MUST NOT affect the 2257 deliveries it represents. It purely removes the record of the email 2258 submission. The server MAY automatically destroy EmailSubmission 2259 objects after a certain time or in response to other triggers, and 2260 MAY forbid the client from manually destroying EmailSubmission 2261 objects. 2263 The following extra _SetError_ types are defined: 2265 For *create*: 2267 o "tooLarge" - The email size is larger than the server supports 2268 sending. A _maxSize_ "Number" property MUST be present on the 2269 SetError specifying the maximum size of an email that may be sent, 2270 in octets. 2272 o "tooManyRecipients" - The envelope (supplied or generated) has 2273 more recipients than the server allows. A _maxRecipients_ 2274 "Number" property MUST be present on the SetError specifying the 2275 maximum number of allowed recipients. 2277 o "noRecipients" - The envelope (supplied or generated) does not 2278 have any rcptTo emails. 2280 o "invalidRecipients" - The _rcptTo_ property of the envelope 2281 (supplied or generated) contains at least one rcptTo value which 2282 is not a valid email for sending to. An _invalidRecipients_ 2283 "String[]" property MUST be present on the SetError, which is a 2284 list of the invalid addresses. 2286 o "forbiddenFrom" - The server does not permit the user to send an 2287 email with the From header of the email to be sent. 2289 o "forbiddenToSend" - The user does not have permission to send at 2290 all right now for some reason. A _description_ "String" property 2291 MAY be present on the SetError object to display to the user why 2292 they are not permitted. The server MAY choose to localise this 2293 string into the user's preferred language, if known. 2295 o "emailNotFound" - The _emailId_ is not a valid id for an email in 2296 the account. 2298 o "invalidEmail" - The email to be sent is invalid in some way. The 2299 SetError SHOULD contain a property called _properties_ of type 2300 "String[]" that lists *all* the properties of the email that were 2301 invalid. 2303 For *update*: 2305 o "cannotUnsend": The client attempted to update the _undoStatus_ of 2306 a valid EmailSubmission object from "pending" to "canceled", but 2307 the email cannot be unsent. 2309 6. Identities 2311 An *Identity* object stores information about an email address (or 2312 domain) the user may send from. It has the following properties: 2314 o *id*: "String" (immutable; server-set) The id of the identity. 2316 o *name*: "String" (default: """") The "From" _name_ the client 2317 SHOULD use when creating a new message from this identity. 2319 o *email*: "String" (immutable) The "From" email address the client 2320 MUST use when creating a new message from this identity. The 2321 value MAY alternatively be of the form "*@example.com", in which 2322 case the client may use any valid email address ending in 2323 "@example.com". 2325 o *replyTo*: "EmailAddress[]|null" (default: "null") The Reply-To 2326 value the client SHOULD set when creating a new message from this 2327 identity. 2329 o *bcc*: "EmailAddress[]|null" (default: "null") The Bcc value the 2330 client SHOULD set when creating a new message from this identity. 2332 o *textSignature*: "String" (default: """") Signature the client 2333 SHOULD insert into new plain-text messages that will be sent from 2334 this identity. Clients MAY ignore this and/or combine this with a 2335 client-specific signature preference. 2337 o *htmlSignature*: "String" (default: """") Signature the client 2338 SHOULD insert into new HTML messages that will be sent from this 2339 identity. This text MUST be an HTML snippet to be inserted into 2340 the "" section of the new email. Clients MAY ignore 2341 this and/or combine this with a client-specific signature 2342 preference. 2344 o *mayDelete*: "Boolean" (server-set) Is the user allowed to delete 2345 this identity? Servers may wish to set this to "false" for the 2346 user's username or other default address. 2348 See the "Addresses" header form description in the Email object for 2349 the definition of _EmailAddress_. 2351 Multiple identities with the same email address MAY exist, to allow 2352 for different settings the user wants to pick between (for example 2353 with different names/signatures). 2355 The following JMAP methods are supported: 2357 6.1. Identity/get 2359 Standard _/get_ method. The _ids_ argument may be "null" to fetch 2360 all at once. 2362 6.2. Identity/changes 2364 Standard _/changes_ method. 2366 6.3. Identity/set 2368 Standard _/set_ method. The following extra _SetError_ types are 2369 defined: 2371 For *create*: 2373 o "maxQuotaReached": The user has reached a server-defined limit on 2374 the number of identities. 2376 o "emailNotPermitted": The user is not allowed to send from the 2377 address given as the _email_ property of the identity. 2379 For *destroy*: 2381 o "forbidden": Returned if the identity's _mayDelete_ value is 2382 "false". 2384 7. Search snippets 2386 When doing a search on a "String" property, the client may wish to 2387 show the relevant section of the body that matches the search as a 2388 preview instead of the beginning of the message, and to highlight any 2389 matching terms in both this and the subject of the email. Search 2390 snippets represent this data. 2392 A *SearchSnippet* object has the following properties: 2394 o *emailId*: "String" The email id the snippet applies to. 2396 o *subject*: "String|null" If text from the filter matches the 2397 subject, this is the subject of the email HTML-escaped, with 2398 matching words/phrases wrapped in "" tags. If it 2399 does not match, this is "null". 2401 o *preview*: "String|null" If text from the filter matches the 2402 plain-text or HTML body, this is the relevant section of the body 2403 (converted to plain text if originally HTML), HTML-escaped, with 2404 matching words/phrases wrapped in "" tags. It MUST 2405 NOT be bigger than 255 octets in size. If it does not match, this 2406 is "null". 2408 o *attachments*: "String|null" If text from the filter matches the 2409 text extracted from an attachment, this is the relevant section of 2410 the attachment (converted to plain text), with matching words/ 2411 phrases wrapped in "" tags. It MUST NOT be bigger 2412 than 255 octets in size. If it does not match, this is "null". 2414 It is server-defined what is a relevant section of the body for 2415 preview. If the server is unable to determine search snippets, it 2416 MUST return "null" for both the _subject_, _preview_ and 2417 _attachments_ properties. 2419 Note, unlike most data types, a SearchSnippet DOES NOT have a 2420 property called "id". 2422 The following JMAP method is supported: 2424 7.1. SearchSnippet/get 2426 To fetch search snippets, make a call to "SearchSnippet/get". It 2427 takes the following arguments: 2429 o *accountId*: "String|null" The id of the account to use for this 2430 call. If "null", defaults to the primary account. 2432 o *emailIds*: "String[]" The list of ids of emails to fetch the 2433 snippets for. 2435 o *filter*: "FilterOperator|FilterCondition|null" The same filter as 2436 passed to Email/query; see the description of this method for 2437 details. 2439 The response has the following arguments: 2441 o *accountId*: "String" The id of the account used for the call. 2443 o *filter*: "FilterOperator|FilterCondition|null" Echoed back from 2444 the call. 2446 o *list*: "SearchSnippet[]" An array of SearchSnippet objects for 2447 the requested email ids. This may not be in the same order as the 2448 ids that were in the request. 2450 o *notFound*: "String[]|null" An array of email ids requested which 2451 could not be found, or "null" if all ids were found. 2453 Since snippets are only based on immutable properties, there is no 2454 state string or update mechanism needed. 2456 The following additional errors may be returned instead of the 2457 _searchSnippets_ response: 2459 "requestTooLarge": Returned if the number of _emailIds_ requested by 2460 the client exceeds the maximum number the server is willing to 2461 process in a single method call. 2463 "unsupportedFilter": Returned if the server is unable to process the 2464 given _filter_ for any reason. 2466 8. Vacation response 2468 The *VacationResponse* object represents the state of vacation- 2469 response related settings for an account. It has the following 2470 properties: 2472 o *id*: "String" (immutable) The id of the object. There is only 2473 ever one vacation response object, and its id is ""singleton"". 2475 o *isEnabled* "Boolean" Should a vacation response be sent if an 2476 email arrives between the _fromDate_ and _toDate_? 2478 o *fromDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time 2479 in UTC after which emails that arrive should receive the user's 2480 vacation response. If "null", the vacation response is effective 2481 immediately. 2483 o *toDate*: "UTCDate|null" If _isEnabled_ is "true", the date/time 2484 in UTC after which emails that arrive should no longer receive the 2485 user's vacation response. If "null", the vacation response is 2486 effective indefinitely. 2488 o *subject*: "String|null" The subject that will be used by the 2489 message sent in response to emails when the vacation response is 2490 enabled. If null, an appropriate subject SHOULD be set by the 2491 server. 2493 o *textBody*: "String|null" The plain text part of the message to 2494 send in response to emails when the vacation response is enabled. 2495 If this is "null", when the vacation message is sent a plain-text 2496 body part SHOULD be generated from the _htmlBody_ but the server 2497 MAY choose to send the response as HTML only. 2499 o *htmlBody*: "String|null" The HTML message to send in response to 2500 emails when the vacation response is enabled. If this is "null", 2501 when the vacation message is sent an HTML body part MAY be 2502 generated from the _textBody_, or the server MAY choose to send 2503 the response as plain-text only. 2505 The following JMAP methods are supported: 2507 8.1. VacationResponse/get 2509 Standard _/get_ method. 2511 There MUST only be exactly one VacationResponse object in an account. 2512 It MUST have the id ""singleton"". 2514 8.2. VacationResponse/set 2516 Standard _/set_ method. 2518 9. Security considerations 2520 All security considerations of JMAP {TODO: insert RFC ref} apply to 2521 this specification. 2523 9.1. EmailBodyPart value 2525 Service providers typically perform security filtering on incoming 2526 email and it's important the detection of content-type and charset 2527 for the security filter aligns with the heuristics performed by JMAP 2528 servers. Servers that apply heuristics to determine the content-type 2529 or charset for _EmailBodyValue_ SHOULD document the heuristics and 2530 provide a mechanism to turn them off in the event they are misaligned 2531 with the security filter used at a particular mailbox host. 2533 Automatic conversion of charsets that allow hidden channels for ASCII 2534 text, such as UTF-7, have been problematic for security filters in 2535 the past so server implementations can mitigate this risk by having 2536 such conversions off-by-default and/or separately configurable. 2538 To allow the client to restrict the volume of data it can receive in 2539 response to a request, a maximum length may be requested for the data 2540 returned for a textual body part. However, truncating the data may 2541 change the semantic meaning, for example truncating a URL changes its 2542 location. Servers that scan for links to malicious sites should take 2543 care to either ensure truncation is not at a semantically significant 2544 point, or to rescan the truncated value for malicious content before 2545 returning it. 2547 9.2. HTML email display 2549 HTML message bodies provide richer formatting for emails but present 2550 a number of security challenges, especially when embedded in a 2551 webmail context in combination with interface HTML. Clients that 2552 render HTML email should make careful consideration of the potential 2553 risks, including: 2555 o Embedded JavaScript can rewrite the email to change its content on 2556 subsequent opening, allowing users to be mislead. In webmail 2557 systems, if run in the same origin as the interface it can access 2558 and exfiltrate all private data accessible to the user, including 2559 all other emails and potentially contacts, calendar events, 2560 settings, and credentials. It can also rewrite the interface to 2561 undetectably phish passwords. A compromise is likely to be 2562 persistent, not just for the duration of page load, due to 2563 exfiltration of session credentials or installation of a service 2564 worker that can intercept all subsequent network requests (this 2565 however would only be possible if blob downloads are also 2566 available on the same origin, and the service worker script is 2567 attached to the message). 2569 o HTML documents may load content directly from the internet, rather 2570 than just referencing attached resources. For example you may 2571 have an "" tag with an external "src" attribute. This may 2572 leak to the sender when a message is opened, as well as the IP 2573 address of the recipient. Cookies may also be sent and set by the 2574 server, allowing tracking between different emails and even 2575 website visits and advertising profiles. 2577 o In webmail systems, CSS can break the layout or create phishing 2578 vulnerabilities. For example, the use of "position:fixed" can 2579 allow an email to draw content outside of its normal bounds, 2580 potentially clickjacking a real interface element. 2582 o If in a webmail context and not inside a separate frame, any 2583 styles defined in CSS rules will apply to interface elements as 2584 well if the selector matches, allowing the interface to be 2585 modified. Similarly, any interface styles that match elements in 2586 the email will alter their appearance, potentially breaking the 2587 layout of the email. 2589 o The link text in HTML has no neccessary correlation with the 2590 actual target of the link, which can be used to make phishing 2591 attacks more convincing. 2593 o Links opened from an email or embedded external content may leak 2594 private info in the "Referer" header sent by default in most 2595 systems. 2597 o Forms can be used to mimic login boxes, providing a potent 2598 phishing vector if allowed to submit directly from the email 2599 display. 2601 There are a number of ways clients can mitigate these issues, and a 2602 defence-in-depth approach that uses a combination of techniques will 2603 provide the strongest security. 2605 o HTML can be filtered before rendering, stripping potentially 2606 malicious content. Sanitizing HTML correctly is tricky, and 2607 implementors are strongly recommended to use a well-tested library 2608 with a carefully vetted whitelist-only approach. New features 2609 with unexpected security characteristics may be added to HTML 2610 rendering engines in the future; a blacklist approach is likely to 2611 result in security issues. 2613 Subtle differences in parsing of HTML can introduce security flaws: 2614 to filter with 100% accurately you need to use the same parser when 2615 sanitizing that the HTML rendering engine will use. 2617 o Encapsulating the message in an "