Mailread.Open inbox
A REFERENCE THAT MATCHES THE API

Build around your inbox.

Read-only access to an authorized mailbox. Structured responses, explicit limits, and examples you can copy into your scripts.

1. Quickstart

Base URL: https://mailread.tech/api/v1. Use your website password to get a token. Never send your email-provider/IMAP password to this API. Replace placeholders with credentials issued by your administrator.

cURL · get a token
curl --fail-with-body -X POST 'https://mailread.tech/api/v1/token' \
  -H 'Content-Type: application/json' \
  -d '{"email":"you@example.com","password":"YOUR_WEBSITE_PASSWORD"}'

Copy access_token from the response. Supply it in an Authorization header:

curl --fail-with-body 'https://mailread.tech/api/v1/messages?limit=5' \
  -H 'Authorization: Bearer YOUR_MAILBOX_TOKEN'

The browser inbox uses separate session endpoints. Scripts should use the documented /api/v1 routes below. There is no API endpoint for bypassing mailbox passwords or for anonymous mailbox discovery.

2. Authentication

  • Tokens are read-only and scoped to one mailbox.
  • Tokens expire after 3,600 seconds. Obtain a new token when expired.
  • Changing or resetting the website password revokes previously issued tokens.
  • Send Authorization: Bearer TOKEN on read endpoints. Bulk reads take one token per mailbox in the JSON body.
  • Never put credentials in query strings. This API does not enable cross-origin browser access (CORS).
  • POST bodies must use Content-Type: application/json. Versioned API requests do not require cookies or CSRF tokens.

3. Limits and polling

LimitCurrent behavior
Read requests120 per token per minute
IP requests300 credits per minute; a bulk batch costs 10
Token sign-ins10 per identifier/IP in 15 minutes; shared IP sign-in cap of 60
Bulk readUp to 10 tokens per batch
Message listLatest 30 search candidates, exact-recipient filtered; INBOX only
Request body128 KiB maximum
Upstream cacheList: 5 seconds; opened message: 2 minutes

Poll every 10 seconds or slower, use a timeout of at least 60 seconds, and back off on 429/502. Read Retry-After on 429. Authenticated single-mailbox responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset (Unix time). The VPS proxy may apply additional limits. App quotas are process-local.

since_uid is IMAP-only and exclusive. Gmail API clients should deduplicate (uid, epoch) pairs while polling; passing since_uid in Gmail mode returns 400. Store each UID alongside its epoch and reset your cursor when the epoch changes. There is no historical pagination; poll often enough that your expected traffic fits the 30-candidate window.

Endpoint reference

POST/api/v1/tokenWebsite password

Get a mailbox token

Exchange an email address (or mailbox_id from its reading URL) and website password for a read-only Bearer token. The token expires after one hour. Password changes invalidate existing tokens.

ParameterTypeUsage
emailstringRequired unless mailbox_id is supplied.
mailbox_idUUID stringAlternative to email; do not send both.
passwordstringRequired. The Mailread website password, never the IMAP password.
cURL
HTTP 200 · application/json
{
  "access_token": "YOUR_MAILBOX_TOKEN",
  "expires_in": 3600,
  "mailbox": {
    "email": "you@example.com",
    "id": "11111111-1111-4111-8111-111111111111"
  },
  "scope": "mail:read",
  "token_type": "Bearer"
}

No cookies or CSRF token are needed for /api/v1. POST requests require application/json. Never put passwords or tokens in a URL.

GET/api/v1/mailboxBearer token

Identify the authorized mailbox

Returns only the mailbox authorized by the token. There is no endpoint that lists other users’ mailboxes.

cURL
HTTP 200 · application/json
{
  "data": {
    "email": "you@example.com",
    "id": "11111111-1111-4111-8111-111111111111"
  }
}
GET/api/v1/messagesBearer token

List recent mail

Newest-first summaries from the latest 30 provider search candidates, after exact-recipient filtering. This is a recent-mail window, not a complete mailbox export.

ParameterTypeUsage
limitinteger 1–30Optional; default 30.
searchstring ≤200Optional; matches sender, subject, snippet or extracted code.
senderstring ≤200Optional; case-insensitive sender substring.
subjectstring ≤200Optional; case-insensitive subject substring.
since_uidnumeric stringIMAP-only; larger UIDs. Gmail clients should deduplicate uid/epoch pairs.
cURL
HTTP 200 · application/json
{
  "data": [
    {
      "address": "hello@example.com",
      "code": "123456",
      "date": "2026-10-23T10:00:00+00:00",
      "epoch": "100",
      "from": "Example \u003chello@example.com\u003e",
      "sender": "Example",
      "snippet": "Your verification code is 123456.",
      "subject": "Your verification code",
      "uid": "42"
    }
  ],
  "meta": {
    "cached": false,
    "fetched_at": "2026-10-23T10:00:00+00:00",
    "has_more": false,
    "returned": 1,
    "window": 30
  }
}

Filters apply within the 30-message window. has_more means upstream search returned over 30 candidates; it does not expose a pagination cursor. Message data is cached in RAM for up to five seconds.

GET/api/v1/messages/{uid}Bearer token

Read a message

Returns normalized text, safe structured blocks, visible HTTP(S) links and an image-blocking count. The UID and epoch must come from this mailbox’s message list.

ParameterTypeUsage
uidopaque path stringRequired opaque message UID from the list; Gmail IDs have a g_ prefix.
epochnumeric query stringRequired epoch from the list; IMAP uses UIDVALIDITY, Gmail uses 1.
cURL
HTTP 200 · application/json
{
  "data": {
    "address": "hello@example.com",
    "blocks": [
      {
        "runs": [
          {
            "text": "Your verification code is 123456."
          }
        ],
        "type": "paragraph"
      }
    ],
    "code": "123456",
    "date": "2026-10-23T10:00:00+00:00",
    "epoch": "100",
    "from": "Example \u003chello@example.com\u003e",
    "images_blocked": 1,
    "links": [],
    "sender": "Example",
    "snippet": "Your verification code is 123456.",
    "subject": "Your verification code",
    "text": "Your verification code is 123456.",
    "truncated": false,
    "uid": "42"
  }
}

Images, scripts, attachments and original sender HTML are never returned for rendering. IMAP reads the first 1 MiB of MIME. Gmail transfers at most 4 MiB of JSON and decodes up to 1 MiB of text, falling back to a snippet when oversized. Previews are limited to 200,000 characters/2,000 blocks; truncated=true indicates a bounded preview. Opened content is cached in RAM for up to two minutes.

GET/api/v1/latestBearer token

Get the newest matching message

Returns the newest summary, or {"data":null} with HTTP 200 when nothing matches.

ParameterTypeUsage
sender / subject / searchstring ≤200Optional filters, as in the message list.
since_uidnumeric stringIMAP-only exclusive minimum UID. Gmail clients should deduplicate uid/epoch pairs.
cURL
HTTP 200 · application/json
{
  "data": {
    "address": "hello@example.com",
    "code": "123456",
    "date": "2026-10-23T10:00:00+00:00",
    "epoch": "100",
    "from": "Example \u003chello@example.com\u003e",
    "sender": "Example",
    "snippet": "Your verification code is 123456.",
    "subject": "Your verification code",
    "uid": "42"
  }
}
GET/api/v1/otpBearer token

Extract a recent email code

Finds the newest detected numeric verification code among the recent summaries, fetching up to five message bodies when snippets do not contain a code. Detection is heuristic, not proof of authenticity.

ParameterTypeUsage
formatjson or textOptional; default json.
sender / subject / searchstring ≤200Optional filters.
since_uidnumeric stringIMAP-only; useful while waiting for new mail. Gmail clients deduplicate uid/epoch pairs.
cURL
HTTP 200 · application/json
{
  "data": {
    "code": "123456",
    "date": "2026-10-23T10:00:00+00:00",
    "epoch": "100",
    "uid": "42"
  }
}

JSON returns data:null with HTTP 200 when no code is detected. format=text returns just the code (200), or an empty response (204). This reads codes from mail; it does not generate TOTP codes from a 2FA secret.

POST/api/v1/bulk/messagesOne token per mailbox in JSON

Read multiple authorized mailboxes

Read up to ten mailboxes in one request. Every mailbox must have its own valid token; a token cannot authorize another mailbox. Results preserve input order, with per-item errors.

ParameterTypeUsage
tokensarray of 1–10 stringsRequired mailbox Bearer tokens, without the Bearer prefix.
cURL
HTTP 200 · application/json
{
  "results": [
    {
      "data": [
        {
          "address": "hello@example.com",
          "code": "123456",
          "date": "2026-10-23T10:00:00+00:00",
          "epoch": "100",
          "from": "Example \u003chello@example.com\u003e",
          "sender": "Example",
          "snippet": "Your verification code is 123456.",
          "subject": "Your verification code",
          "uid": "42"
        }
      ],
      "index": 0,
      "mailbox": {
        "email": "you@example.com",
        "id": "11111111-1111-4111-8111-111111111111"
      },
      "meta": {
        "cached": false,
        "fetched_at": "2026-10-23T10:00:00+00:00"
      }
    },
    {
      "error": {
        "code": "invalid_token",
        "message": "A valid mailbox Bearer token is required."
      },
      "index": 1
    }
  ]
}

HTTP 200 can contain successful and failed items. Each token consumes one read from its quota. A batch consumes ten IP request credits. All tokens and credentials stay out of URLs.

GET/api/v1/healthPublic

Check application health

Checks the web process, not upstream mail-provider connectivity. It does not reveal configuration or mailbox counts.

cURL
HTTP 200 · application/json
{
  "api_version": "1",
  "status": "ok"
}

Errors and empty results

Application errors use the JSON envelope below. A reverse proxy may return a non-JSON error; check the HTTP status before parsing the body.

{
  "error": {
    "code": "invalid_token",
    "message": "A valid mailbox Bearer token is required."
  }
}
StatusMeaningAction
400Invalid JSON, parameters or missing epochFix the request.
401Wrong credentials, invalid/expired/revoked tokenReauthenticate with the current website password.
404Message unavailable or does not belong to this mailboxRefresh the list; do not reuse another mailbox’s UID.
413Body exceeds 128 KiBReduce batch/input size.
415POST is not application/jsonSet the JSON content type.
429Application or proxy rate limit reachedHonor Retry-After; add backoff/jitter.
502Mail provider unavailableRetry later; check server configuration if persistent.
500Unexpected application errorRetry with backoff; contact the server owner.

Empty lists return {"data":[]} with metadata. Latest/OTP JSON returns {"data":null} when empty. OTP text returns an empty 204. Bulk reads return 200 with an error on each failed item; always inspect every result.

Data model and privacy

  • uid and epoch are strings. Treat them as opaque identifiers. IMAP uses numeric UIDs and UIDVALIDITY; Gmail uses a g_ prefix and epoch 1.
  • code is a detected 4–8 digit string or null. It is heuristic and can be wrong.
  • Dates normally use ISO 8601; malformed upstream dates may remain in their original string form.
  • text is readable text including link destinations. blocks contains safe paragraph/heading/list/pre runs with optional href/bold/italic fields.
  • links contains visible HTTP(S) destinations. Links are extracted, not visited.
  • images_blocked counts removed HTML image elements. No sender images/scripts or original HTML are rendered.
  • The VPS stores mailbox addresses and password hashes. Message previews are temporarily cached in RAM. Backups contain private access configuration and should be protected.
  • The formatter and TOTP generator are browser-only utilities. There is intentionally no server endpoint that accepts a TOTP secret.
  • All configured domains share the same installation and connected master account (IMAP or Gmail HTTPS API). API tokens work across those hostnames; browser cookies are separate per hostname.

Machine-readable schemas for requests, summaries, message bodies and errors are included in openapi.json.