Some tests need a real email to arrive: the code a sign-up sends, a magic link, a password reset. Agents hit the same wall when they sign up for something on your behalf. tempboi.email gives you an address that exists for as long as you need it, with no sign-up and no token of Postboi’s. Everything it receives is readable over plain HTTP, and it goes away on its own.
With curl
Make an inbox:
Send something to that address, then wait for it. The request holds until a match
arrives (up to 60 seconds by default, 90 at most) and answers with the message as JSON,
including the one-time code and the verify link already pulled out of it:
A 408 means nothing matched in time. Add Accept: application/json to the first request
to get the inbox as JSON instead of text, and curl tempboi.email prints a usage card.
The whole API is described at tempboi.email/llms.txt.
From the CLI
postboi inbox does the same from the terminal, remembers the token for you, and needs
no POSTBOI_TOKEN:
wait exits 0 when a mail arrives, 2 on timeout, and 3 when --code or --link asked
for something the mail doesn’t have, so a script can branch on it. --new ignores mail
that was already there, and a filter written as /…/ is a regular expression.
In CI, make the inbox in one step and hand it to the next through the environment:
watch --forward http://localhost:5173/webhooks/postboi posts every mail to your own app
in the shape of Postboi’s email.received webhook, signed with POSTBOI_WEBHOOK_SECRET when it’s set. That tests an inbound handler locally with no
tunnel. watch --exec runs a command per mail instead, with SUBJECT, FROM, CODE, LINK and friends in its environment. Every command is in the CLI reference.
In a test
postboi/inbox is the same thing as one function. It only uses fetch, so it runs in
Node, Bun, Deno and Workers. Here it is in a Playwright test:
await using deletes the inbox when the test ends. Without it, call inbox.delete() yourself, or leave it to expire.
inbox.wait()returns the newest mail that matches, including one that arrived before you started waiting, since “sign up, then wait” is the usual order. Passafter: inbox.cursorto insist on new mail.fromandsubjecttake a substring or a RegExp;tagis exact. A timeout rejects withInboxTimeoutError.- Each mail has
codeandcodes,linkandlinks,from,name,subject,text,html,headers,auth(SPF, DKIM, DMARC),attachmentsandreceivedas aDate.await mail.raw()is the.emlas bytes. The HTML is as received, so render it sandboxed. - Plus-tags land in the same inbox:
inbox.tag('run-42')givesquiet-otter-k3f9+run-42@tempboi.email, andwait({ tag: 'run-42' })picks that one out. Parallel tests can share one inbox this way. for await (const mail of inbox.watch())yields every new mail until you break out or abort itssignal.inbox.list(),inbox.extend('2h')andinbox.delete()do what they say.temp.attach()picks up an inbox made elsewhere, fromPOSTBOI_INBOX_TOKENby default, which is how a test reads the inbox a CI step made. The token alone is enough: it finds its own inbox, andPOSTBOI_INBOXonly has to be set if you want the address checked too. The same goes for the CLI, so the command tempboi.email’s page gives you,POSTBOI_INBOX_TOKEN=tb_… npx tempboi watch, watches the inbox you were looking at.
Limits
An inbox lives an hour unless you say otherwise, and 24 hours at most. It holds 100 messages, and a message can be up to 10 MB; mail past either limit is refused when it arrives. Reading an inbox always needs its token, which is only handed out when the inbox is made. Anyone can send to an address they know, and anyone holding the token can read it, so keep the token out of logs you share.
On your own domain
With a Postboi account you can make the same kind of inbox on your own receiving domain
(reply.<your domain>), for mail that has to come from an address you own or tests that
shouldn’t depend on a public host. Name the domain; the API key is your POSTBOI_TOKEN,
found wherever mail() finds it (the environment, a Worker’s bindings, .env in dev). You
read the inbox with its token exactly as before, and it can live up to 7 days.
Pass key only to use a different API key from the one your project sends with.
Abuse
tempboi.email is for testing and automation. Report abuse to abuse@postboi.app.