Waiting
One open request until the mail is there. No sleeps, no polling loops.
waitFor keeps a single HTTP request open. Mailwurf answers as soon as a matching message is stored, or when the timeout ends.
const mail = await inbox.waitFor({ subject: "Confirm", timeout: 15_000 });Options
| Option | Default | Meaning |
|---|---|---|
subject | none | Case-insensitive part of the subject. "confirm" matches "Please Confirm your email". |
timeout | 15000 | Milliseconds. Maximum 120000. 0 checks once without waiting. |
after | none | Message id. Only messages received after it match. |
signal | none | AbortSignal to cancel the wait from the test. |
Matching order
The oldest matching message wins. If it is already stored when the wait starts, the call returns immediately. A wait started after the mail arrived does not miss it.
Several emails in one test
Pass the previous message id as after to wait for the next one:
const first = await inbox.waitFor({ subject: "code" });
await page.getByRole("button", { name: "Resend code" }).click();
const second = await inbox.waitFor({ subject: "code", after: first.id });
expect(second.otp).not.toBe(first.otp);Without after, the second call returns first again, because it is still the oldest match. after must be the id of a message in the same inbox; any other value returns 400.
Timeouts
When nothing matches in time, the client throws MailwurfTimeoutError (HTTP 408).
import { MailwurfTimeoutError } from "@mailwurf/e2e";
try {
await inbox.waitFor({ subject: "Invoice", timeout: 5_000 });
throw new Error("invoice was sent but should not be");
} catch (error) {
if (!(error instanceof MailwurfTimeoutError)) throw error;
}Keep the Mailwurf timeout below the test runner timeout, so the failure names the missing email instead of a generic test timeout.
With timeout: 0 and no match, the call fails with status 404 instead.
Concurrent waits
Each API key can hold four waits open at the same time. A fifth returns 429. With more than four parallel workers, give each CI job its own key or retry the wait after a short pause.
Listing instead of waiting
To assert on everything that has arrived so far, list the messages. The list is newest first.
const messages = await inbox.messages({ subject: "Confirm" });
expect(messages).toHaveLength(1);
Mailwurf