API reference
Disposable inboxes over HTTP
Create a throwaway email address, poll it, and read the verification code back already extracted from the message.
The Dev-Mail API is free and open. There is no registration, no API key and no paid tier. A single POST returns an address and a bearer token; every other call uses that token. Reads are idempotent, so an agent can poll the same inbox as often as it needs.
Quickstart
# 1. get an inbox (no auth needed)
curl -sX POST https://dev-mail.com/v1/inboxes
# {"address":"casey.vogel@diyapn.com","token":"3f9c...","expires_at":"...","ttl_seconds":...}
# 2. wait for the code and read it back
curl -s -H "Authorization: Bearer $TOKEN" \
"https://dev-mail.com/v1/inboxes/$ADDRESS/code?wait=60"
# {"found":true,"code":"309154","from":"Acme","subject":"Confirm your email",...}
That is the whole flow. Step 2 blocks until the code arrives, so you do not need a polling loop of your own.
Basics
| Base URL | https://dev-mail.com |
|---|---|
| Auth | Bearer token from POST /v1/inboxes. No signup, no API key. |
| Format | JSON in, JSON out. Standard HTTP status codes. |
| Rate limits | 60 requests per minute per IP; 20 new inboxes per hour per IP. Over the limit returns 429 with Retry-After. |
| Inbox lifetime | 6 hours of inactivity. Every read resets the clock. |
| Direction | Receive only. Dev-Mail cannot send email. |
| Attachments | Not stored. Message text and HTML only. |
| Domains | diyapn.com, winmail.cfd, mailcom.top, i-os.top, kingshould.com, nicepl.com, aeria-mall.com |
| Machine spec | openapi.json · llms.txt |
Endpoints
GET/v1/domains
List the domains that can receive mail. No auth.
curl -s https://dev-mail.com/v1/domains
{"domains":["diyapn.com", "..."],"count":7}
POST/v1/inboxes
Create a disposable inbox. No auth. Returns the address and the token you use for everything else.
| Body field | Type | Notes |
|---|---|---|
| domain | string | Optional. One of /v1/domains. Picked at random when omitted. |
| style | string | Optional. american, chinese or japanese — the naming style of the address prefix. Default american. |
curl -sX POST https://dev-mail.com/v1/inboxes \
-H "Content-Type: application/json" \
-d '{"domain":"diyapn.com","style":"american"}'
GET/v1/inboxes/{address}/messages
List every message delivered to the address. Safe to call in a loop: reading does not consume messages or mark them read.
| Query | Type | Notes |
|---|---|---|
| since | integer | Optional unix seconds. Returns only messages received after it — use the received_ts of the last message you saw. |
Each message carries id, from, from_address, to, subject, body (as delivered, usually HTML), body_text (flattened to plain text) and received_at / received_ts.
curl -s -H "Authorization: Bearer $TOKEN" \
"https://dev-mail.com/v1/inboxes/$ADDRESS/messages?since=1757000150"
GET/v1/inboxes/{address}/code
Pull the one-time code out of the newest message that has one. This is the endpoint most callers actually want: it saves you writing the extraction regex yourself.
| Query | Type | Notes |
|---|---|---|
| wait | integer | Optional. Seconds to long-poll while the code is in flight, 0 to 60. Default 0, which returns immediately. |
Returns found:false with empty fields when no code has arrived before the wait runs out. Codes are matched near words like verification, code, OTP and 验证码, in both the subject and the body; four-digit years are ignored.
curl -s -H "Authorization: Bearer $TOKEN" \
"https://dev-mail.com/v1/inboxes/$ADDRESS/code?wait=60"
Errors
Errors come back as {"error":{"code":"...","message":"..."}} with a matching HTTP status.
| Status | code | Means |
|---|---|---|
| 400 | unknown_domain | The domain is not in the pool. |
| 401 | missing_token | No Authorization header. |
| 401 | invalid_token | The token is not recognised. |
| 403 | not_your_inbox | The address exists but is held by a different token. Create a new inbox. |
| 404 | no_such_inbox | No such address. |
| 429 | rate_limited | Over the IP limit. Honour Retry-After. |
MCP server for AI agents
Dev-Mail speaks the Model Context Protocol at https://dev-mail.com/mcp over Streamable HTTP. It is stateless and needs no auth, so an assistant can complete a signup flow on its own: create an inbox, watch it, read the code back.
| Tool | Arguments | Returns |
|---|---|---|
| list_domains | — | The receiving domains. |
| create_inbox | domain, style | address + token. |
| list_messages | address, token, since | Every message in the inbox. |
| get_verification_code | address, token, wait | The extracted code. |
Because the server keeps no session, the token from create_inbox is passed back on each later call.
claude mcp add --transport http dev-mail https://dev-mail.com/mcp
Or in an MCP client config file:
{
"mcpServers": {
"dev-mail": {
"type": "http",
"url": "https://dev-mail.com/mcp"
}
}
}
A full signup, end to end
#!/usr/bin/env bash
set -euo pipefail
inbox=$(curl -sX POST https://dev-mail.com/v1/inboxes)
address=$(echo "$inbox" | jq -r .address)
token=$(echo "$inbox" | jq -r .token)
echo "signing up as $address"
# ... trigger the signup on the site under test, using $address ...
result=$(curl -s -H "Authorization: Bearer $token" \
"https://dev-mail.com/v1/inboxes/$address/code?wait=60")
if [ "$(echo "$result" | jq -r .found)" = "true" ]; then
echo "code: $(echo "$result" | jq -r .code)"
else
echo "no code arrived in 60s" >&2; exit 1
fi
Fair use
The API is open because asking for a key would defeat the point. In exchange: stay inside the rate limits, back off when you see a 429, and do not use Dev-Mail to create accounts in bulk or to evade a service's own terms. Inboxes are disposable — nothing here is durable storage, and mail is purged as addresses are recycled.