Playwright
Test emails in Playwright
Your Playwright test signs up with an address like {teamId}[email protected], asks the Zyntra API for the email, and opens the confirmation link — in the same test, with Playwright's own request fixture. No Gmail login, no inbox shared between runs, no HTML parsing.
// tests/signup.spec.ts
import { test, expect } from "@playwright/test";
import { randomUUID } from "node:crypto";
const TEAM = process.env.ZYNTRA_TEAM_ID!;
const KEY = process.env.ZYNTRA_API_KEY!;
test("a new user confirms their email", async ({ page, request }) => {
// The email can take a few seconds: allow more than the 30 s default.
test.setTimeout(90_000);
// A fresh address per run. Nothing to create first.
const email = `${TEAM}.signup-${randomUUID().slice(0, 8)}@zyntramail.com`;
await page.goto("/signup");
await page.getByLabel("Email").fill(email);
await page.getByLabel("Password").fill("a-long-test-password");
await page.getByRole("button", { name: "Create account" }).click();
// One request: waits up to 30 s on the server for the email.
const res = await request.get("https://api.zyntra.app/emails/last", {
params: { email },
headers: { "X-API-Key": KEY },
timeout: 45_000,
});
expect(res.ok()).toBeTruthy();
const message = await res.json();
expect(message.subject).toContain("Confirm");
const confirm = message.links.find((l: { url: string }) =>
l.url.includes("/verify"),
);
await page.goto(confirm.url);
await expect(page.getByText("Email confirmed")).toBeVisible();
});// The same read with the Node.js SDK (npm i zyntramail-api)
import { ZyntraClient } from "zyntramail-api";
const zyntra = new ZyntraClient(); // reads ZYNTRA_API_KEY, ZYNTRA_TEAM_ID
const email = zyntra.generateEmail();
// ...sign up with `email`...
const message = await zyntra.getLastEmail(email);You need two values from the dashboard: an API key (API Keys page) and your team ID (bottom-left of the sidebar). Keep both in environment variables. Getting started shows where they are.
What happens to the email
- Your app sends it through its usual email provider, to an address on zyntramail.com.
- A real mail server receives it and stores it for your team, with its links pulled out of the HTML and text and its attachments kept.
- Your test reads it with one API request. Mail to an address you did not create in the dashboard is deleted after 1 day.
Run it in CI
Add ZYNTRA_API_KEY and ZYNTRA_TEAM_ID as secrets in your CI and expose them to the Playwright step. Nothing else changes: the test talks to the API over HTTPS like any other request, from GitHub Actions, GitLab CI or your own runner.
Parallel workers are safe because every test builds its own address. Two tests never read each other's email, and a retry gets a new address too.
When the same address gets a second email
/emails/last returns the newest email at once when the address already has mail. If a test sends two emails to one address, a sign-up confirmation and then a password reset, check the subject and ask again until the newest email is the one you expect. The password-reset guide has a short helper that does this.
Limits to know about
- Playwright's default test timeout is 30 seconds, and
/emails/lastcan wait up to 30 seconds for the email. Raise the test timeout, as the example does. - Every API call counts toward your plan's API requests: one read of an email is one request.
- Mail to these addresses is kept 1 day, which is enough for a test run. Create a permanent inbox in the dashboard when someone needs to look at the email later.
- The address must use your team ID; mail to an unknown team is not stored.
Questions
- Do I need a Playwright plugin?
- No. The test uses Playwright's built-in
requestfixture. Any HTTP client works. - Why is the test timeout raised to 90 seconds?
- The request to
/emails/lastcan wait up to 30 seconds for the email to arrive, and Playwright's default limit for a whole test is 30 seconds. - What if the confirmation link opens another domain?
page.gotofollows it like any URL. If your staging app sends production links, the test catches that, which is often the point.- Can I use the Node.js SDK instead of raw requests?
- Yes.
zyntramail-apihasgenerateEmail()andgetLastEmail(), which make the same calls. See the SDK docs.
Add the email step to your Playwright suite
Free plan, no setup: send to any address and read it back.
Start free