# An email API you can run in five minutes — and verify forever

> An email API you can run in five minutes and verify forever: durable idempotent sends, a sandbox that fakes nothing, and drop-in SendGrid compatibility.

Canonical: https://emailfast.dev/developers

## Send in one call

```js
import { EmailFast } from "@email-fast/nodejs";

const ef = new EmailFast({ apiKey: process.env.EMAILFAST_API_KEY, baseUrl: "https://api.emailfast.dev" });

await ef.send({
  to: "ada@example.com",
  subject: "Welcome!",
  html: "<h1>Hi {{name}}</h1>",
  data: { name: "Ada" },
  idempotency_key: "signup-42",
});
```

a 202 from the API means the send is committed to a durable, partitioned outbox before we answer — a crash can't lose it, and a retry with the same idempotency key can't double-send.

## The parts you usually have to build yourself

| Built in | What it means for you |
|---|---|
| Idempotency keys | Retry any request without double-sending — per message, honored for 90 days |
| Suppression management | Bounces, complaints, and unsubscribes are enforced at admission; no ingress can skip them |
| Scheduling & batch | `send_at` up to 30 days out; batches of 500 with per-item results |
| Message timeline | `GET /v1/messages/:id` returns the full event history for any send |
| Signed webhooks | webhooks signed with timestamped HMAC-SHA256 (Stripe-style t=…,v1=…), with delivery hardened against server-side request forgery |
| Inbound email | Receive, parse, and route replies and inbound mail to your webhook, with SPF/DKIM/DMARC verdicts attached |
| Email validation | `POST /v1/validate` to catch bad addresses before you send |

## A sandbox that fakes nothing

sandbox keys (ef_sandbox_…) that run the real pipeline dry: real validation, real rendering, real events, a hosted capture inbox — and no email leaves.

```bash
curl https://api.emailfast.dev/v1/emails \
  -H "Authorization: Bearer ef_sandbox_..." \
  -d '{ "to": "test@example.com", "subject": "CI run", "html": "<p>ok</p>" }'
```

Point your CI at it. Assert on the event stream. Browse the captured message in the
hosted inbox. Nothing leaves, and nothing is mocked.

## Your existing code probably already works

SendGrid-, Mailgun-, and Postmark-compatible endpoints: point your existing SDK at a new base URL with a new key and keep your code — and if you'd rather not touch code at all, point your app's
[SMTP config at us](/features/smtp): your API key is the SMTP password. [See every migration path →](/features/migration)

## Frontend-only apps included

a browser SDK with EmailJS-compatible endpoints — the recipient always comes from the server-stored template, never from the request, so a public key in your frontend can't be abused to spam arbitrary addresses. [How the browser SDK stays abuse-proof →](/features/frontend)

## Built for the way you work now

SDKs for the browser (EmailJS-compatible), Node.js, Python, PHP, Go, and Ruby, plus a zero-dependency CLI and a published OpenAPI specification.

Your coding agent is a first-class citizen: markdown mirrors on every page (append
`.md`), [llms.txt](/llms.txt) and llms-full.txt, and an MCP server arming at launch.
[The agent guide →](/agents)

## And underneath it all

every send — REST, SMTP, browser SDK, compatibility endpoints, broadcasts, automations — passes through one admission gate: idempotency, suppression, quota, and content policy in a single checkpoint no ingress can skip — the property that makes everything above trustworthy.
Email Fast runs its own mail transfer agent, warmup engine, reputation breaker, and per-tenant fair queue — the pipes are ours, not resold. [How deliverability works →](/features/deliverability)

## What does the send API look like?

POST /v1/emails with to , subject , html , optional data merge variables, an optional idempotency_key , scheduling via send_at , and stream selection. A 202 response means the message is durably queued. Full reference in the docs .

## Do you support batch sending and scheduling?

Yes — POST /v1/emails/batch accepts up to 500 messages with per-item results, and any send can be scheduled with send_at . Batches through the compatibility endpoints are transactionally atomic: a mid-batch failure rolls back every recipient so a retry can't double-send.

## Can I keep using my SendGrid/Mailgun/Postmark SDK?

Yes: SendGrid-, Mailgun-, and Postmark-compatible endpoints: point your existing SDK at a new base URL with a new key and keep your code. See migration .

## How do webhooks work?

Subscribe endpoints to email.sent , email.bounced , email.opened , email.clicked , email.complained , email.unsubscribed , and email.inbound — all of them webhooks signed with timestamped HMAC-SHA256 (Stripe-style t=…,v1=…), with delivery hardened against server-side request forgery.

## How do I test without sending real email?

sandbox keys (ef_sandbox_…) that run the real pipeline dry: real validation, real rendering, real events, a hosted capture inbox — and no email leaves. Your test suite gets real behavior with zero risk — no third-party capture service required.
