blob: d607c2284c194f78ba427306649c43ff6c06a2c7 [file] [log] [blame]
## Push
<aside class="warning">
Not implemented
</aside>
Any modern email client should be able to update instantly whenever the data on the server is changed by another client or message delivery. Push notifications in JMAP occur out-of-band (i.e. not over the same connection as API exchanges) so that they can make use of efficient native push mechanisms on different platforms.
The general model for push is simple and does not send any sensitive data over the push channel, making it suitable for use with less trusted 3rd party intermediaries. The format allows multiple changes to be coalesced into a single push update, and the frequency of pushes to be rate limited by the server. It doesn't matter if some push events are dropped before they reach the client; it will still get all changes next time it syncs.
When something changes on the server, the server pushes a small JSON object to the client with the following property:
- **changed**: `String[ChangedStates]`
A map of *account id* to an object encoding the state of data types which have changed for that account since the last push event, for each of the accounts to which the user has access and for which something has changed.
A **ChangedStates** object is a map of the type name (e.g. "Mailbox" or "Message") to the current state token for that type (i.e. the "state" property that would currently be returned by a call to "getMailboxes" or "getMessages", as appropriate). The types in JMAP are "Mailbox", "Thread", "Message", "ContactGroup", "Contact", "Calendar", "CalendarEvent".
Upon receiving this data, the client can compare the new state strings with its current values to see whether it has the current data for these types. The actual changes can then be efficiently fetched in a single standard API request (using the *getFooUpdates* type methods).
### Event Source
There are two mechanisms by which the client can receive the push events. The first is directly via a `text/event-stream` resource, as described in
<http://www.w3.org/TR/eventsource/>. This is essentially a long running HTTP request down which the server can push data. When a change occurs, the server MUST push an event called **state** to any connected clients.
The server MAY also set a new `Last-Event-Id` that encodes the entire server state visible to the user. When a new connection is made to the event-source endpoint, the server can then work out whether the client has missed some changes which it should send immediately.
The server MUST also send an event called **ping** with an empty object as the data if a maximum of 5 minutes has elapsed since the previous event. This MUST NOT set a new `Last-Event-Id`. A client may detect the absence of these to determine that the HTTP connection has been dropped somewhere along the route and so it needs to re-establish the connection.
Refer to the Authentication section of this spec for details on how to get the URL for the event-source endpoint. The request must be authenticated using an `Authorization` header like any HTTP request.
A client MAY hold open multiple connections to the event-source, although it SHOULD try to use a single connection for efficiency.
### setPushCallback
The second push mechanism is to register a callback URL to which the JMAP server will make an HTTPS POST request whenever the event occurs. The request MUST have a content type of `application/json` and contain the same UTF-8 JSON encoded object as described above as the body.
The JMAP server MUST also set the following headers in the POST request:
- `X-JMAP-EventType: state`
- `X-JMAP-User: ${username}` where `${username}` is the username of the authenticated user for which the push event occurred.
The JMAP server MUST follow any redirects. If the final response code from the server is `2xx`, the callback is considered a success. If the response code is `503` (Service Unavailable), the JMAP server MAY try again later (but may also just drop the event). If the response code is `429` (Too Many Requests) the JMAP server SHOULD attempt to reduce the frequency of pushes to that URL. Any other response code SHOULD be considered a **permanent failure** and the callback should be deregistered (not tried again even for future events unless explicitly re-registered by the client).
The URL set by the client MUST use the HTTPS protocol and SHOULD encode within it a unique token that can be verified by the server to know that the request comes from the JMAP server the authenticated client connected to.
The callback is tied to the access token used to create it. Should the access token expire or be revoked, the callback MUST be removed by the JMAP server. The client MUST re-register the callback after reauthenticating to resume callbacks.
Each session may only have a single callback URL registered. To set it, make a call to *setPushCallback*. It takes the following argument:
- **callback**: `String|null`
The (HTTPS) URL the JMAP server should POST events to. This will replace any previously set URL. Set to `null` to just remove any previously set callback URL.
The response to *setPushCallback* is called *pushCallbackSet*. It has the following argument:
- **callback**: `String|null`
Echoed back from the call.
The following error may be returned instead of the *mailboxesSet* response:
`invalidUrl`: Returned if the URL does not begin with `https://`, or is otherwise syntactically invalid or does not resolve.
### getPushCallback
To check the currently set callback URL (if any), make a call to *getPushCallback*. It does not take any arguments. The response to *getPushCallback* is called `pushCallback`. It has a single argument:
- **callback**: `String|null`
The URL the JMAP server is currently posting push events to, or `null` if none.