TempMail.name

Temporary Email API

A public, API-key-authenticated API for creating and reading temporary inboxes programmatically, plus email.received webhooks so you don’t have to poll. This is the real, working Phase 5 API — every example on this page hits an endpoint that exists in this codebase.

Getting an API key

Self-service key creation isn’t built yet — it would need an end-user account system this product doesn’t have (today the only accounts are internal admin accounts). For now, an admin mints keys from /admin/api-keys. Contact us if you’d like one.

Authentication & rate limits

Every request needs Authorization: Bearer <your key>. Rate limits are per key, not per IP, and scale with plan: Free, Developer, and Business tiers get different hourly caps (see pricing). A 429 response includes a resetSeconds field.

Create a temporary inbox

curl -X POST https://tempmail.name/api/public/v1/inboxes \
  -H "Authorization: Bearer tmk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"lifetimeSeconds": 1800}'

# {"id":"a1b2...","address":"q7x9k2p4@tempmail.name","createdAt":"...","expiresAt":"..."}

List messages in an inbox

curl https://tempmail.name/api/public/v1/inboxes/a1b2.../messages \
  -H "Authorization: Bearer tmk_your_api_key_here"

Endpoints

These mirror the internal, unauthenticated /api/v1/* endpoints the web app itself uses (same underlying logic — see src/lib/inbox-service.ts in the source) — the public versions just add API key auth and per-key rate limiting on top.

JavaScript

const res = await fetch('https://tempmail.name/api/public/v1/inboxes', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TEMPMAIL_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ lifetimeSeconds: 1800 }),
});
const inbox = await res.json();

// Poll for a message (or register a webhook instead — see below)
const messages = await fetch(
  `https://tempmail.name/api/public/v1/inboxes/${inbox.id}/messages`,
  { headers: { Authorization: `Bearer ${process.env.TEMPMAIL_API_KEY}` } },
).then((r) => r.json());

Python

import os
import requests

API_KEY = os.environ["TEMPMAIL_API_KEY"]
headers = {"Authorization": f"Bearer {API_KEY}"}

inbox = requests.post(
    "https://tempmail.name/api/public/v1/inboxes",
    headers=headers,
    json={"lifetimeSeconds": 1800},
).json()

messages = requests.get(
    f"https://tempmail.name/api/public/v1/inboxes/{inbox['id']}/messages",
    headers=headers,
).json()

Webhooks: email.received

Register a webhook URL from your key’s page in /admin/api-keys. Every message that arrives in an inbox created by that key fires a POST to your URL with this payload:

{
  "event": "email.received",
  "inboxAddress": "q7x9k2p4@tempmail.name",
  "message": {
    "id": "c3d4...",
    "from": "no-reply@example.com",
    "subject": "Your verification code",
    "receivedAt": "2026-08-22T14:03:11.000Z",
    "bodyText": "Your code is 482913. It expires in 10 minutes.",
    "sizeBytes": 412,
    "otp": { "code": "482913", "confidence": 0.94 },
    "verificationLinks": []
  }
}

Each delivery is signed: the raw request body is HMAC-SHA256’d with your webhook’s secret (shown once, at registration) and sent as the X-TempMail-Signature header (hex-encoded). Verify it before trusting the payload:

import crypto from 'node:crypto';

function verifyTempMailWebhook(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac('sha256', secret).update(rawBody, 'utf8').digest('hex');
  const expectedBuf = Buffer.from(expected, 'hex');
  const actualBuf = Buffer.from(signatureHeader, 'hex');
  if (expectedBuf.length !== actualBuf.length) return false;
  return crypto.timingSafeEqual(expectedBuf, actualBuf);
}

// In your webhook route handler, verify BEFORE trusting req.body:
// const ok = verifyTempMailWebhook(rawBody, req.headers['x-tempmail-signature'], YOUR_WEBHOOK_SECRET);

Known limitation, stated plainly: delivery is a single best-effort attempt with a short timeout, not a retry-with-backoff queue — that needs durable background-job infrastructure this build doesn’t have yet. The most recent delivery’s HTTP status is visible on the webhook in the admin UI, so a failure is at least observable, but nothing re-sends it automatically. If your endpoint needs to be certain it saw every message, poll GET /api/public/v1/inboxes/:id/messages as a backstop.

Not built yet

Questions or want early access to a feature above? Contact us.