Use case · Email testing
Signup confirmations, OTPs and magic links land in a mailbox your test runner can actually script. One real address per CI run, a transformer that extracts the code, and a webhook push or a GET /v1/emails poll to hand it to the assertion.
the whole flow · playwright
// signup.spec.ts · Playwright
const alias = `ci-run-${process.env.CI_RUN_ID}@yournick.hidemy.world`;
await page.goto("/signup");
await page.fill("#email", alias);
await page.click("text=Create account");
// poll until the OTP mail lands · GET /v1/emails (every plan)
let otp: string | undefined;
await expect(async () => {
const res = await request.get(
`https://api.hidemy.world/v1/emails?q=${alias}`,
{ headers: { Authorization: `Bearer ${process.env.HIDEMY_API_KEY}` } }
);
otp = (await res.json()).items[0]?.transformed?.fields?.otp;
expect(otp).toBeDefined();
}).toPass({ timeout: 30_000 });
await page.fill("#otp", otp!);
await page.click("text=Confirm");The problem
# testing email today
# with hidemy.world
Built for suites
[address]
Name addresses after the CI run: ci-run-83@yournick.hidemy.world is real the moment mail hits it. No DNS, no provisioning step, nothing to tear down.
[extract]
A transformer pulls the OTP or the confirm URL into transformed.fields. Your test asserts a string; it never parses HTML soup for a 6-digit code.
[webhook]
A pipeline POSTs the extracted fields to your runner or a small capture endpoint: HMAC-signed, retried with backoff, replayable from the delivery log.
[rest]
GET /v1/emails filters by address and returns the extracted fields. One polling loop with a timeout covers every flow, and the API is included on every plan.
[eml]
Upload a real .eml of your signup mail and run it through the transformer. Iterate on the extraction in seconds, without sending a single email.
[auth]
Every email carries its authentication results. Assert that DKIM passes in a smoke test and catch a broken DNS record before your customers do.
[parallel]
Each job writes to its own address, and inbound mail is deduped by Message-ID. Shard the suite as wide as you like; shared-mailbox races are gone.
[cleanup]
Pause or delete an address any time. Retention runs 7 to 365 days by plan, so yesterday's run is still there when you dig into a flake.
How it works
ci-run-${BUILD_ID}@yournick.hidemy.world. The address is live the moment your app's signup mail hits it: no DNS, no per-run setup, no teardown.
Extract { otp, confirm_url } from the body. Tune it against an uploaded .eml of your real signup email until the fields come out right.
Point a webhook at your runner, or poll GET /v1/emails with a timeout. Assert the OTP, click the link, move on to the next spec.
No testimonials, just configs
Plans
Prove the flow first: Free
2 addresses, 100 emails a month, webhooks and signatures included. No card. Enough to get one spec green against your real signup flow this afternoon.
The CI tier: Pro
€24.90/mo: 5,000 emails a month for busy pipelines, 1,000 AI evaluations, 5 team members and up to 365-day retention. Room for every branch build.
Webhook-only suite? Lite (€9.90/mo) has unlimited addresses and 1,000 emails a month. Compare all plans
FAQ
Two ways. Push: a pipeline webhook POSTs the extracted fields to your runner or a small capture endpoint, HMAC-signed and retried with backoff. Pull: the runner polls GET /v1/emails filtered to the run's address and reads transformed.fields.otp from the response. Polling is the usual starting point because it needs no inbound endpoint in CI, and the REST API is included on every plan.
No. An address at your subdomain exists the moment mail hits it, so ci-run-83@yournick.hidemy.world works without a provisioning step. Set up the extraction transformer and the webhook once, and every run's mail flows through the same pipeline under its own address.
Upload a .eml of your real signup email and run it through the transformer until { otp, confirm_url } come out right. Nothing is sent anywhere while you iterate. Once the fields look correct, the same transformer runs on live mail from your staging environment.
No. Each job uses its own address, so there is no shared mailbox to race on, and inbound mail is deduped by Message-ID, so a sender's retry can't double-fire your webhook. The practical ceiling is the plan quota: 5,000 emails a month on Pro. If you hit the API's fair-use limit you get a 429 with Retry-After, not a silent drop.
Yes. SPF, DKIM and DMARC are evaluated on receipt and included with every email, in the webhook payload and over the API. Add one smoke test that sends from staging and asserts all three pass, and a broken DNS record fails CI instead of production deliverability.
Create an address, point your staging signup at it, and assert your first OTP before the next standup. Free to prototype, no card.