Developers

Email for your code and your agents

FutureMail is email hosting with an API. Everything the web inbox can do, your code and your AI agents can do over REST, the MCP server, or a Resend-compatible API. Domains, addresses, sending, receiving, searching, threads, webhooks: same data, same permissions.

  • API base URL: https://api.futuremail.dev
  • MCP server (Streamable HTTP): https://api.futuremail.dev/mcp
  • Resend-compatible API: https://api.futuremail.dev/resend
  • Auth: Authorization: Bearer fm_live_…

Quickstart

  1. Sign up. You get a free you@futuremail.dev address instantly, with no DNS to configure.
  2. Create an API key in Settings → API keys.
  3. Send an email:
curl -X POST https://api.futuremail.dev/v1/emails \
  -H "Authorization: Bearer $FUTUREMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "you@futuremail.dev",
    "to": "delivered@test.futuremail.dev",
    "subject": "Hello from FutureMail",
    "text": "It works."
  }'

delivered@test.futuremail.dev is a test address: it simulates a delivery without sending real mail and doesn't count toward your limits.

Authentication

Every request carries an API key: Authorization: Bearer fm_live_…. Keys belong to an organization (your personal org or a team) and only see that org's data.

Scope Allows
full Everything, including domains, addresses, keys and webhooks
send Sending, replying, forwarding, drafts
read Listing, reading, searching, waiting, updating thread state

Keys can be pinned to one mailbox (agent keys always are), limited to one sending domain, and given an expiry. Keys never manage the org itself (members, invites, billing); that needs a signed-in member.

Sending email

POST /v1/emails

Field Notes
from An address you own in FutureMail
to, cc?, bcc?, replyTo? "ada@x.com", "Ada <ada@x.com>", { address, name }, or an array of these
subject Required unless a template provides it
text?, html? Plain text and/or HTML body
attachments? [{ filename, content (base64) | path (public URL), contentType?, contentId? }]. contentId makes it inline (<img src="cid:logo">). Max 20 attachments, 10 MB per message
headers? Custom headers such as List-Unsubscribe
tags? [{ name, value }], returned on the email, in webhooks, and filterable
scheduledAt? ISO 8601, up to 30 days ahead. Reschedule with PATCH /v1/emails/:id, cancel with POST /v1/emails/:id/cancel
template? { id, variables }: render a published template (id or alias)
  • Batch: POST /v1/emails/batch sends up to 100 emails in one call, validated all-or-nothing.
  • Idempotency: send an Idempotency-Key header (≤256 chars). Retrying with the same key within 24 hours returns the original response instead of sending twice.
  • Delivery timeline: an email moves queued → sent → delivered, or ends bounced / complained / failed. GET /v1/emails/:id/events returns every event, including opened and clicked when tracking is on.
  • Replies and forwards: POST /v1/emails/:id/reply ({ text?, html?, replyAll? }) threads correctly and quotes the original; POST /v1/emails/:id/forward ({ to, text? }) includes attachments.

Test addresses

Send to <outcome>[+label]@test.futuremail.dev to simulate an outcome without sending anything:

Address Result
delivered@test.futuremail.dev delivered
bounced@test.futuremail.dev bounced (permanent)
complained@test.futuremail.dev delivered, then complained
delayed@test.futuremail.dev delivery_delayed, then delivered

Test sends don't count toward limits and can't be mixed with real recipients in one email.

Agent inboxes

Give every AI agent its own mailbox, address and API key:

curl -X POST https://api.futuremail.dev/v1/agents \
  -H "Authorization: Bearer $FUTUREMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Signup bot" }'
# → { "mailbox": {…}, "address": {…}, "apiKey": { "id": "…", "key": "fm_live_…", … } }
# apiKey.key is shown once: store it now

The agent's key is pinned to its mailbox: it can only read and send from its own inbox.

GET /v1/emails/wait long-polls until a matching inbound email arrives. Filter with from, to, subject and since; timeout is in seconds (≤300). It returns the email, or 204 on timeout. One-time codes and links are extracted for you:

curl "https://api.futuremail.dev/v1/emails/wait?from=github.com&timeout=120" \
  -H "Authorization: Bearer $AGENT_KEY"
# → { …, "extracted": { "otp": "481516", "links": ["https://github.com/…"] } }

Reading and searching

  • GET /v1/threads?folder=inbox lists conversations (inbox, starred, sent, all, spam, trash); GET /v1/threads/:id returns a thread with all its messages; PATCH /v1/threads/:id archives, stars, trashes or marks read.
  • GET /v1/emails?q=… searches messages with Gmail-style operators: from: to: subject: has:attachment is:unread is:starred in:inbox|sent|spam|trash before:2026-10-01 after:2026-09-01 newer_than:7d older_than:1m. Quote values with spaces: subject:"weekly report".
  • GET /v1/emails/:id/raw returns the RFC 822 source; GET /v1/attachments/:id downloads an attachment.

MCP server

FutureMail runs a remote MCP server over Streamable HTTP. Add it to any MCP client (Claude, Claude Code, Cursor, …):

{
  "mcpServers": {
    "futuremail": {
      "type": "http",
      "url": "https://api.futuremail.dev/mcp",
      "headers": { "Authorization": "Bearer fm_live_…" }
    }
  }
}

With Claude Code:

claude mcp add --transport http futuremail https://api.futuremail.dev/mcp \
  --header "Authorization: Bearer fm_live_…"

Tools: whoami, list_inbox, search_emails, read_thread, read_email, send_email, send_batch, get_email_events, cancel_scheduled_email, reschedule_email, list_templates, reply_to_email, forward_email, update_thread, wait_for_email, list_domains, add_domain, verify_domain, create_address, create_agent_inbox.

Use an agent key to confine the model to one mailbox.

Resend compatibility

FutureMail serves the same API in Resend's format under https://api.futuremail.dev/resend. Request bodies, responses and errors match Resend's, so moving over is a base URL and key change:

RESEND_BASE_URL=https://api.futuremail.dev/resend
RESEND_API_KEY=fm_live_…
import { Resend } from "resend";

const resend = new Resend("fm_live_…", { baseUrl: "https://api.futuremail.dev/resend" });

await resend.emails.send({
  from: "Acme <hello@acme.com>", // an address you own in FutureMail
  to: ["delivered@test.futuremail.dev"],
  subject: "Hello",
  html: "<p>It works</p>",
});

Supported: POST /emails, POST /emails/batch, GET /emails, GET /emails/:id, PATCH /emails/:id, POST /emails/:id/cancel, domains and API keys. Other Resend SDKs (Python, Go, PHP, Ruby, …) work if they let you override the base URL. Webhooks use FutureMail's signature format (below), not Svix's.

Webhooks

Create webhooks in Settings → Developers or with POST /v1/webhooks ({ url, events }; the signing secret is returned once).

Events: email.received, email.scheduled, email.sent, email.delivery_delayed, email.delivered, email.bounced, email.complained, email.failed, email.suppressed, email.opened, email.clicked, domain.verified.

Payload: { "id": "evt_…", "type": "email.delivered", "createdAt": "…", "data": { … } }. The id is stable across retries, so use it to dedupe.

Every delivery is signed: FutureMail-Signature: t=<unix>,v1=<hex> where v1 = HMAC_SHA256(secret, "<t>.<raw body>"). Reject requests whose t is more than 5 minutes old:

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyFutureMail(rawBody: string, header: string, secret: string) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=") as [string, string]));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const received = Buffer.from(parts.v1 ?? "", "hex");
  return received.length === expected.length / 2 && timingSafeEqual(received, Buffer.from(expected, "hex"));
}

Non-2xx responses and timeouts (10s) are retried, up to 8 attempts over about 28 hours. Replay any delivery with POST /v1/webhooks/:id/deliveries/:deliveryId/replay. For a live feed instead, GET /v1/events is a Server-Sent Events stream of the same events.

Domains and addresses

On Pro you can use any domain you own:

  1. POST /v1/domains with { "name": "acme.com" } returns the DNS records[] to add: DKIM (three CNAMEs), MX for receiving, a custom MAIL FROM (MX + SPF TXT) and a recommended DMARC record.
  2. Add them at your DNS provider, then POST /v1/domains/acme.com/verify.
  3. Create addresses: POST /v1/addresses with { "address": "hello@acme.com" }. Addresses are free and unlimited; set a catch-all per domain, and plus-addressing (me+tag@acme.com) always works.

Per-domain settings (PATCH /v1/domains/:idOrName): catchAllMailboxId, mailFromSubdomain, tlsPolicy, openTracking, clickTracking, trackingSubdomain.

Templates and suppressions

  • Templates: POST /v1/templates with { name, alias?, subject, html?, text?, variables? }, then POST /v1/templates/:idOrAlias/publish. Placeholders are {{name}} (HTML-escaped) and {{{name}}} (raw). Send with template: { id, variables }.
  • Suppressions: permanent bounces and spam complaints are suppressed automatically. Manage the list with GET/POST /v1/suppressions, DELETE /v1/suppressions/:email, and POST /v1/suppressions/check.

Endpoint reference

Endpoint Purpose
POST /v1/emails, POST /v1/emails/batch Send one or up to 100 emails
GET /v1/emails, GET /v1/emails/:id List/search and read messages
GET /v1/emails/wait Long-poll for the next matching inbound email
GET /v1/emails/:id/events Delivery timeline
PATCH /v1/emails/:id, POST /v1/emails/:id/cancel Reschedule or cancel a scheduled email
POST /v1/emails/:id/reply, POST /v1/emails/:id/forward Reply in-thread, forward
GET/PATCH/DELETE /v1/threads/:id, POST /v1/threads/batch Conversations
GET/POST /v1/domains, POST /v1/domains/:idOrName/verify Custom domains and DNS
GET/POST /v1/addresses, GET /v1/addresses/availability Addresses and aliases
GET/POST /v1/mailboxes, POST /v1/agents Mailboxes and agent inboxes
GET/POST /v1/templates, POST /v1/templates/:id/publish Templates
GET/POST /v1/suppressions Suppression list
GET/POST /v1/api-keys API keys
GET/POST /v1/webhooks, GET /v1/events Webhooks and the SSE event stream
GET /v1/me Current org, role, plan and usage

Errors, pagination and rate limits

  • Errors: { "error": { "code": "not_found", "message": "Email not found" } } with a matching HTTP status. Paid-plan actions on Free return 402 upgrade_required.
  • Pagination: lists return { "data": [...], "nextCursor": "…" | null } and accept limit (1–100) and cursor.
  • Rate limits: 10 requests/second per API key. Responses carry RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset; over the limit you get 429 with Retry-After, and the request was not processed, so it is safe to retry.

Plans and limits

Free Pro ($20/month)
Addresses on futuremail.dev ✓ ✓
Agent inboxes, API, MCP, webhooks ✓ ✓
Custom domains and addresses on them – Unlimited
Recipients per month 3,000 (100 a day) 50,000, no daily cap

Limits are hard caps: you're never charged overage, and there's no per-seat pricing. At most 50 recipients and 10 MB per message.