Skip to main content
Everything about mail that already exists. Sending is a separate resource, on purpose.
Folders are named by role, not by path. Use inbox, archive, sent, drafts, junk or trash.Path names are not portable and are not even stable for us — Junk is “Junk” on Dovecot and “Spam” elsewhere, Trash is “Deleted Items” on Exchange, and any of them can sit under a namespace prefix. Roles are resolved against the server’s own SPECIAL-USE attributes on every request, so folder=junk keeps meaning the junk folder whatever it is called.Folders you made are addressed by their path from GET /v1/folders. move_to accepts either, so a message can be filed into one; folder= on the read endpoints takes a role.

List messages

Required permission: Messages → Read (messages:read)
total is how many messages the folder holds, not how many came back, so you can tell whether another page exists without fetching it. has_more says the same thing directly.
A uid is unique within one folder, not within the mailbox. It is IMAP’s identifier, and the same number can legitimately name a different message in a different folder. Always carry the folder alongside it — every endpoint below requires both.A uid is also not permanent: moving a message gives it a new one, and a mailbox rebuild can reset the whole range. If you need a durable identifier across time, store message_id, which is the sender’s and never changes.
Bodies are not included in the list — a page of 100 messages with full HTML would be megabytes. Use preview, or fetch the message.

Get one message

Required permission: Messages → Read (messages:read) Takes the same mailbox (required) and folder parameters as the list.
html is sanitised before it reaches you. The stored bytes are whatever a stranger sent us; scripts, event handlers and other active content are removed. text is the message’s own plain-text part, untouched.html is null for a plain-text message, so you can tell “no HTML” from “empty HTML”.
Reading a message does not mark it read. That is a separate, deliberate call — an integration that indexes a mailbox should not silently change what its owner sees as new.

Update a message

Required permission: Messages → Write (messages:write) Takes mailbox (required) and folder as query parameters — naming where the message is now — and the change as a JSON body. Send at least one of:
Flags are applied before any move, so a single call can mark a message read, label it and file it in one step.
add_labels and remove_labels take keywords, not names, and every one must belong to your organization — read them from GET /v1/labels. An unknown keyword is refused before anything is written, so a request naming one bad label does not half-apply.A label’s keyword never changes, even when the label is renamed, so it is the safe thing to store in your own code.
After a move, the response carries no uid. The message has a different one in its new folder and this endpoint does not learn it. Returning the old number beside the new folder would be a value you might store and later use to address the wrong message — "moved": true says “look it up again” instead.When nothing moved, uid is returned unchanged.

Change many messages at once

Required permission: Messages → Write (messages:write) The same change, applied to up to 500 messages in one request.
Use this rather than looping. Archiving five hundred messages one request at a time is five hundred round trips against a 600/minute ceiling, and five hundred IMAP sessions on the mail server, to do what the web app does in one click. This is the same work in one request.Pair it with GET /v1/threads, whose uids array is exactly what this endpoint wants — archiving a whole conversation is one list handed straight over.
All the uids must be in the same folder, which is IMAP’s constraint rather than ours: a uid only means anything inside one folder, so a mixed set has no coherent reading.The response returns a count, not uids. After a move every message has a different uid in its new folder and this endpoint does not learn them — five hundred stale numbers a caller might store would be worse than none.

Errors

See Errors for the full response shape.