Skip to content

wait_for_email is a long-poll for the next matching message. It returns the canonical message plus an extracted OTP code and verification link when present. Use it for sign-in, verification, and other time-limited flows where a polling loop would add avoidable state.

  1. Create an inbox and use its address in the external flow.

  2. Trigger the email.

  3. Start the wait with narrow sender or subject filters and since_now: true.

  4. Use the returned message and extracted credentials. A timeout is a normal result, not an HTTP error.

wait-for-code.ts
import { Extrovert } from "@extrovert.dev/sdk";
const extrovert = new Extrovert({ apiKey: process.env.EXTROVERT_API_KEY! });
const inbox = await extrovert.inboxes.create({ username: "signup-agent" });
await fetch("https://acme.test/signup", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ email: inbox.address }),
});
const result = await inbox.waitForEmail({
from: "no-reply@acme.test",
subject: "verification",
match: "(?i)code",
link_hint: "verify",
since_now: true,
timeout_seconds: 120,
});
if (result.timed_out) throw new Error("No verification email arrived in time");
console.log(result.extracted.otp);
console.log(result.extracted.link);
MeaningREST and SDKMCP
Sender substringfromfrom
Subject substringsubjectsubject
Go RE2 expression over subject and readable bodymatchregex
Verification-link preference, not a message filterlink_hintlink_hint
Match only arrivals after the wait startssince_nowsince_now
Wait budgettimeout_secondstimeout_ms

The regular expression is case-sensitive unless it includes (?i). link_hint selects a preferred verification URL from a matched message; it does not decide whether the message matches.

The REST default is 300 seconds and the server cap is 600 seconds. MCP defaults to 120 seconds and also caps at 600 seconds, subject to its configured maximum. Set any proxy or client read timeout above the requested wait. The SDK and MCP package do this automatically.

since_now defaults to true, which excludes mail that arrived before the call. Set it to false only when an already-delivered message should match.

On timeout:

  • REST and SDK return timed_out: true, message: null, and null extracted values.
  • MCP returns matched: false and waited_ms.

Decide whether to retry, extend the wait, or retrigger the external email. Do not treat a normal timeout as malformed message data.

The nested message uses the same body contract as every read:

  • source text and html fields independently represent the MIME alternatives;
  • extracted_text and extracted_html are nullable, best-effort derivatives;
  • no missing format is synthesized from the other;
  • HTML is untrusted and must be sanitized before rendering.

The OTP and verification URL in extracted or the MCP top-level fields are credential extraction, separate from the quoted-text and signature stripping in the message’s extracted body fields.