Skip to content
machinemail

Search and export

Find messages, threads and inboxes with full-text search and filters, fetch messages in batches, and export an inbox as mbox or JSON lines.

Search messages in an inbox

Terminal
curl "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages/search?q=invoice%20march" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

How q matches:

  • It searches the subject, the from, to and cc addresses, the plain-text body (or the HTML with tags stripped) and attachment filenames.
  • Every word must match. invoice march finds messages that contain both.
  • The last word is a prefix, so invoi finds invoice. Earlier words match whole words.
  • Case does not matter. Punctuation other than @ . + _ ' - inside words is ignored.

Search also takes before and after (ISO 8601 timestamps), limit and page_token. It never returns mail with the hidden labels SPAM, BLOCKED, TRASH, QUARANTINE or UNAUTHENTICATED.

Response (trimmed)
{
  "count": 1,
  "limit": 50,
  "messages": [
    {
      "message_id": "msg_01m4fybrc20000ypd31v108d71",
      "thread_id": "thd_01m4fybrc2000195s5ghmfqfnq",
      "labels": ["INBOX", "UNREAD"],
      "from": "ada@example.com",
      "subject": "Invoice",
      "preview": "Invoice attached.",
      "attachments": [{ "attachment_id": "att_01m4fybrc10000qyygf5yv5thv", "filename": "invoice.pdf", "size": 13, "content_type": "application/pdf" }],
      "direction": "inbound",
      "trust_level": "unknown"
    }
  ]
}

Results are message items, without bodies or trust reports. Fetch the full message by ID when you need them.

Search threads

Pass q to the thread list, either across every inbox the key can see or within one inbox:

Terminal
curl "https://api.machinemail.dev/v0/threads?q=invoice" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

curl "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/threads?q=invoice" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

/v0/threads/search?q= and /v0/inboxes/{inbox_id}/threads/search?q= do the same thing. Thread search runs the message search above and returns the threads those messages belong to. It considers the newest 500 matching messages; when there were more, the response has "truncated": true. Narrow the query or add after and before in that case.

Filter lists

Message and thread lists take filters that combine with q (threads) or work on their own:

ParameterEffect
labelsOnly items with any of these labels. Repeat the parameter, or pass a comma-separated list or JSON array.
before, afterISO 8601 bounds on the message timestamp.
ascendingtrue for oldest first.
include_spamInclude SPAM. Needs label_spam_read.
include_blockedInclude BLOCKED. Needs label_blocked_read.
include_trashInclude TRASH. Needs label_trash_read.
include_unauthenticatedInclude UNAUTHENTICATED. Needs label_unauthenticated_read.
include_quarantineInclude QUARANTINE.
limit, page_tokenPagination: 50 per page by default, at most 500.

Asking for a hidden label in labels also includes it, so labels=QUARANTINE lists the quarantine. Without the matching permission the hidden label stays excluded. See Threads and messages.

Quarantine review queue
curl "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages?labels=QUARANTINE&after=2026-10-01T00:00:00Z" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

Note

For inbound mail, timestamp comes from the sender’s Date header. Use before and after for reporting, not as a cursor for new mail. For new mail, use the UNREAD label or events.

Search inboxes

Terminal
curl "https://api.machinemail.dev/v0/inboxes/search?q=support" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

This matches q as a substring of the address or the display name. It scans the newest 500 inboxes in the key’s scope and sets "truncated": true when there were more. The response has count and inboxes but no pagination.

Fetch many messages at once

batch-get returns full messages, with bodies and trust reports, for up to 100 IDs:

Terminal
curl https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages/batch-get \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message_ids": ["msg_01m4fybrc20000ypd31v108d71", "msg_01m4fy8han0000y3ge3m73vw3w"]}'

IDs that do not exist in the inbox are skipped, and results keep the order you asked for. batch-update takes the same message_ids with add_labels and remove_labels, which is the quickest way to mark search results read:

Terminal
curl https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages/batch-update \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message_ids": ["msg_01m4fybrc20000ypd31v108d71"], "remove_labels": ["UNREAD"]}'

Export an inbox

GET /v0/inboxes/{inbox_id}/export streams every message in the inbox, oldest first, as a file download. It includes all labels, hidden ones too.

formatContent typeEach entry
mbox (default)application/mboxThe original raw MIME, in mboxrd format. Opens in Thunderbird, Apple Mail and most mail tools.
jsonlapplication/x-ndjsonOne full message per line, in the same JSON as GET .../messages/{message_id}, trust report included.
Terminal
curl -o support-agent.mbox "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/export?format=mbox" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

curl -o support-agent.jsonl "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/export?format=jsonl" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
export.py
import json, os, requests

url = "https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/export"
with requests.get(url, params={"format": "jsonl"}, headers={"Authorization": f"Bearer {os.environ['MACHINEMAIL_API_KEY']}"}, stream=True) as res:
    res.raise_for_status()
    for line in res.iter_lines():
        if line:
            msg = json.loads(line)
            print(msg["timestamp"], msg["direction"], msg.get("subject"))

Export needs message_read. Attachments are inside the mbox MIME; the JSON lines export has attachment metadata only, so download files separately if you need them. See Attachments.

Export an ephemeral inbox before it expires. Once the reaper deletes it, its mail is gone.

Raw MIME for one message

Terminal
curl -o message.eml https://api.machinemail.dev/v0/inboxes/support-agent@machinemail.dev/messages/msg_01m4fybrc20000ypd31v108d71/raw \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"

The response is the original message as received (or as sent) with Content-Type: message/rfc822. Raw MIME is untrusted input; do not pass it to a model.