Skip to main content

Verification email never arrives

Work through these in order — the cause is almost always upstream of the inbox:
1

Confirm the address is correct

Log the exact address your test submitted. A typo’d domain silently drops mail.
2

Check the sending side

Look at your app’s SMTP/server logs. If the send failed or queued, no inbox will ever show it. This is the most common cause.
3

Poll the right way

Use GET /api/mails?limit=1&offset=0 with the same JWT that created the address. Mail lists are cached for 60 seconds at offset=0 — a brand-new mail can take up to a minute to appear in a cached response.
4

Extend the timeout

Local/staging SMTP delivers in seconds; external providers (SES, SendGrid, Postmark) can queue for 30–60s. Use a 60-second poll timeout in CI.
5

Check the sender's spam reputation

Some senders’ mail is rejected at SMTP level before reaching any inbox. Test the same flow with a personal address to isolate.

POST /api/new_address fails or challenges

The public instance protects address creation with Cloudflare Turnstile. Scripts calling it directly without a valid cf_token will fail. Fix for automation: don’t create addresses from scripts. Pre-create the address in the web UI, copy the JWT (DevTools → Application → Cookies → jwt), and use it in your scripts. The mail-reading endpoints don’t require Turnstile. Full workflow in API Overview. Self-hosted: disable Turnstile in your instance config and POST /api/new_address returns a JWT directly.

429 Too Many Requests

Rate limits apply per IP, per path. Common triggers: Back off exponentially on 429 — hammering a rate-limited endpoint extends the limit window.

401 / invalid JWT

  • JWTs are bound to a specific address. If the address was deleted, its JWT stops working — create a new inbox.
  • Copying the JWT with surrounding whitespace or quotes breaks the header. Send exactly: Authorization: Bearer <jwt>.
  • Clearing browser data removes the cookie the UI relies on; the raw JWT string you saved elsewhere continues to work in API calls.

Parallel tests are flaky

One shared inbox across parallel workers causes race conditions: worker A consumes the mail worker B is waiting for. Fix: every test creates its own inbox. All framework guides follow this pattern — Playwright, Cypress, Selenium. Never pass one address through a CI env var into a parallel test matrix.

OTP extraction returns the wrong code

A \b\d{6}\b regex can match other 6-digit numbers (zip codes, order numbers) in the email body:
  • Anchor the regex near a label: code[:\s]*(\d{6}) or is[:\s]*(\d{6})
  • Prefer parsing the plain-text part over raw HTML — tracking pixels and style blocks add numeric noise
  • Log the raw body on extraction failure so you can fix the pattern, not guess

Mail body is empty or metadata missing

GET /api/mails returns list entries; the full body requires the detail call GET /api/mail/:uuid. metadata is a JSON string — parse it (JSON.parse / json.loads) before reading subject.

Still stuck?

  • API Overview — auth model, Turnstile, rate-limit table
  • API Client Snippets — known-good Python, Node.js, and shell clients to compare against
  • Check the service itself: open tempinbox.dev and send yourself a test mail from a personal account