Skip to content

Waiting for mail

A test triggers an email, then needs it. Polling the list works but wastes time on every iteration. The await endpoint holds the request open until a matching message arrives, then returns its summary:

GET /v1/mailboxes/{mailboxId}/messages/await?to=…&subject=…&from=…&since=…&timeout=30

All filters are optional, case-insensitive substring matches, and combine with AND.

Parameter Matches
to The recipient address contains this
subject The subject contains this
from The sender address contains this
since Only messages received at or after this time (ISO 8601)
timeout Seconds to wait, 1 to 60. Default 30

since defaults to five seconds before the request, so a message that landed just before the call still counts. Set it explicitly when a test sends several emails to the same address and needs the newest.

Status Meaning
200 A message matched. The body is its summary: id, from, to, subject, receivedAt, sizeBytes, attachmentCount
204 Nothing matched within the timeout. No body
404 The mailbox does not exist or is outside the key’s scope

The summary has no body text. Fetch the full message by id to read textBody, htmlBody, headers and attachments.

const summary = await mc.messages.await(mailboxId, {
to: address,
subject: "Reset your password",
timeoutSeconds: 30,
});
if (!summary) throw new Error("Password reset email did not arrive");
const message = await mc.messages.get(mailboxId, summary.id);
const link = message.textBody?.match(/https:\/\/\S+\/reset\?token=\S+/)?.[0];

Most transactional mail arrives in one to three seconds. Thirty seconds is a comfortable default that survives a slow provider without hanging a suite. The server caps a single call at 60 seconds; loop if you need longer.

Filtering on subject alone is fragile when tests run in parallel and several send the same email. Give each test its own recipient address and filter on to. The address costs nothing and needs no setup. See Mailboxes and addresses.