Skip to content
Tutorials

Instant Inbox via API: Create, Use, and Expire Safely

| | 10 min read
Instant Inbox via API: Create, Use, and Expire Safely
Instant Inbox via API: Create, Use, and Expire Safely

When your workflow needs an email address right now, waiting on a human mailbox or reusing a shared test inbox is the fastest path to flaky tests, leaked secrets, and confusing “which run was this?” debugging.

An instant inbox via API flips the model. You provision a fresh, disposable inbox for a single purpose (a test run, a verification attempt, an agent task), consume the incoming email as structured JSON, and then let the inbox expire on a short, intentional lifecycle.

This guide shows a practical, reliability-first way to create, use, and expire an instant inbox safely, with patterns that work well for CI, QA automation, and LLM agents.

For the canonical Mailhook API contract and the exact request/response shapes, use: mailhook.co/llms.txt

What “instant inbox” should mean (beyond “a random email address”)

For automation and agents, an instant inbox is not just a syntactically valid address. It is a routable email destination with a handle you can query, clear lifecycle semantics, and deterministic delivery mechanics.

Here are the properties that matter in practice:

  • Provisionable: create inboxes on demand via REST API.
  • Isolated: one inbox per run, attempt, or agent task, so parallelism is safe.
  • Machine-readable: received emails are delivered as structured JSON, so you assert on fields, not on brittle HTML.
  • Eventable: low-latency notification (webhooks) plus a deterministic fallback (polling) for reliability.
  • Expirable: a clear TTL so inboxes do not become accidental data stores.
  • Authenticable: webhook payloads should be verifiable (Mailhook supports signed payloads).

If your “instant inbox” provider cannot model lifecycle and authenticity, you end up rebuilding those guarantees on top of an unreliable primitive.

The lifecycle: create, receive, extract, expire

A simple way to reason about an instant inbox is as a short-lived resource with a contract.

A simple lifecycle diagram with four boxes connected left to right: Create Inbox (API) -> Use Address (signup or trigger email) -> Receive Email (webhook or polling, JSON) -> Expire and Cleanup (TTL, retention). Each box has a small icon (plus, envelope, webhook hook, trash/clock).

Here is the lifecycle broken into phases you can implement as code:

Phase What you do What you should store What can go wrong
Create Provision a new inbox resource via API inbox_id, email, expires_at (or equivalent) Reusing inboxes, no TTL, collisions across runs
Use Feed the email address into the system under test or agent task Correlation metadata (run/attempt IDs) Wrong address, wrong environment domain
Receive Wait for arrival via webhook (preferred) or polling (fallback) Delivery IDs, message IDs, minimal derived artifact Duplicate deliveries, spoofed webhooks, fixed sleeps
Extract Extract the minimal artifact (OTP, magic link) deterministically Artifact hash, extracted value, timestamps HTML scraping breaks, prompt injection into agent
Expire Let the inbox expire and stop accepting new work Audit logs (IDs only), deletion markers Retention creep, accidental PII capture

Step 1: Create an instant inbox via API

The most robust pattern is to create an inbox and pass around an object that includes both:

  • the email address (what the external system needs), and
  • an inbox handle (what your code uses to retrieve messages deterministically).

Many teams call this pattern “email plus inbox handle.” It prevents your automation from scanning a shared mailbox, and it makes parallel runs safe.

A typical create response looks like this conceptually:

{
  "email": "unique-key@your-inbox-domain",
  "inbox_id": "inbox_...",
  "expires_at": "2026-02-27T22:10:45Z"
}

Field names vary by provider, so treat this as a shape, not a promise. For Mailhook’s exact contract, refer to llms.txt.

Shared domain vs custom domain

Your domain choice affects deliverability and governance:

  • Shared domains are fastest to start with (no DNS work) and great for early CI and prototyping.
  • Custom domain support is valuable when you need allowlisting, stronger environment isolation, or tighter operational control.

Mailhook supports both shared domains and custom domains, so you can start simple and upgrade when your constraints change.

Step 2: Use the address with correlation built in

Instant inboxes get their power from correlation. The inbox is already isolated, but you still want traceability across logs and retries.

A practical approach:

  • Generate a run_id or attempt_id for every workflow.
  • Put that ID into your internal logs.
  • If you control the sending system, include it in a header or template variable (for example, as an internal reference string), then match on it.

This keeps debugging actionable: when a run fails, you can answer “which inbox, which message, which delivery?” quickly.

Step 3: Receive emails deterministically (webhook first, polling fallback)

Webhook-first: the default for instant workflows

Webhooks are the best default for instant inbox flows because they are low latency and parallel-safe. Your handler should be designed to tolerate retries and duplicates.

Key practices:

  • Verify authenticity: if your provider supports signed payloads, verify them before parsing.
  • Make processing idempotent: store a delivery identifier (or a stable message identifier) and ignore repeats.
  • Acknowledge quickly: do minimal work in the webhook handler, enqueue deeper processing elsewhere.

Conceptual webhook verification flow:

receive webhook -> verify signature over raw body -> check timestamp tolerance -> dedupe -> enqueue -> respond 2xx

Mailhook supports signed payloads for security, which is a big deal for agent workflows where spoofing and replay are real threats.

Polling fallback: the “still succeeds” path

Even with webhooks, you want a polling fallback for:

  • temporary webhook downtime,
  • local development,
  • CI environments where inbound HTTP is constrained.

A deterministic polling loop should:

  • poll with a deadline (not a fixed sleep),
  • keep a “seen” cursor to avoid reprocessing,
  • stop when the inbox expires.

Conceptual polling pseudocode:

const deadline = Date.now() + 60_000;
let cursor = null;

while (Date.now() < deadline) {
  const messages = await listMessages({ inbox_id, cursor });

  const match = findMatch(messages, {
    subjectContains: "Your verification code",
    toEquals: email
  });

  if (match) return match;

  cursor = nextCursor(messages);
  await sleep(500);
}

throw new Error("Timed out waiting for email");

This style is stable in CI: you either receive a matching message within the budget, or you fail with a clear timeout that includes run_id and inbox_id.

Step 4: Extract only what you need (especially for LLM agents)

For tests and agent tasks, you almost never need to “read the email like a human.” You need one artifact:

  • OTP code
  • magic link
  • verification URL
  • reset link

Treat the email as untrusted input. Emails can contain trackers, unexpected HTML, and content that attempts to manipulate downstream systems.

Recommended guardrails:

  • Prefer text-like fields from the JSON output over rendering HTML.
  • Extract via a narrow parser (regex or URL parser) with strict bounds.
  • Validate outbound URLs before any fetch.

LLM-agent specific safety notes

If an LLM agent will see email content, reduce risk by constraining the interface:

  • Provide the agent only the minimal extracted artifact, not the full message.
  • If you must provide message content, provide a minimized JSON view (selected fields only) and cap length.
  • Never allow the agent to blindly follow links without allowlists.

This is not only a security measure, it also improves agent reliability by reducing ambiguity.

Step 5: Expire safely (TTL, drain windows, and retention discipline)

Most teams get the “create” part right and the “expire” part wrong.

A safe expiry strategy answers three questions:

  1. How long is the inbox valid for new messages? (TTL)
  2. How long do you keep messages available for debugging? (retention)
  3. What happens after expiry? (hard delete, tombstone, or access denied)

Even if the provider expires the inbox automatically, you should still treat expiry as a first-class part of your integration.

Practical TTL recommendations

Use short TTLs by default, then increase only for workflows that truly need it.

Use case Suggested TTL Why
Signup verification test (CI) 10 to 30 minutes Enough for retries and queue delays, limits retention creep
Password reset test 15 to 45 minutes Reset emails can be slower and sometimes retried
LLM agent “wait for email” tool 5 to 20 minutes Keeps agent tasks bounded and reduces leak risk
Manual QA debugging session 1 to 4 hours Humans are slower, but still keep it temporary

Expiry checklist

  • Stop polling when the inbox is expired.
  • Redact or avoid logging message bodies in CI logs.
  • Store only identifiers needed for troubleshooting (inbox ID, message ID, timestamps).
  • If you persist message JSON for debugging, apply a retention policy and access controls.

If you are building for regulated environments, consider treating inboxes as sensitive resources even if they are “disposable.”

Reliability patterns that prevent flaky tests

Instant inboxes remove a huge class of email flakiness, but only if you keep the consumption contract tight.

Common pitfalls and fixes:

Pitfall Symptom Fix
Fixed sleeps Random timeouts in CI Deadline-based wait (webhook or polling)
Shared inbox reuse Tests assert on the wrong message One inbox per run or per attempt
Wide matchers “Found an email” but it is the wrong one Narrow match: recipient + subject intent + time window
No dedupe Double-processing OTP or link Store and enforce idempotency keys
No webhook verification Spoofing and replay risk Verify signed payloads and reject failures closed

Mailhook’s primitives map cleanly onto these needs: disposable inbox creation via API, real-time webhook notifications, polling for fallback, and signed payloads for authenticity.

Implementation notes for batching and high-throughput runs

If you run large suites or many agent tasks, you will care about throughput.

Two practical considerations:

  • Batch email processing: prefer consuming messages in batches when doing backfills, reprocessing, or large parallel runs.
  • Backpressure: keep webhook handlers fast, queue work, and process asynchronously.

This avoids turning your inbound email layer into the bottleneck of your CI.

FAQ

What is an instant inbox? An instant inbox is a disposable, programmatically created inbox that can receive real emails and deliver them to your code (often as JSON) with clear lifecycle and retrieval semantics.

How do I safely use an instant inbox for signup verification? Create a fresh inbox per attempt, use webhooks to receive the email quickly, verify signed payloads, extract only the OTP or verification link, then let the inbox expire.

Webhooks or polling, which is better? Webhooks are usually better for latency and scale. Polling is still valuable as a fallback when webhooks are temporarily unavailable or inbound HTTP is constrained.

How long should a disposable inbox live? For CI and agent workflows, keep TTLs short (often minutes, not days). Long-lived inboxes become shared state and increase the chance of leaks and collisions.

Can LLM agents read emails directly? They can, but it is safer to give agents only the minimal extracted artifact (OTP or URL) and to treat email content as untrusted input.

Try Mailhook for instant inbox workflows

If you want an instant inbox via API that is built for automation and agents, Mailhook provides disposable inbox creation, emails delivered as structured JSON, real-time webhooks, polling fallback, signed payloads, and batch processing.

No credit card is required to get started.

instant inbox email automation API testing AI agents webhook integration

Related Articles