A modern JMAP client, on whatever backend you have.
jmap-proxy lets a JMAP client, a webmail UI or a mobile mail app, talk to a backend that may not speak JMAP at all. Point it at a JMAP-native store and it relays. Point it at plain IMAP, including a server decades old, and it translates, live, for the whole session.
01Two ways to reach a backend
Every other daemon in the Scorpion suite goes transparent once a client has authenticated. JMAP is different: jmap-proxy stays an active JSON mediator for the life of each request, translating between the client's JMAP calls and whatever the backend actually understands. Which of the two modes below applies is set per backend target, never proxy-wide, so one running instance can front a mix of both at once.
Splice mode
For a backend that already speaks JMAP — Cyrus, Stalwart, any future JMAP-native store. jmap-proxy fetches and caches the backend's own session resource, relays method calls to its apiUrl over a verifying HTTPS client, and passes EmailSubmission/set straight through to the backend's own submission path.
Gateway mode
For a backend that only speaks IMAP4rev1 — Sun/iPlanet, Dovecot, Cyrus without JMAP enabled, or anything else that age or licensing has left behind. jmap-proxy stays a live, translating IMAP client for the whole session: each JMAP call becomes one or more real IMAP commands, and the response is translated back into a JMAP result. This is the heavier of the two modes — see below for exactly what it does today.
02Mixed fleets, routed per user
With no lookup driver configured, every request goes to one static backend. Configure a lookup driver and each request is routed per user instead, keyed on the username from the client's own login — the same file/domain/LDAP/PostgreSQL/MySQL drivers used for login routing elsewhere in Scorpion. A file or domain map entry can also override the backend mode for that one user, so a single jmap-proxy instance can serve some mailboxes against a JMAP-native store and others against a legacy IMAP server, at the same time, from the one entry point.
Routing only decides which backend a login reaches. The password itself is always verified by that backend's own accept-or-reject — jmap-proxy never checks a credential itself.
03What gateway mode does today
Gateway mode is real translation against a live IMAP4rev1 server, not a stub. Here is where that stands today, kept current as it ships:
Mailbox/get
Built from the folder list. Special-use flags map to a JMAP role; INBOX is always the top-level inbox. A parent folder that only exists as a naming convention is synthesised so the tree is never missing a node.
Mailbox/set
Create, delete, rename and subscribe all work. A mailbox cannot be given a role on create. INBOX cannot be renamed, moved or destroyed.
Email/get
Envelope, flags and the text body. No attachment or HTML body walk yet, so a multipart message is flattened to plain text. No message-thread linking yet.
Email/set
Flag changes, moving a message to one mailbox, and composing and sending a real message with subject, recipients, body and flags set atomically on send.
Email/query
One flat filter condition, always scoped to a single mailbox, with a single sort on date. No nested AND/OR/NOT filters yet.
Not yet there
Query-change syncing, calendar objects, attachment upload/download and push all return a clean, honest "not supported" rather than a wrong answer.
Every gap above fails cleanly with a proper JMAP error for that one call, never a crash and never a silently wrong result for the rest of the request.
04Click-time protection, for JMAP too
The same click-time URL protection described on the how it works page applies to mail read over JMAP, in both modes. Links can optionally be rewritten in calendar invitations as well as message bodies — closing off fake "join this meeting" and "this meeting moved" links, a distinct attack surface from links in an ordinary message.
05What it never keeps
- No client credential is ever stored. Whatever the client sends is passed to the backend unexamined, and the backend's own accept or reject is the only check.
- No message content is cached.
- Gateway mode's only optional persistent state is a small per-mailbox counter used to notice when a backend has renumbered its messages between requests — never credentials, never anything from inside a message.
Run your own mix of backends behind one JMAP endpoint.
Tell us what your backends actually are — JMAP-native, plain IMAP, or both — and we will scope a pilot on your existing infrastructure.