Skip to content

Reading mail

GET /inboxes/:id/messages returns mail for one address, newest first:

{
"messages": [
{
"id": "msg_91be02c4a7d1",
"inboxId": "ibx_k3v9x2mq7a",
"receivedAt": "2026-09-18T09:14:03.000Z",
"read": false,
"sizeBytes": 18432,
"folder": "inbox",
"starred": false,
"content": { "…": "sealed" }
}
],
"nextCursor": null,
"total": 1,
"unread": 1
}

Page with limit (default 50, at most 200) and cursor, passing the previous response’s nextCursor until it is null. total and unread count the whole folder, not the page.

GET /messages/recent returns the account’s newest inbox mail across every address, with limit (default 6, at most 50). GET /inboxes gives each address’s unreadCount.

content is sealed. See Encryption and sealed data.

Mail past its address’s retention window is not returned, and is deleted.

Every message is in one folder:

FolderWhat is in it
inboxMail that arrived. The default.
sentA copy of each message sent from the address, sealed to its key. It carries sentVia: app, api, device, agent, or member for a team member sending from a shared address.
junkMail moved there.
trashMail moved there.

Pass ?folder= to list one. ?folder=starred lists every starred message outside the trash. Any other value lists the inbox.

  • POST /messages/:id/star stars a message, and { "starred": false } unstars it. A star is a flag, not a folder.
  • POST /messages/:id/move with { "folder": "junk" }, "inbox" or "trash" moves it. "restore" takes it out of the trash to the folder it came from. Sent mail can only move to the trash and back.
  • DELETE /messages/:id deletes one message now. POST /messages/empty-trash deletes everything in the trash.

Mail in any folder, the trash included, is still deleted when its retention window ends.

GET /messages/:id returns a single message in the same shape, as message, whichever folder it is in.

GET /messages/:id/attachments/:index returns one attachment body as sealed bytes, Content-Type: application/octet-stream. The real file name and type are inside the sealed message. Inline images, the ones HTML mail shows with <img src="cid:…">, are attachments too, with a contentId in the sealed message. The apps show them in the body when you tap Show images. Each SDK fetches and opens an attachment for you, for example mc.messages.attachment(message, 0) in TypeScript.

POST /messages/:id/read marks a message read. Send { "read": false } to mark it unread.

A paired device reads its own mail with its device credential: GET /workers/messages, with the same folder parameter. It pages back with before, passing the previous response’s olderCursor until it is null, and gets total and unread for the folder. It can also mark, star, move and delete that mail and fetch its attachments with the endpoints above, and opens all of it with the address keys it was handed at pairing. It cannot reach the account’s other addresses. See Devices.

Reading is metered per message body or attachment fetched, not per request. Each plan has an hourly allowance; past it, reads return 429 with Retry-After. See Rate limits.

© Northlab Studios Ltd, trading as Mailcycle. Registered in England and Wales, company no. 17462734. Registered office: 167-169 Great Portland Street, London W1W 5PF.