Email SDK

Email SDK

One typed send() for 23 email providers, with explicit routing, retries, and fallbacks. Zero runtime dependencies.

Email SDK is a zero-dependency TypeScript library for transactional email. You write one typed message, and the adapters you configured decide how it reaches Resend, Postmark, SendGrid, AWS SES, Mailgun, SMTP, or any of 23 providers. Switching providers, or surviving an outage with a fallback route, is a config change. Your application code stays the same.

import { createEmailClient } from "@opencoredev/email-sdk";
import { resend } from "@opencoredev/email-sdk/resend";

const email = createEmailClient({
  adapters: [resend({ apiKey: process.env.RESEND_API_KEY! })],
});

await email.send({
  from: "Acme <hello@acme.com>",
  to: "user@example.com",
  subject: "Welcome",
  text: "Your account is ready.",
});

Why Email SDK

Provider SDKs are easy to adopt and hard to leave. Each has its own message shape, its own error format, and its own opinion about retries. Email SDK puts one client in front of all of them. Every adapter is a separate entry point, so your bundle only contains the providers you actually send through, and the core has no runtime dependencies.

Providers genuinely differ. Resend has no metadata field, SMTP has no tags, Iterable takes exactly one recipient. When a message uses a field the selected adapter cannot carry, the adapter throws before making the request instead of quietly dropping the field. The field support matrix shows what each provider maps.

Failure handling has two explicit layers: exponential backoff inside an adapter for transient errors, then fallback adapters once the current one has failed for good. How routing works covers both, including why a fallback route only helps when it can carry the same fields.

The one message shape also covers batches and scheduling. recipientVariables personalizes a batch per recipient on any adapter (natively on Mailgun and SendGrid, client-side everywhere else), and sendAt hands delivery timing to providers with a scheduling API.

The rest is operational plumbing you would otherwise write yourself. Hooks and the observability plugin emit redacted events (counts and tag names, not bodies or recipients). Memory and failing adapters plus the capture plugin let unit tests assert send behavior without a provider account. The CLI covers setup checks: email-sdk doctor inspects your environment, send --dry-run validates a message against an adapter, and send runs a real smoke test. See the CLI reference.

Start here

Beyond the core

What it is not

Email SDK is not a campaign tool, a queue, a template engine, or a hosted analytics product. It is the layer apps keep rebuilding by hand: adapter setup, one consistent send call, typed errors, compatibility checks, and fallback routes explicit enough to debug at 3 a.m.

Local checks are not deliverability

The SDK validates message shape and field support before every request, but live delivery still depends on your provider account: verified sender domains, API scopes, regions, and sandbox rules. Dry-run first, then run one real smoke send from your production environment.

On this page