Skip to content

CI Email Testing

Test email delivery in CI pipelines using ephemeral receivers.

Use Bounce House receivers to verify real email delivery in your CI pipeline — no mock SMTP servers, no shared inboxes, no flaky polling loops.

The problem

Testing email flows in CI is hard:

  • Local SMTP catchers (Mailpit) can't receive real email from production providers
  • Shared test inboxes create race conditions between parallel test runs
  • Polling for email with retries is slow and flaky

The solution

Create an ephemeral receiver per test run, send to it, and wait:

import { describe, it, expect } from "vitest";

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

describe("signup flow", () => {
  it("sends a verification email", async () => {
    // 1. Create a receiver
    const receiver = await fetch(`${API}/api/accounts/me/receivers`, {
      method: "POST",
      headers,
      body: JSON.stringify({
        channel: "email",
        label: "signup-test",
        ttl_seconds: 3600,
      }),
    }).then((r) => r.json());

    // 2. Trigger signup with the receiver's email address
    await signupUser({ email: receiver.address });

    // 3. Wait for the verification email (blocks, no polling)
    const message = await fetch(`${API}/api/accounts/me/receivers/${receiver.id}/wait?timeout=30`, {
      headers,
    }).then((r) => r.json());

    // 4. Assert
    expect(message.subject).toContain("Verify your email");
    expect(message.extracted.links).toHaveLength(1);

    // 5. Clean up
    await fetch(`${API}/api/accounts/me/receivers/${receiver.id}`, {
      method: "DELETE",
      headers,
    });
  });
});

Key benefits

  • Isolation — each test run gets its own email address, no cross-contamination
  • No polling — the wait endpoint blocks until a message arrives or the timeout expires
  • Real delivery — tests actual email sending through your production provider
  • Content extraction — OTPs, verification links, and structured content are extracted automatically

Was this page helpful?