blob: 10d6ad9c822f6816226bc735ed021be306e5e960 [file] [log] [blame]
## Threads
<aside class="warning">
Not implemented
</aside>
Replies are grouped together with the original message to form a thread. In JMAP, a thread is simply a flat list of messages, ordered by date. Every message MUST belong to a thread, even if it is the only message in the thread.
The JMAP spec does not require the server to use any particular algorithm for determining whether two messages belong to the same thread, however there is a recommended algorithm in the [implementation guide](server.html).
If messages are delivered out of order for some reason, a user may receive two messages in the same thread but without headers that associate them with each other. The arrival of a third message in the thread may provide the missing references to join them all together into a single thread. Since the `threadId` of a message is immutable, if the server wishes to merge the threads, it MUST handle this by deleting and reinserting (with a new message id) the messages that change threadId.
A **Thread** object has the following properties:
- **id**: `String`
The id of the thread. This property is immutable.
- **messageIds**: `String[]`
The ids of the messages in the thread, sorted such that:
- Any message with `isDraft == true` and an *inReplyToMessageId* property that corresponds to another message in the thread comes immediately after that message in the sort order.
- Other than that, everything is sorted in date order (the same as the *date* property on the Message object), oldest first.
### getThreads
Threads can only be fetched explicitly by id. To fetch threads, make a call to *getThreads*. It takes the following arguments:
- **accountId**: `String|null`
The id of the account to use for this call. If not given, defaults to the primary account.
- **ids**: `String[]`
An array of ids for the threads to fetch.
- **fetchMessages**: `Boolean|null`
If true, after outputting a *threads* response, an implicit call will be made to *getMessages* with a list of all message ids in the returned threads as the *ids* argument, and the *fetchMessageProperties* argument as the *properties* argument. If `false` or `null`, no implicit call will be made.
- **fetchMessageProperties**: `String[]|null`
The list of properties to fetch on any fetched messages. See *getMessages* for a full description.
The response to *getThreads* is called *threads*. It has the following arguments:
- **accountId**: `String`
The id of the account used for the call.
- **state**: `String`
A string encoding the current state on the server. This string will change
if any threads change (that is, new messages arrive, or messages are deleted, as these are the only two events that change thread membership). It can be passed to *getThreadUpdates* to efficiently get the list of changes from the previous state.
- **list**: `Thread[]`
An array of Thread objects for the requested thread ids. This may not be in the same order as the ids were in the request.
- **notFound**: `String[]|null`
An array of thread ids requested which could not be found, or `null` if all ids were found.
The following errors may be returned instead of the `threads` response:
`accountNotFound`: Returned if an *accountId* was explicitly included with the request, but it does not correspond to a valid account.
`accountNoMail`: Returned if the *accountId* given corresponds to a valid account, but does not contain any mail data.
`invalidArguments`: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A *description* property MAY be present on the response object to help debug with an explanation of what the problem was.
Example of a successful request:
[ "getThreads", {
"ids": ["f123u4", "f41u44"],
"fetchMessages": false,
"fetchMessageProperties": null
}, "#1" ]
and response:
[ "threads", {
"state": "f6a7e214",
"list": [
{
"id": "f123u4",
"messageIds": [ "eaa623", "f782cbb"]
},
{
"id": "f41u44",
"messageIds": [ "82cf7bb" ]
}
],
"notFound": null
}, "#1" ]
### getThreadUpdates
When messages are created or deleted, new threads may be created, or the set of messages belonging to an existing thread may change. If a call to *getThreads* returns with a different *state* string in the response to a previous call, the state of the threads has changed on the server and the client needs to work out which part of its cache is now invalid.
The *getThreadUpdates* call allows a client to efficiently update the state of any cached threads to match the new state on the server. It takes the following arguments:
- **accountId**: `String|null`
The id of the account to use for this call. If not given, defaults to the primary account.
- **sinceState**: `String`
The current state of the client. This is the string that was returned as the *state* argument in the *threads* response. The server will return the changes made since this state.
- **maxChanges**: `Number|null`
The maximum number of Thread ids to return in the response. The server MAY choose to clamp this value to a particular maximum or set a maximum if none is given by the client. If supplied by the client, the value MUST be a positive integer greater than 0. If a value outside of this range is given, the server MUST reject the call with an `invalidArguments` error.
- **fetchRecords**: `Boolean|null`
If `true`, after outputting a *threadUpdates* response, an implicit call will be made to *getThreads* with the *changed* property of the response as the *ids* argument, and *fetchMessages* equal to `false`.
The response to *getThreadUpdates* is called *threadUpdates*. It has the following arguments:
- **accountId**: `String`
The id of the account used for the call.
- **oldState**: `String`
This is the *sinceState* argument echoed back; the state from which the server is returning changes.
- **newState**: `String`
This is the state the client will be in after applying the set of changes to the old state.
- **hasMoreUpdates**: `Boolean`
If `true`, the client may call *getThreadUpdates* again with the *newState* returned to get further updates. If `false`, *newState* is the current server state.
- **changed**: `String[]`
An array of thread ids where the list of messages within the thread has
changed between the old state and the new state, and the thread currently has at least one message in it.
- **removed**: `String[]`
An array of thread ids where the list of messages within the thread has changed since the old state, and there are now no messages in the thread.
If a *maxChanges* is supplied, or set automatically by the server, the server must try to limit the number of ids across *changed* and *removed* to the number given. If there are more changes than this between the client's state and the current server state, the update returned MUST take the client to an intermediate state, from which the client can continue to call *getThreadUpdates* until it is fully up to date. The server MAY return more ids than the *maxChanges* total if this is required for it to be able to produce an update to an intermediate state, but it SHOULD try to keep it close to the maximum requested.
If a thread has been modified AND deleted since the oldState, the server SHOULD just return the id in the *removed* response, but MAY return it in the changed response as well. If a thread has been created AND deleted since the oldState, the server should remove the thread id from the response entirely, but MAY include it in the *removed* response, and optionally the *changed* response as well.
The following errors may be returned instead of the *threadUpdates* response:
`accountNotFound`: Returned if an *accountId* was explicitly included with the request, but it does not correspond to a valid account.
`accountNoMail`: Returned if the *accountId* given corresponds to a valid account, but does not contain any mail data.
`invalidArguments`: Returned if the request does not include one of the required arguments, or one of the arguments is of the wrong type, or otherwise invalid. A *description* property MAY be present on the response object to help debug with an explanation of what the problem was.
`cannotCalculateChanges`: Returned if the server cannot calculate the changes from the state string given by the client. Usually due to the client's state being too old, or the server being unable to produce an update to an intermediate state when there are too many updates. The client MUST invalidate its Thread cache. The error object MUST also include a `newState: String` property with the current state for the type.