# wait_for_email — the OTP flow

{/* // BLOCK UNTIL IT LANDS */}

Agents sign up for things. The high-value, time-boxed task is "wait for the verification email and
read the code before the 5-minute window closes." `wait_for_email` is the primitive for exactly that:
a **blocking** call that returns the next matching message with the **OTP code and verification link
already extracted**.

No polling loop. Postern blocks server-side on the inbox (IMAP IDLE on WildDuck) and hands you a
structured result the moment a matching message arrives.

## The shape of the flow

1. Create a mailbox and use its address as the sign-up email.

2. Trigger the sign-up elsewhere (it emails an OTP to your address).

3. Call `wait_for_email` with an optional `from` / `subject` / `regex` filter — it blocks until a
   match lands or the timeout elapses.

4. Read `extracted.otp` / `extracted.link` and submit it back.

## Wait for it

```ts title="wait-for-otp.ts"
import { Postern } from "@postern/sdk";

const postern = new Postern({ apiKey: process.env.POSTERN_API_KEY! });
const inbox = await postern.inboxes.create({ username: "signup-agent" });

// Trigger a sign-up that emails an OTP to inbox.address.
await fetch("https://acme.test/signup", {
  method: "POST",
  body: JSON.stringify({ email: inbox.address }),
});

// Block until it lands (up to 2 min), then read the structured result.
const result = await inbox.waitForEmail({
  from: "no-reply@acme.test",
  subject: "verification",
  timeout_seconds: 120,
});

if (result.timed_out) throw new Error("no email in time");

console.log(result.extracted.otp);  // "492013"
console.log(result.extracted.link); // "https://acme.test/verify?token=…"
```

  ```json title="wait_for_email (tool call)"
{
  "name": "wait_for_email",
  "arguments": {
    "address": "signup-agent@x4p.mszazu.com",
    "from": "no-reply@acme.test",
    "subject": "verification",
    "timeout_seconds": 120
  }
}
```

```json title="result"
{
  "timed_out": false,
  "message": { "id": "msg_8Tz", "from": "no-reply@acme.test", "subject": "Verify your email" },
  "extracted": {
    "otp_code": "492013",
    "verification_link": "https://acme.test/verify?token=…"
  }
}
```

Because the host gets the code in the **same turn**, the agent can submit it without losing the
window. This is what makes Postern feel different from "an inbox you poll."

  ```bash frame="terminal"
curl -sS -X POST \
  "$POSTERN_API_BASE_URL/v1/inboxes/signup-agent@x4p.mszazu.com/wait" \
  -H "Authorization: Bearer $POSTERN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from": "no-reply@acme.test", "subject": "verification", "timeout_seconds": 120 }'
```

The request hangs (long-poll) until a matching message arrives or the timeout elapses. Set your HTTP
client's read timeout above `timeout_seconds`.

  ## What gets extracted

The `extracted` object comes from the same OTP/link extraction machinery that has pulled codes out of
real mail for years.

| Field | Meaning |
|---|---|
| `otp_code` | The numeric / alphanumeric one-time code, if one was found. |
| `verification_link` | The first click-through verification URL, if one was found. |
| `credentials` | Username/password pairs when the message contains them. |

In the SDK these are `extracted.otp`, `extracted.link`, and `extracted.credentials`. Need extraction
without a wait? Import `extractOtp` / `extractLink` / `extractCredentials` and run them on any string.

## Filters

| Filter | Behavior |
|---|---|
| `from` | Match the sender address (substring, case-insensitive). |
| `subject` | Match the subject (substring, case-insensitive). |
| `regex` | Match the message body against a regular expression. |
| `since` | Only consider messages newer than this timestamp (default: the call time). |
| `timeout_seconds` | How long to block. Server caps at the configured maximum (default 300s). |
**Set client timeouts above the wait:** `wait_for_email` is a long-poll: the HTTP request stays open until a match or the timeout. Make
  sure your HTTP client (and any proxy) allows a read timeout longer than `timeout_seconds`. The SDK
  and MCP server manage this for you.

## Next

- [MCP `wait_for_email`](https://docs.agents.mszazu.com/mcp/wait-for-email/) — the tool definition and host behavior.
- [API · wait_for_email](https://docs.agents.mszazu.com/api/wait/) — the endpoint contract.
- [Inboxes](https://docs.agents.mszazu.com/concepts/inboxes/) — the receive model behind it.