Playwright email testing: wait for the verification email
Playwright email testing means giving the test its own inbox, signing up with that address, and blocking until the verification email lands. Inflovy adds a wait endpoint so the test never sleeps or polls.
Last updated September 18, 2026
Who this is for
1Playwright suites that sign up, reset a password, or confirm a magic link
2CI pipelines where each run needs a fresh address
3Teams that want the email visible in a dashboard when a test fails
In short
To test an email flow in Playwright, create an Inflovy inbox from the test, fill the signup form with its address, then call GET /v1/inboxes/:id/messages/wait?timeout=30. The call returns within about two seconds of the email arriving, with verificationCode already extracted. Delete the inbox in teardown.
Why email steps make tests flaky
An IMAP or Gmail API client adds a polling loop, credentials in CI, and 5–10 seconds per test.
Gmail "+" aliases leak your real address, sites strip the "+", and Gmail silently de-duplicates identical test emails.
Parallel workers that share one mailbox read each other’s codes.
When a test fails, nobody can see what the email actually said.
What changes with a wait endpoint
One inbox per test: created in the test, deleted in teardown, never shared between workers.
wait holds the request open (1–60 s) and returns the first message that arrives after the call started.
verificationCode, candidates[] and links[] come back extracted; the test reads a field, not HTML.
The inbox and its messages stay in the workspace dashboard so a failing run can be inspected.
How to do it
- 1
Create an API key
Settings → API on a Pro or Team workspace. The secret is shown once; store it as INFLOVY_API_KEY in CI.
- 2
Create an inbox in the test
POST /v1/inboxes with the key. The response has id and emailAddress.
- 3
Sign up with the address
Fill your form with inbox.emailAddress and submit as usual.
- 4
Wait for the email
GET /v1/inboxes/:id/messages/wait?timeout=30. Assert status === "received", then use message.verificationCode or message.links[0].
- 5
Clean up
DELETE /v1/inboxes/:id in afterEach so the inbox count stays low. Messages are removed with it.
const api = 'https://api.inflovy.com/v1';
const headers = { Authorization: `Bearer ${process.env.INFLOVY_API_KEY}` };
const inbox = await (await fetch(`${api}/inboxes`, { method: 'POST', headers })).json();
await page.goto('https://yourapp.test/signup');
await page.fill('#email', inbox.emailAddress);
await page.click('text=Sign up');
const res = await (await fetch(`${api}/inboxes/${inbox.id}/messages/wait?timeout=30`, { headers })).json();
expect(res.status).toBe('received');
await page.fill('#code', res.message.verificationCode);
await page.click('text=Verify');
await fetch(`${api}/inboxes/${inbox.id}`, { method: 'DELETE', headers });Needs an API key from Settings → API on a Pro or Team workspace. Full reference at /docs/api.
IMAP polling versus an Inflovy wait call.
What the test has to do in each approach.
| Need | IMAP / Gmail API | Inflovy |
|---|---|---|
| Getting an address | A shared mailbox or a "+" alias on a real account. | POST /v1/inboxes returns a fresh address in under a second. |
| Waiting for the email | A retry loop with sleep(); tune the interval, hope the mail is fast. | One GET that returns ~2 s after arrival or a clean { status: "timeout" }. |
| Reading the code | Parse MIME, strip HTML, write a regex per template. | message.verificationCode and links[] are on the response. |
| Parallel runs | Workers share one inbox and race for the same message. | Each worker owns its inbox; nothing to coordinate. |
| Credentials in CI | A mailbox password or OAuth refresh token. | One API key, scoped to the workspace, revocable from Settings. |
Questions people ask before switching.
Short answers. Inflovy is a receive-only test inbox for developers and QA teams; it does not replace your mailbox or send anything.
How fast does wait return after the email is sent?
Inflovy polls storage every second, so wait returns within about two seconds of the message arriving. Inbound delivery itself usually takes a few seconds from the sender.
What if the email never arrives?
After timeout seconds (1–60) the call returns HTTP 200 with { status: "timeout" } so the test can fail with a clear assertion instead of a network error.
Can I wait for a second email in the same inbox?
Yes. Pass since=<messageId or ISO timestamp> and wait only considers messages that arrived after that marker.
Which plans include the API?
Pro ($12/month) and Team ($39/month). Free workspaces can see the samples and create a key after upgrading; the Chrome extension and dashboard work on every plan.
Related guides
Nearby workflows and comparisons, so you can evaluate the right one without guessing.
Give every Playwright run its own inbox.
Create a workspace, add an API key, and paste the sample. The first inbox on the homepage needs no account at all.