Z ZMAILDROP
--:--:--
REST · JSON · FREE · NO AUTH

ZMAIL Drop Public API

Query temporary inboxes, read messages, and delete them from your apps, bots, or scripts. No signup, no API key, no cost. Rate limited to 30 requests / minute per IP with a 5-minute blacklist on excess.

4Endpoints
30/minRate limit
3sCache TTL
$0Forever
Total API Requests
—
Tap the Refresh button to load current stats
Last Hit
—
Africa/Lagos · only updates when you tap Refresh
01 / QUICK START

One curl. That's it.

Hit any endpoint directly from your terminal. No setup, no key.

# List every message in mailbox "any-name" curl -s "https://zmaildrop.vercel.app/api/v1/inbox?mailbox=any-name" | jq
Tip: pipe through | jq for pretty output. Every response is valid JSON.
02 / OVERVIEW

How the API works.

ZMAIL Drop is a thin, cached proxy over public @maildrop.cc inboxes. Every request is rate limited, throttled, and cached to protect the upstream server — but from your side, it's just clean JSON over HTTPS 💡.

Base URL: https://zmaildrop.vercel.app/api/v1 Auth: none Format: JSON (application/json) Methods: GET, DELETE, OPTIONS CORS: allowed from any origin
03 / ENVELOPE

Every response shares the same shape.

All responses are JSON objects with a top-level ok boolean. Success responses include data and meta. Errors include error and meta.

{ "ok": true, "data": { /* the actual payload */ }, "meta": { "request_id": "req_b41o301d", "timestamp": "2026-09-22T16:25:10.193Z", "rate": { "limit": 30, "remaining": 29, "reset_in_seconds": 59 } } }
{ "ok": false, "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded.", "hint": "You've hit 30 requests in 60 seconds. Wait a moment.", "retry_after_seconds": 43, "docs": "https://zmaildrop.vercel.app/developers.html#errors" }, "meta": { "request_id": "req_xyz12345", "timestamp": "2026-09-22T16:25:10.193Z" } }
04 / ENDPOINTS

Everything the API does.

GET /api/v1/health

Status check. Confirms the service is online, whether Firebase is connected, returns current Lagos time, lifetime request count, and links to every available endpoint.

curl -s "https://zmaildrop.vercel.app/api/v1/health" | jq
Response 200 OK
{ "ok": true, "data": { "service": "ZMAIL Drop API", "version": "v1", "status": "online", "firebase": "connected", "timezone": { "name": "Africa/Lagos", "offset": "UTC+1", "now": "Tuesday, 22 September 2026 at 17:25:09 WAT" }, "time": { "iso_utc": "2026-09-22T16:25:09.948Z", "unix_ms": 1790094309948 }, "stats": { "total_requests": 40, "last_hit_at": "2026-09-22T16:25:08.743Z" }, "endpoints": { "inbox": "/api/v1/inbox?mailbox=:name", "message": "/api/v1/message?mailbox=:name&id=:id", "docs": "https://zmaildrop.vercel.app/developers.html" } }, "meta": { "request_id": "req_b41o301d", "timestamp": "2026-09-22T16:25:10.193Z", "docs": "https://zmaildrop.vercel.app/developers.html" } }
200 Success 405 Method Not Allowed
GET /api/v1/inbox?mailbox=:name

Lists all messages in a mailbox. Results are cached for 3 seconds to protect the upstream. Second calls within the window return instantly from cache.

curl -s "https://zmaildrop.vercel.app/api/v1/inbox?mailbox=any-name" | jq
Response 200 OK · cache MISS
{ "ok": true, "data": { "mailbox": "any-name", "address": "any-name@maildrop.cc", "count": 7, "messages": [ { "id": "pH6k1fyokk", "headerfrom": "Tactical <support@tacticalusa.com>", "subject": "You free box of Magtech .45 ACP", "date": "2026-09-22T13:50:33.657Z" }, { "id": "aWTBrqSY8v", "headerfrom": "\"Pixlr\" <no-reply@pixlr.com>", "subject": "What if your photos looked like this? 🎨✨", "date": "2026-09-22T10:02:29.474Z" } ] }, "meta": { "request_id": "req_opirqilb", "timestamp": "2026-09-22T16:25:25.378Z", "cached": false, "duration_ms": 1274, "rate": { "limit": 30, "remaining": 29, "reset_at": "2026-09-22T16:26:24.104Z", "reset_in_seconds": 59 } } }
Response 200 OK · cache HIT
{ "ok": true, "data": { /* identical payload */ }, "meta": { "cached": true, "duration_ms": 143, "rate": { "limit": 30, "remaining": 28, "reset_in_seconds": 35 } } }
200 Success 400 Invalid / Missing mailbox 429 Rate limited 502 Upstream error 503 Upstream busy
GET /api/v1/message?mailbox=:name&id=:id

Reads a single message by ID. Returns the sanitized HTML body, the raw MIME source, a pre-built cid_map for inline images, and a has_attachments flag.

curl -s "https://zmaildrop.vercel.app/api/v1/message?mailbox=any-name&id=pH6k1fyokk" | jq
Response 200 OK
{ "ok": true, "data": { "mailbox": "any-name", "address": "any-name@maildrop.cc", "message": { "id": "pH6k1fyokk", "from": "Tactical <support@tacticalusa.com>", "subject": "You free box of Magtech .45 ACP", "date": "2026-09-22T13:50:33.657Z", "html": " <!DOCTYPE html>...", "raw": "Received: from mta2.tacticalusa.com...", "has_attachments": false, "cid_map": {} } }, "meta": { "request_id": "req_40al6cjj", "timestamp": "2026-09-22T16:27:11.936Z", "cached": false, "duration_ms": 1409, "rate": { "limit": 30, "remaining": 29, "reset_in_seconds": 59 } } }
Response 200 OK · with attachment
{ "ok": true, "data": { "mailbox": "any-name", "address": "any-name@maildrop.cc", "message": { "id": "XDM5OW4eUC", "from": "Isaac Achor <achorisaac827@gmail.com>", "subject": "With a file", "date": "2026-09-22T07:29:22.900Z", "html": "<div dir=\"auto\">Bruuuh</div>", "raw": "Received: by mail-oi2-f12.google.com...", "has_attachments": true, "cid_map": { "ii_1a0c7fdf13420c233d01": "data:image/jpeg;base64,/9j/4AAQ..." } } }, "meta": { /* ... */ } }
200 Success 400 Invalid params 404 Message not found 429 Rate limited 502 / 503 Upstream
DELETE /api/v1/message?mailbox=:name&id=:id

Permanently removes a message from the mailbox. Invalidates any cached views of that mailbox and message. Deletion is final — ZMail Drop has no trash recovery policy or endpoint.

curl -s -X DELETE "https://zmaildrop.vercel.app/api/v1/message?mailbox=any-name&id=pH6k1fyokk" | jq
Response 200 OK
{ "ok": true, "data": { "mailbox": "1", "id": "pH6k1fyokk", "deleted": true, "result": true }, "meta": { "request_id": "req_da7mkyzw", "timestamp": "2026-09-22T16:33:55.791Z", "duration_ms": 707, "rate": { "limit": 30, "remaining": 29, "reset_in_seconds": 60 } } }
Heads up: ZMail Drop list index can lag a few seconds behind a delete. A subsequent inbox call may still show the deleted message for a moment — that's upstream behavior, not a bug.
200 Success 400 Invalid params 405 Wrong method 429 Rate limited 502 / 503 Upstream
05 / DATA MODELS

What's inside a message.

Message (list item)

Lightweight object returned by /inbox.

idstring
headerfromstring
subjectstring
dateISO 8601

Message (full)

Detailed object returned by /message.

idstring
fromstring
subjectstring
dateISO 8601
htmlstring | null
rawstring | null
has_attachmentsboolean
cid_mapobject
06 / CLIENT EXAMPLES

Copy. Paste. Ship.

// Fetch and print every message in a mailbox const res = await fetch("https://zmaildrop.vercel.app/api/v1/inbox?mailbox=any-name"); const json = await res.json(); if (!json.ok) throw new Error(json.error.message); for (const msg of json.data.messages) { console.log(`${msg.subject} — ${msg.headerfrom}`); }
import requests r = requests.get("https://zmaildrop.vercel.app/api/v1/inbox?mailbox=any-name") data = r.json() if data["ok"]: for msg in data["data"]["messages"]: print(msg["subject"], "-", msg["headerfrom"])
# List inbox curl -s "https://zmaildrop.vercel.app/api/v1/inbox?mailbox=any-name" | jq # Read one message curl -s "https://zmaildrop.vercel.app/api/v1/message?mailbox=any-name&id=abc123" | jq # Delete one message curl -s -X DELETE "https://zmaildrop.vercel.app/api/v1/message?mailbox=any-name&id=abc123" | jq
const axios = require("axios"); const { data } = await axios.get( "https://zmaildrop.vercel.app/api/v1/inbox", { params: { mailbox: "any-name" } } ); if (data.ok) { data.data.messages.forEach(m => console.log(m.subject)); }
07 / LIMITS & HEADERS

Fair use, clearly stated.

Every response carries standard rate-limit headers. Your client should back off automatically when it sees a 429.

X-RateLimit-Limit: 30 X-RateLimit-Remaining: 14 X-RateLimit-Reset: 1758550830 # unix seconds Retry-After: 43 # only present on 429
Policy: 30 requests / minute / IP. Exceeding this blacklists your IP for 5 minutes. The window is sliding — it resets naturally 60 seconds after your first request.
08 / ERROR CODES

What can go wrong.

Code Status Meaning
MISSING_MAILBOX400The mailbox query parameter was omitted.
MISSING_ID400The id query parameter was omitted.
INVALID_MAILBOX400Mailbox name failed validation (a-z0-9._-, max 64 chars).
INVALID_ID400Message ID failed validation.
MESSAGE_NOT_FOUND404Message doesn't exist, or it expired.
METHOD_NOT_ALLOWED405Wrong HTTP verb for this endpoint.
RATE_LIMITED429You've hit 30 requests in 60 seconds.
IP_BLACKLISTED429Your IP is temporarily blocked for 5 minutes.
UPSTREAM_BUSY503Server queued too many concurrent upstream calls.
UPSTREAM_ERROR502ZMail Drop Server itself returned an error.
CLEANUP_FAILED500Only on /cleanup. Firestore write failure.
UNAUTHORIZED401Only on /cleanup. Missing or invalid CRON_SECRET.
09 / HTTP STATUS CODES

Quick reference.

400 Bad request — invalid or missing params 404 Not found — message doesn't exist 405 Method not allowed — wrong HTTP verb 429 Too many requests — rate limit or blacklist 500 Internal server error — cleanup failed 502 Bad gateway — Zmail Drop Server failed 503 Service unavailable — upstream busy
READY TO BUILD?

Grab a mailbox. Hit the API.

Open any mailbox name on the main site, then use it with the API. All inboxes are public and free forever.