docs/examples
Examples
Copy-paste recipes for the three jobs TossInbox does: sign up with a throwaway address, collect the verification code, and toss the inbox. Every snippet uses the documented JSON contract — no screen scraping, no fragile parsing.
1 · Shell: sign up, get the code, verify
The whole loop as a paste-runnable bash block. Needs jq
(or swap in node -e parsing). Replace the two curl calls with
whatever your target app actually does.
# 1: create the inbox and grab its address as plain text ADDR=$(tossinbox spawn --json | jq -r .inbox.address) echo "inbox: $ADDR" # 2: use the address in the signup flow of the app under test curl -fsS https://staging.example-app.dev/api/signup \ -d "email=$ADDR" \ -d "password=correct-horse-battery" # 3: block until the verification email lands, print just the code CODE=$(tossinbox wait --code --timeout 180 --json | jq -r .code) echo "code: $CODE" # 4: complete the verification curl -fsS https://staging.example-app.dev/api/verify \ -d "email=$ADDR" \ -d "code=$CODE" # 5: done — delete the inbox on the server and locally tossinbox toss
Exit codes tell your script what happened: 2 = the email never
arrived before the timeout, 3 = nothing matched your filters. Treat non-zero as a test failure.
2 · GitHub Actions: e2e signup on every push
A workflow that signs up a fresh account on your staging API every push and verifies it — no shared test account, no mailbox quota, no state between runs.
name: e2e-signup on: [push] jobs: signup: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install TossInbox run: npm install --global tossinbox@0.1.6 - name: Spawn inbox id: inbox run: | echo "address=$(tossinbox spawn --json | jq -r .inbox.address)" >> "$GITHUB_OUTPUT" - name: Sign up on staging run: | curl -fsS https://staging.example-app.dev/api/signup \ -d "email=${{ steps.inbox.outputs.address }}" \ -d "password=correct-horse-battery" - name: Wait for the verification code id: code run: | echo "code=$(tossinbox wait --code --timeout 180 --json | jq -r .code)" >> "$GITHUB_OUTPUT" - name: Verify the account run: | curl -fsS https://staging.example-app.dev/api/verify \ -d "email=${{ steps.inbox.outputs.address }}" \ -d "code=${{ steps.code.outputs.code }}" - name: Toss the inbox if: always() run: tossinbox toss
There is also a packaged action (- uses: mohamed-khairy-5i/tossinbox@v1)
that spawns + waits in one composite step and exposes address / code outputs —
handy when nothing has to run between spawn and wait. Full setup on the
Agents page.
3 · Node.js: drive it from a script
Same contract, inside Node. spawnSync keeps it dependency-free;
the exit code is your error channel, --json is your data channel.
import { spawnSync } from "node:child_process"; const run = (args) => { const r = spawnSync("tossinbox", args, { encoding: "utf8" }); if (r.status !== 0) throw new Error(`tossinbox ${args.join(" ")} exited ${r.status}`); return JSON.parse(r.stdout); }; // 1: a fresh inbox for this run const { inbox } = run(["spawn", "--json"]); console.log("inbox:", inbox.address); // 2: your app under test does its signup with inbox.address here … // 3: block until the verification email lands const { code } = run(["wait", "--code", "--timeout", "180", "--json"]); console.log("code:", code); // 4: clean up no matter what happened run(["toss"]);
State lives in ~/.tossinbox/state.json (0600). Point it
somewhere temporary with TOSSINBOX_STATE=$(mktemp) to keep parallel runs isolated.
4 · MCP: hand the whole job to an agent
TossInbox ships a stdio MCP server. Point any MCP client at it and the agent can create inboxes, read messages, and wait for codes with tool calls.
{ "mcpServers": { "tossinbox": { "command": "npx", "args": ["-y", "tossinbox", "mcp"] } } }
Then just say it in natural language:
- “Create a disposable inbox, sign this test account up on staging, wait for the code, finish the verification, then delete the inbox.”
- The agent maps that to
create_inbox→ its own signup step →wait_for_code→tossinbox toss.
All four tools, plus client-by-client setup: the Agents & MCP page.
5 · When a provider is down, failover kicks in
Seven providers ship built in: mailtm (default),
mailgw (mail.tm-compatible API on independent infrastructure),
guerrillamail, tempmaillol, tempmailio,
tempmailplus and maildrop. If the one you asked for is down,
spawn retries the create against the others automatically and reports the switch — no config files, no retry scripts.
# mail.gw is down? the inbox still lands on a healthy provider tossinbox spawn -p mailgw # ⚠ mailgw: HTTP 502 from api.mail.gw — provider is down or having trouble… # ✔ Inbox ready : ab12cd34ef@uberip.com # provider : mailtm (failover from mailgw) # strict mode: fail instead of switching tossinbox spawn -p mailgw --no-failover # or pick a healthy provider yourself tossinbox providers tossinbox spawn -p guerrillamail
--json makes the switch machine-readable: a failover object (requested / used) plus a warnings array with one entry per failed attempt.
6 · Wait flags: filter by sender, subject, timing
wait polls until a message matches. Tighten the match so noise
from other mail never delays your run.
# only the sender you expect, only the subject you expect tossinbox wait --code \ --from noreply@example-app.dev \ --subject verification \ --timeout 120 \ --interval 3
Codes with letters come back uppercased (f4x9k2 → F4X9K2);
extraction understands prompts in twelve languages — English and Arabic (رمز / كود / تفعيل / تحقق),
plus French, Spanish, German, Portuguese, Italian, Russian, Turkish, Chinese, Japanese, and Korean.
Flag reference on the
CLI page.
7 · Watch: stream codes the moment they land
Long-lived automation should not exit after the first message. watch
keeps polling, prints every new message (and its code when found), and stops on Ctrl-C. Only new
arrivals are reported — restarting a watch never replays old mail.
# watch until the code from your app lands, then keep going tossinbox watch --from noreply@example-app.dev # agents: one compact JSON object per line on stdout, stderr stays silent tossinbox watch --json
8 · Attachments: pull the files to disk
Messages can carry attachments. read --save downloads all of
them plus the HTML/plain-text bodies into <dir>/<message-id>/
(default dir: ./tossinbox-attachments).
tossinbox spawn # inbox that will receive the email # ... the email with the attachment arrives ... tossinbox list # find the message id tossinbox read 42 --save # ./tossinbox-attachments/42/{body.html, body.txt, report.pdf, …} tossinbox read 42 --html # print the raw HTML body instead of the plain text
Agents: with --json, read --save returns a
saved array with the exact path of every file it wrote — parse it and read the
files directly, no path guessing. Full attachment support on mailtm,
mailgw and tempmailplus; tempmailio when its upstream
exposes the files; the other providers have no attachments upstream.