Most mail apps still talk to their servers the way they did in the 1990s: a long-lived IMAP connection, a text protocol with its own grammar, one connection per folder you want to watch, and SMTP on the side for sending. JMAP is the open standard that replaces all of that with something any web developer already knows: JSON over HTTPS.
This guide explains what JMAP is, how a session works, what makes it faster than IMAP, and where it stands in 2026.
What JMAP is
JMAP stands for the JSON Meta Application Protocol. Its core, RFC 8620, was published by the IETF in July 2019, written by Neil Jenkins of Fastmail and Chris Newman of Oracle. Mail followed a month later in RFC 8621.
The "meta" is the important part. The core does not describe email at all. It describes a general way to fetch, change, query and sync any kind of JSON object over HTTPS, with push and file transfer included. Each kind of data then gets its own specification on top: mail in RFC 8621, contacts in RFC 9610, Sieve filtering scripts in RFC 9661, quotas in RFC 9425 and sharing in RFC 9670. JMAP for Calendars has passed the working group and sits in the RFC Editor's queue. In all, the IETF's JMAP working group has published eleven RFCs since 2019.
How a session starts
A client begins by finding the server's session resource, usually at /.well-known/jmap, and authenticating, typically with an OAuth or bearer token. The session object it gets back lists the capabilities the server supports, the accounts the user can reach, and the URLs for API calls, uploads, downloads and push. Fastmail, for example, serves its session resource at https://api.fastmail.com/jmap/session.
From then on, everything is an HTTPS request with a JSON body. Nothing has to stay connected between requests except the optional push channel, so JMAP works through the same proxies, load balancers and CDNs as any other web API.
One request, many method calls
A JMAP request names the capabilities it uses and carries a list of method calls. Each call is a method name in the form Type/verb, its arguments, and a short id the response will echo back. The trick is that a later call can use the result of an earlier one through a back-reference, so the server runs a whole sequence in one round trip.
This request finds the ten newest messages in the inbox and fetches their subjects, senders and previews, in one go:
{ "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], "methodCalls": [ ["Email/query", { "accountId": "u123", "filter": { "inMailbox": "inbox-id" }, "sort": [{ "property": "receivedAt", "isAscending": false }], "limit": 10 }, "a"], ["Email/get", { "accountId": "u123", "#ids": { "resultOf": "a", "name": "Email/query", "path": "/ids" }, "properties": ["subject", "from", "receivedAt", "preview"] }, "b"] ]}The #ids argument tells the server to take the ids from the result of call a. In IMAP, the same job is a SELECT, a SEARCH and a FETCH, each waiting for the one before.
Every data type offers the same small set of standard methods:
| Method | What it does |
|---|---|
/get | Fetch objects by id, with only the properties you ask for |
/set | Create, update and destroy objects in one call |
/query | Search, filter and sort, returning ids |
/changes | List what was created, updated or destroyed since a given state |
/queryChanges | Update a search result without running it again |
/copy | Copy objects from one account to another |
Sync by asking what changed
Every type of data on a JMAP server has a state string that changes whenever any object of that type changes. A client remembers the last state it saw, and on its next visit calls Email/changes with sinceState. The server answers with three lists of ids, created, updated and destroyed, plus the new state, and the client fetches only those.
That is why reconnecting after a weekend offline is cheap. The JMAP project's own measurement puts resyncing a 28,234-message mailbox at 13.1 KB with JMAP, against 2.9 MB for Thunderbird over IMAP after a restart. IMAP clients have to work out what changed folder by folder, from flags and message numbers that are only valid within a folder.
Push: one connection for every mailbox
When anything changes, a JMAP server pushes a small state-change notice that says which types changed in which accounts, and the client calls /changes to catch up. There are three ways to receive it:
- Server-sent events, a plain HTTP response the server keeps open, one connection for every mailbox in every account.
- WebSocket, in RFC 8887, which also lets the client send its requests over the same connection.
- Web Push, for mobile apps that should not hold a connection at all, secured with VAPID since RFC 9749.
IMAP's equivalent, IDLE, watches the one folder a connection has selected, so a client that wants to know about five folders keeps five connections open.
Mail in JMAP
RFC 8621 defines the objects a mail client works with: Mailbox, Thread, Email, SearchSnippet, Identity, EmailSubmission and VacationResponse. A few design choices stand out:
- Threads are built in. Every
Emailhas athreadId, so a client never has to rebuild conversations from headers. - Mailboxes can behave like labels. An
Emaillists the mailboxes it belongs to, and a server can let it sit in more than one at once. - Sending is part of the API. A client creates the message and an
EmailSubmissionfor it in the same request, and can ask the server to move it from Drafts to Sent once it goes out. There is no separate SMTP login. - Attachments are blobs. Files are uploaded and downloaded over plain HTTP, outside the JSON, and referenced by id.
JMAP compared with IMAP
| IMAP | JMAP | |
|---|---|---|
| Transport | A long-lived TCP connection | HTTPS requests |
| Format | Its own text grammar | JSON |
| Sync | Per folder, with message numbers and flags | /changes from a state string, for every type |
| Push | IDLE on one selected folder per connection | One channel for every mailbox |
| Conversations | An optional extension | threadId on every message |
| Sending | A separate SMTP submission | EmailSubmission in the same API |
| Round trips | Commands one after another | Many method calls in one request |
IMAP has improved too. Its current version, IMAP4rev2, became RFC 9051 in 2021 and folded many extensions into the base. But it remains a stateful session protocol, and the JMAP site's comparison puts its specification at roughly 272,000 words against about 51,000 for JMAP. Our guide What is IMAP? covers the older protocol on its own terms.
Who supports JMAP in 2026
- Fastmail, where the protocol was created, runs JMAP in production and offers it as its public API, with API tokens for your own scripts and OAuth for apps other people use.
- Stalwart, an open-source mail server, speaks JMAP for mail and, according to its own announcement, JMAP for contacts, calendars and file storage as well.
- Thunderbird finished exploring JMAP for its new iPhone app in 2026, and its roadmap now plans full support for 2027, with IMAP first so the first release covers every provider.
- Gmail and Outlook do not offer JMAP. They expose IMAP alongside their own APIs.
Libraries exist for most languages, and the JMAP site keeps a list of servers, clients and libraries.
Should you build on JMAP?
If you are writing a client for a server that speaks it, yes: you get batching, cheap sync and real push with a fraction of the code IMAP needs. If your app has to reach any mailbox on any provider, IMAP is still the common ground, because the largest providers do not offer JMAP.
And if you are building a product rather than a general mail client, the question is often which API gives you mailboxes, sending and events together, not which sync protocol to speak.
Where Nextmail fits
Nextmail does not speak JMAP today. Mail apps connect to it over IMAP and SMTP, and code uses its REST API, which shares several of JMAP's ideas: JSON over HTTPS, threads as first-class objects, and one live event stream for every change in a mailbox that picks up where it left off after a disconnect. On top of that it adds what a product needs around the mailbox: sending at scale, domains and their DNS records, webhooks, and OAuth sign-in for the people who use your app.
Our guide to building your own email client on Nextmail shows those pieces in code.
References
- 1RFC 8620: The JSON Meta Application Protocol (JMAP)IETF
- 2RFC 8621: The JSON Meta Application Protocol (JMAP) for MailIETF
- 3RFC 8887: A JSON Meta Application Protocol (JMAP) Subprotocol for WebSocketIETF
- 4RFC 9610: JSON Meta Application Protocol (JMAP) for ContactsIETF
- 5RFC 9051: Internet Message Access Protocol (IMAP), Version 4rev2IETF
- 6JMAP working group documentsIETF
- 7JMAP: the JSON Meta Application Protocoljmap.io
- 8API documentationFastmail
- 9Thunderbird for iOS roadmapThunderbird
- 10JMAP for Calendars, Contacts and Files now in StalwartStalwart
Google Workspace