Skip to content
NewA free test that shows whether your emails will reach the inbox.

Test your app's emails without parsing a single email

Use a fresh address in every test. Wait for the email, then read the code or link it contains.

What it does

Three things you get, in plain words.

  • A new address for every test

    Any address on your private mailbay.email domain reaches your catch-all inbox. Make one up in the test. There is nothing to set up first.

  • Waits for the email

    One call waits until the next matching email arrives. You can match on the sender, the subject or the exact address it was sent to.

  • Hands you the code or link

    The one-time codes and links in the email come back ready to use. Each message also shows its sender checks (SPF, DKIM and DMARC), a spam score and its attachments.

Wait for the email, then use what is in it

Your test fills in a new address, waits, and gets the code back. Choose a fresh inbox per test, or use the catch-all and invent addresses.

import { expect, test } from "@playwright/test";

const API = "https://api.mailbay.dev";
const headers = {
  Authorization: `Bearer ${process.env.MAILBAY_API_KEY}`,
  "Content-Type": "application/json",
};

test("sign up with an emailed code", async ({ page }) => {
  // A fresh inbox just for this test
  const inbox = await (
    await fetch(`${API}/v1/inboxes`, {
      method: "POST",
      headers,
      body: JSON.stringify({ local_part: `signup-${Date.now()}` }),
    })
  ).json();

  await page.goto("/signup");
  await page.getByLabel("Email").fill(inbox.address);
  await page.getByRole("button", { name: "Send code" }).click();

  // Wait for the email. The code is already pulled out for you.
  const res = await fetch(`${API}/v1/inboxes/${inbox.id}/wait?timeout=60`, { headers });
  const { codes } = await res.json();
  await page.getByLabel("Code").fill(codes[0]);
  await page.getByRole("button", { name: "Continue" }).click();
  await expect(page.getByRole("heading", { name: "Welcome" })).toBeVisible();

  // Clean up
  await fetch(`${API}/v1/inboxes/${inbox.id}`, { method: "DELETE", headers });
});

It works the same from Cypress, Jest, Vitest or any tool that can make an HTTP request. If a wait finds nothing in time, it answers wait_timeout. Calling it again is safe.

Limits, honestly

What it does not do, so you can decide before you start.

  • A wait lasts at most 120 seconds. If your app is slower, call it again.
  • Sukhovei Mail tests email only. There is no SMS or phone number testing.
  • There is no recorder or browser extension. You write the test in your own tool.
  • The simulated outcomes (delivered, bounced, complained) test your sending side only. They do not send real mail and are not added to your suppression list.
  • Mail is kept until you delete it, unless you set a retention period. Received mail does not count against your sending allowance.
  • The free plan includes 3 named inboxes. Catch-all inboxes do not count toward that.

Questions

How do I test a sign-up email?

Sign up in your test with a new address on your mailbay.email domain. Then call the wait endpoint for that address. It returns the email with any one-time code or link already extracted, so you do not need to read the HTML.

Do I need to create an inbox for each test?

No. Any address on your private domain reaches your catch-all inbox, so a test can invent one. If you prefer, create a named inbox per test with POST /v1/inboxes and delete it afterwards.

Can I test bounces and spam complaints?

Yes, for emails you send through Sukhovei Mail. Send to delivered@, bounced@ or complained@ on test.mailbay.dev. Sukhovei Mail records that outcome without sending real mail, and does not add the address to your suppression list.

Does it work with Playwright and Cypress?

Yes. It is a plain HTTP API, so it works from Playwright, Cypress, Jest, Vitest or any script. There is a Playwright example on this page.

Can I test SMS or phone codes?

No. Sukhovei Mail tests email only.

Try it on the free plan.

The free plan has 3 inboxes, 3,000 emails a month and 3 custom domains. No card needed.