Quickstart
From nothing to a message read back over HTTP, in four commands. No account, no key, no SDK.
1. Pick an address
Any name, on any of our public domains. There is nothing to call and nothing to register — the address becomes real the moment something is delivered to it.
Keep it unguessable if you would rather nobody wandered in: on a public domain the address is the only thing standing between the mailbox and the world.
$ ADDR="ci-$(openssl rand -hex 4)@grabmail.io"; echo "$ADDR"2. Send it something
Use it in the signup form, the password-reset flow or whatever you are testing. Delivery is normally a couple of seconds.
Our mail servers accept messages up to 5 MB. Anything larger is refused at SMTP time, so the sender is told immediately rather than left wondering.
$ curl -sX POST https://your-app.example/signup --data-urlencode "email=$ADDR"3. Poll the mailbox
One request per second is the intended rhythm and is never throttled. An empty mailbox answers 200 with count: 0 — never a 404, so your loop does not need to special-case it.
This snippet gives up after a minute rather than spinning forever, which is what you want in CI.
$ for i in $(seq 60); do
ID=$(curl -sG https://grabmail.io/api/v1/mailbox --data-urlencode "address=$ADDR" | jq -r '.messages[0].id // empty')
[ -n "$ID" ] && break
sleep 1
done; echo "$ID"4. Read it, then throw it away
Fetch the message and pull out whatever you came for — here, a six-digit code from the plain-text part.
Deleting is optional: everything goes on its own after 5 days. Do it anyway in CI, and the next run starts from a clean mailbox.
$ curl -sG https://grabmail.io/api/v1/message/$ID --data-urlencode "mailbox=$ADDR" \
| jq -r .text | grep -oE '[0-9]{6}'
curl -sX DELETE -G https://grabmail.io/api/v1/message/$ID --data-urlencode "mailbox=$ADDR"Wiring it into CI
Two habits keep a suite that reads real mail from becoming flaky:
- A fresh address per run
- Derive it from the build id or a random suffix. Reusing one address across runs means yesterday’s message can satisfy today’s assertion.
- A deadline, not a retry count
- Poll against a wall-clock timeout as above. Retry counts silently become longer as your sender gets slower.
- Never assert on delivery time
- Mail is not synchronous. Assert that the message arrives, not that it arrives within a specific second.
- Use your own domain for anything real
- A public mailbox is readable by anyone who guesses the address. That is fine for a throwaway signup, and not fine for a staging environment with customer data. One MX record fixes it.
Next
API reference
Every parameter, every status code, the error shape.
Limits
What is capped, what is not, and what happens at the ceiling.
Your own domain
Make every mailbox on your domain private to you.