For CI runners and coding agents

Disposable email addresses via HTTP

Disposable, throw away email addresses, register and access inbox via HTTP. Let your agent or test runner register an address, have your system send mail to it, and poll for the message. Without the hassle of setting up permanent accounts or using SMTP. No inbound network access required.

  • Auth 1 bearer token
  • Surface HTTP endpoints
  • Retention up to 24 h
  • Long poll up to 30 s
ci-job.sh 200 OK
ADDRESS="run-$(openssl rand -hex 8)@fabricatedemail.com"
# 1. Register the address, and print the answer
ANSWER=$(curl -sS -X POST https://api.fabricatedemail.com/subscriptions \
  -H "Authorization: Bearer $FABRICATEDEMAIL_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"address\":\"$ADDRESS\",\"ttlSeconds\":3600}")
echo "$ANSWER"
SID=$(echo "$ANSWER" | sed -n 's/.*"id":"\([^"]*\)".*/\1/p')

# 2. Have your system send mail to $ADDRESS, then wait for it.
#    The request holds open for up to 30 seconds.
curl -sS "https://api.fabricatedemail.com/subscriptions/$SID/messages?wait=30" \
  -H "Authorization: Bearer $FABRICATEDEMAIL_KEY"

# 3. Delete the address. A live address counts against your account's cap.
curl -sS -X DELETE "https://api.fabricatedemail.com/subscriptions/$SID" \
  -H "Authorization: Bearer $FABRICATEDEMAIL_KEY"
response one message, about a second after delivery
{"messages": [{
  "id": 1,
  "messageId": "<8f14e45f@acme.test>",
  "from": "noreply@acme.test",
  "to": "run-8f2c1d94a7b30e56@fabricatedemail.com",
  "subject": "Confirm your email",
  "text": "Your verification code is 482913…",
  "html": "<p>Your verification code is…",
  "headers": [["authentication-results", "spf=pass; dkim=pass…"], …],
  "attachments": [],
  "truncated": false,
  "rawSize": 4096,
  "receivedAt": "2026-08-10T12:00:01.000Z"
}]}

Pipeline

How it works

From your CI job to a JSON message in about a second. Nothing on your side has to be reachable from the internet.

Register · receive · read one request per step
A CI job registers an address, mail arrives at the mail edge, and a long poll returns the message. ci job · run-8f2c1d94a7b30e56 · wait=30 LONG POLL Your CI job or coding agent POST /subscriptions ttlSeconds: 3600 address: "run-8f2c…@…" system under test sends the signup mail GET …/messages?wait=30 HTTPS The mail edge @fabricatedemail.com SPF / DKIM / DMARC checked INBOUND SMTP Cloudflare Email Routing parsed and stored text + html up to 24 h ~1 s Your assertion exit code: 0 // GET …/{id}/extract expect(codes[0]) .toBe("482913") links: 1 https://…/verify?t=8f14e one request

Scroll the diagram sideways to follow the whole pipeline.

Authenticated senders only No inbound tunnel JSON over HTTPS
  1. Register an address over HTTP

    One POST with a random local part. The address is live as soon as you receive the response.

  2. Mail arrives at the edge

    Your system sends to the address. SPF, DKIM and DMARC are checked at the mail edge before our service runs; what passes is parsed into text, HTML and headers and kept until the address expires, 24 hours at most, then deleted by an hourly cleanup.

  3. One long poll returns the message

    Your system holds a GET open with ?wait=30. The moment the message is stored the response completes with a JSON payload. Extract what you need from the payload and assert.

What you get

Built for pipelines

One key, and the same limits whether a script or a coding agent is calling.

API only

HTTP endpoints, access with bearer token, JSON in and out. A long poll returns the moment mail lands.

GET …/messages?wait=30 200

Extracted codes and URLs

If your email contains one-time codes or URLs, those are extracted and reachable via API. How it works, so you can skip those regular expressions and parsers.

GET …/{id}/extract "codes": ["482913"]
MCP

Agentic first

MCP Server for your coding agents to make the most out of the API. Connect one.

POST /mcp · HTTP transport

Mail kept up to 24 hours

Until the address expires, 24 hours at most, then deleted by an hourly cleanup. On every tier.

min(receivedAt + 24 h, expiresAt)

Stability as a service

Our service runs on Cloudflare's global network, which powers roughly 20% of the web. We design our APIs with stability in mind; anything that would break a working client gets a new path prefix and six months of overlap. The policy.

six months of overlap

Your test mail has to be authenticated

Mail is checked at the mail edge before our service sees it. Mail that fails both SPF and DKIM, fails its domain's DMARC policy, or comes from a blocklisted server is rejected there, so nothing shows up in the API. This is a security precaution and protects us from misuse. If you send from Azure ACS, Amazon SES, SendGrid, Postmark or your own server with the records in DNS, your mail passes the authentication checks.

Why mail might not arrive →

Agents

Built for agents and agentic testing

Your coding agent gets an MCP server: the same operations, on the same key and the same limits as your CI job. Claude Code, Codex, GitHub Copilot and any other client that speaks MCP over HTTP.

  • The agent can run the whole loop

    It registers an address, drives your signup, waits for the mail, pulls the one-time code out of it and asserts. No regular expression to maintain, and no screenshot of an inbox.

  • Give the agent its own key

    Mint a key for the agent rather than reusing the one your CI holds, so you can revoke it on its own. Revoking a key deletes the addresses it created and their mail.

  • The tools are the API

    The same caps, the same retention and the same 30-second long poll. Nothing an agent can do here falls outside the HTTP contract. Connect a client.

mcp config HTTP
{
  "mcpServers": {
    "fabricatedemail": {
      "type": "http",
      "url": "https://api.fabricatedemail.com/mcp",
      "headers": {
        "Authorization": "Bearer <api-key>"
      }
    }
  }
}
  • create_addressregister a disposable address
  • wait_for_messagewait for mail and return what is there
  • extractone-time codes and links from a message
  • get_messageread one stored message
  • list_addressesthe live addresses this key holds
  • delete_addressdelete an address and its stored mail

Documentation

Start reading

Getting started takes you from an API key to a received email. The HTTP API contract is self-contained, with an OpenAPI reference beside it.