Postbox docs

Test mode

A sandbox project where mail loops back into its own inbox. Nothing leaves, nothing is billed, reputation is untouched.

Test mode is the email equivalent of Stripe's test mode. A test project loops every send back into its own inbox instead of delivering over the internet. It's for integration testing (your API calls, webhooks, threading, and bounce handling) with an ironclad guarantee that nothing real ever happens.

What's guaranteed

No mail leaves the platform. No SES send. No sending reputation impact. No plan usage or billing. A test project can never send a real email.

Create a test project

In the dashboard, click New test project on the Projects page. It spins up instantly with a ready-to-use loopback domain (<slug>.test.postboxapp.cloud) and an inbox mailbox, with no DNS and no domain verification.

Its API keys are minted with a pb_test_ prefix. A pb_test_ key resolves to the test project and can only ever drive loopback, so it's safe to hand around.

import { Postbox } from "@postbox/sdk";

const pb = new Postbox({ apiKey: process.env.PB_TEST_KEY! }); // pb_test_…

Send and receive

A send from a test project lands in the recipient's test inbox and fires the same message.received webhook + SSE event as real inbound mail, so your inbound integration is exercised for real.

await pb.messages.send({
  from: "[email protected]",
  to: [{ address: "[email protected]" }],
  subject: "Loopback",
  bodyHtml: "<p>This never leaves Postbox.</p>",
});
// → appears in the test inbox; fires message.received to your webhook

Open the inbox mailbox in the dashboard to read what you sent, exactly as it renders for real inbound mail.

Magic addresses

Like test cards for payments, magic recipients force deterministic outcomes so you can test your webhook handlers without waiting for a real bounce:

Recipient local-partFires
bounce@…message.bounced (hard)
complaint@…message.complained
defer@…message.deferred
anything elseloops back → message.received
// Test your bounce handler deterministically:
await pb.messages.send({
  from: "[email protected]",
  to: [{ address: "[email protected]" }],
  subject: "Trigger a bounce",
});
// → message.bounced webhook, tagged test: true

Every synthesized event carries test: true so it never touches your deliverability analytics.

Your own domain in test mode

You can add your own domain to a test project. It verifies instantly (no DNS needed) so you can rehearse the whole add-domain → verify → send onboarding flow. It's cosmetic: mail from it still loops back.

Limits

Each org can have one test project. A single sandbox is all you need to exercise an integration, and it isn't meant to hold data.

Test mode is free and unmetered, but a per-project hourly cap keeps loopback from being flooded (loopback sends per rolling hour). It defaults to a generous platform value; set your own under Settings → Test mode, or leave it empty to inherit the default.

When you're ready for real delivery, use a live project with a verified domain.