Messages and threads

Every email sent or received by an inbox is a message. Replies are grouped into threads using the standard In-Reply-To and References headers.

The message object

FieldTypeDescription
idstringPrefixed id such as msg_01jbz9c3….
inbox_id, thread_idstringThe inbox it belongs to and its thread.
direction"in" | "out"Received or sent.
from, to, ccstring, string[]Addresses as they appear in the headers.
delivered_tostring[]For received mail, the addresses it was delivered to (the SMTP envelope). On a Catch-all this is the address the sender used.
subjectstringThe decoded subject.
text, htmlstring | nullBody parts. Either can be null.
references, in_reply_tostring[], string | nullThreading headers.
spambooleanTrue when the spam score passed the threshold. The message is still stored.
auth_resultsobject | nullSPF, DKIM and DMARC results: pass, fail, softfail, none or temperror.
size_bytesnumberSize of the raw message.
statusstringDelivery status for sent mail; received for inbound.
attachmentsAttachment[]id, filename, content_type and size_bytes for each file.
{
  "id": "msg_01jbz9c3m7xq...",
  "inbox_id": "ibx_01jbz8w4k2q9...",
  "thread_id": "thr_01jbz9c3m7xr...",
  "direction": "in",
  "from": "auth@yourapp.dev",
  "to": ["signup-bot@k7m3qz.mailbay.email"],
  "cc": [],
  "subject": "Your sign in code",
  "text": "Use 482913 to finish signing in.",
  "html": "<p>Use <b>482913</b> to finish signing in.</p>",
  "references": [],
  "in_reply_to": null,
  "spam": false,
  "auth_results": { "spf": "pass", "dkim": "pass", "dmarc": "pass" },
  "size_bytes": 4182,
  "status": "received",
  "created_at": "2026-10-13T09:41:07Z",
  "attachments": []
}

List messages

GET/v1/inboxes/{id}/messages?limit=&cursor=

Newest first. limit is 1 to 100 and defaults to 50. Pass the next_cursor from a page to get the next one; it is null on the last page.

curl "https://api.mailbay.dev/v1/inboxes/ibx_01jbz8w4k2q9/messages?limit=20" \
  -H "Authorization: Bearer $MAILBAY_API_KEY"

# {"data": [ ...messages ], "next_cursor": "msg_01jbz7..."}

Wait for an email

GET/v1/inboxes/{id}/wait?from=&subject=&to=&timeout=

A long poll that returns as soon as a matching message arrives, with one time codes and links already extracted. This is how an agent finishes a sign up in two calls. from and subject match part of the sender and subject; to matches one recipient address exactly, which pairs well with the Catch-all: sign up as signup-42@k7m3qz.mailbay.email and wait for that address.

curl "https://api.mailbay.dev/v1/inboxes/ibx_01jbz8w4k2q9/wait?subject=code&timeout=60" \
  -H "Authorization: Bearer $MAILBAY_API_KEY"

mailbay wait ibx_01jbz8w4k2q9 --to signup-42@k7m3qz.mailbay.email --timeout 60

Threads

GET/v1/inboxes/{id}/threads

GET/v1/threads/{id}

An inbound message joins the thread of any message in the same inbox whose Message-ID appears in its In-Reply-To or References. Otherwise it starts a new thread. Replies you send set both headers, so threads hold in Gmail and Outlook. A thread returns its messages oldest first.

Raw message

GET/v1/messages/{id}/raw

Returns the original message as message/rfc822, exactly as our server received it.

Reading a message from another organization returns not_found, never the message. See Errors.

Something unclear or wrong? The API answers every error with a fix, and so should these docs. Back to mailbay.dev