All help articles

JMAP for mail apps and developers

Mailocity speaks JMAP (RFC 8620 and RFC 8621) at /jmap/api, found from /.well-known/jmap. Mail apps and scripts sign in with HTTP Basic (the password, or an app password once two-step sign-in is on) or with a mailbox token (Authorization: Bearer cs_mt_... with the jmap scope).

Keeping in sync

Every type has its own state, and the server keeps a log of what changed, whoever changed it: new mail, IMAP clients, webmail, filters, imports.

Hearing about changes

Changes are announced the moment they are saved, by every server process (Postgres notifications), in three ways:

Searching mail

Email/query takes every filter in RFC 8621 section 4.4.1: inMailbox, inMailboxOtherThan, before, after, minSize, maxSize, hasKeyword, notKeyword, allInThreadHaveKeyword, someInThreadHaveKeyword, noneInThreadHaveKeyword, hasAttachment, text, from, to, cc, bcc, subject, body and header, joined with AND, OR and NOT operators (up to 10 deep, 50 conditions each).

It sorts by receivedAt, sentAt, size, from, to, subject, hasKeyword, allInThreadHaveKeyword and someInThreadHaveKeyword, and takes position (negative counts from the end), anchor with anchorOffset, limit (at most 500 a page) and collapseThreads. A query reaches the first 100,000 results.

Mailbox/query filters by name, role, hasAnyRole, isSubscribed and parentId, and sorts by name and sortOrder. EmailSubmission/query filters by identityIds, emailIds, threadIds, undoStatus, before and after.

SearchSnippet/get takes the same filter and a list of emails, and returns each one's subject and a piece of its text with the matching words in <mark>, as HTML (everything else escaped), or null where nothing matched.

Reading messages

Email/get returns any header in any form RFC 8621 defines: header:X-Mailer:asText, header:Cc:asAddresses, header:List-Post:asURLs, header:Received:all and so on (asRaw, asText, asAddresses, asGroupedAddresses, asMessageIds, asDate, asURLs). headers lists every field as it was sent, and bodyStructure is the whole MIME tree. bodyProperties chooses what each part shows, including its headers and header: forms.

Email/parse reads a message that is only a blob: an upload, or a message attached to another one (its part's blobId). The parts of an attached message get blob ids of their own (<blob>-3-1 is part 1 of the message in part 3), which download and Blob/get read.

Blobs

With urn:ietf:params:jmap:blob (RFC 9404):

Uploads nothing uses are deleted after a day. Email/copy and Blob/copy copy between your account and mailboxes shared with you; within one account use Email/set or Blob/upload.

Quotas

With urn:ietf:params:jmap:quota (RFC 9425), Quota/get shows the account's limits with what is used: storage (bytes of mail), aliases, send-hour and send-day (recipients). Each has a warnLimit at 90%. Quota/changes, Quota/query (by name, scope, resourceType and type; sorted by name or used) and Quota/queryChanges work as for other types.

Read receipts

With urn:ietf:params:jmap:mdn (RFC 9007):

Receipts are never sent by themselves: only when the app (or you) asks.

Signed mail

S/MIME signatures are checked (RFC 9219); see Signed mail.

Shared mailboxes and address books

Mailboxes shared with you are more accounts in the session; see Sharing. Principal/get, /query and /changes list your team, and ShareNotification/get, /query, /changes and /set (destroy) tell you about shares. AddressBook/set makes, renames and removes address books (onDestroyRemoveContents, onSuccessSetIsDefault), and ContactCard/copy copies cards between accounts.

After an upgrade

Mail stored before the Cc, Bcc, attachment and header filters existed is read again in the background after the server starts. Until that is done, those filters do not find older messages; nothing else changes, and clients are not told the messages changed.

Also supported

Tasks (JMAP for Tasks; see Tasks), Sieve scripts (RFC 9661), vacation replies, contacts (RFC 9610), sending with delayed send, blob upload and download, and result references. See mail filters, vacation replies, contacts and webmail.

Signing with S/MIME

EmailSubmission/set takes smimeSign: true (a Zappocity extension) to sign the message with the sender's S/MIME certificate and key kept in webmail settings; without them it fails with smimeSignFailed. It cannot be combined with sending later. See S/MIME.