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.

bash: signup + otp end to end
# 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.

.github/workflows/e2e-signup.yml
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.1

      - 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.

signup-flow.mjs
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.

mcp client config (claude desktop / cursor / any MCP client)
{
  "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_codetossinbox toss.

All four tools, plus client-by-client setup: the Agents & MCP page.

5 · Second provider when the first is flaky

Two providers ship built in: mailtm (default) and guerrillamail. When one is having a bad day, switch with a flag — no config files.

shell: provider failover by hand
# what is available?
tossinbox providers

# default provider is down / slow? spawn on the other one
tossinbox spawn -p guerrillamail

Automatic failover is on the roadmap.

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.

shell: filtered wait
# 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 (f4x9k2F4X9K2); extraction understands English and Arabic prompts (رمز / كود / تفعيل / تحقق). Flag reference on the CLI page.