Email SDK

Email SDK

A small TypeScript email client with swappable adapters, plugins, and explicit provider limits.

Email SDK is a small TypeScript package for transactional email. It gives your application one client and one message shape while keeping provider-specific behavior visible in the adapter docs.

Use Resend for a simple API path, SMTP when you want a cheap or self-managed route, or another provider when its field support fits your app better. Add plugins for shared defaults, observability, capture, or community adapters. Your application code still calls send; the adapter decides how that message maps to the provider.

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.",
});

Start here

What is included

  • createEmailClient for one shared email client.
  • email.send() for one message.
  • email.sendBatch() for small batches where each result is reported separately.
  • Fifteen adapters, including Resend, SMTP, Postmark, SendGrid, Mailgun, and MailerSend.
  • Retry and fallback options that run in the order you configure.
  • Hooks for logs, metrics, tracing, and retry visibility.
  • Plugins for defaults, observability, capture, community adapters, and reusable send behavior.
  • A small CLI for setup checks, dry runs, and smoke-test sends.
  • A repo-local agent skill for future coding agents.

What stays small

Email SDK does not try to be a template engine, campaign tool, queue, analytics platform, or full email operations suite. It is the layer many apps keep rebuilding: adapter setup, a consistent send call, typed errors, and a fallback path that is explicit enough to debug.

Provider behavior is not hidden

Email providers do not all support the same fields. A fallback route is only safe when the backup adapter can represent the same class of message. Before choosing routes, read the field support guide; unsupported fields should fail fast instead of being silently dropped.

On this page