1mail.dev
@1mail.dev

API

Three GET endpoints, the errors they return, and the cadence we recommend — read-only, no keys, and an OpenAPI contract clients and types generate from.

Every inbox at 1mail.dev is public. Anyone who knows the address can read it. Never use these addresses for anything sensitive — or any account you care about.

Base URL

https://api.1mail.dev/v1 · read-only · no keys · machine-readable contract: /openapi.json (client + types + schemas generate from it).

Endpoints

GET/v1/inboxes/{address}/messages

List an inbox, newest first. Any syntactically valid address answers 200 — never-existed and all-expired are the same state.

  • limit — page size, default 100, max 1000.
  • since_id — only messages strictly newer than this id: your poll cursor.
  • older_than_id — page back from this id.
  • wait — hold the call for mail instead of polling (see below).

Polling: the strong ETag is the newest message id — send If-None-Match and an unchanged poll answers 304 in one indexed read. Poll at most every 2 s.

Waiting: send wait=20000 with your since_id cursor and the call holds until mail newer than the cursor lands — a signup flow is one request instead of a loop (0..30000 ms; a bare wait without a cursor returns only future arrivals). On timeout you get 200 with an empty list: retry to keep waiting. A held call counts as one read.

curl "https://api.1mail.dev/v1/inboxes/test-runner-42@1mail.dev/messages?since_id=0198…&wait=20000"

GET/v1/inboxes/{address}/messages/{id}

One full parsed message: text, unsanitized html (treat as untrusted!), curated headers, attachment metadata.

404 when the id is unknown or expired — the same state. The id is the UUID list returns.

curl "https://api.1mail.dev/v1/inboxes/test-runner-42@1mail.dev/messages/0190…-…/1.json"

GET/v1/inboxes/{address}/messages/{id}/raw

The untouched original as message/rfc822, attachment disposition — never rendered on our origin.

Assert on the raw bytes your app sent.

curl -OJ "https://api.1mail.dev/v1/inboxes/test-runner-42@1mail.dev/messages/0190…/raw"

Errors

RFC 9457 problem details (application/problem+json): 400 bad address syntax · 404 unknown/expired message · 429 rate limited · 500. Every response carries advisory RateLimit-Limit / -Remaining / -Reset; a 429 adds Retry-After. Honor them.

Recommended cadence

Waiting for mail? Send wait=20000 with your since_id cursor — the call holds until mail newer than the cursor lands (or answers an empty 200 after 20 s; retry to keep waiting). A held call counts as one read.

Polling instead? At most every 2 seconds — 304s replay your cached body, so re-read your own expires_at and stop when the message ages out.