# Email SDK

Provider-portable transactional email for Bijection with durable queues, retries, fallback adapters, idempotency, webhooks, and reactive status.

- Package: @bijectionhq/email-sdk
- Category: Messaging
- Status: Reference
- License: MIT
- Bijection source (repository access required): https://github.com/bijectionhq/email-sdk/tree/fe6ec67063930027228f021d6e67ca5cd5d6dbd1/packages/convex-email
- Upstream: https://github.com/opencoredev/email-sdk/tree/2f89fbc34630e75685a87f2497cff36378827970/packages/convex-email
- Documentation: https://docs.bijection.com/components/using
- Directory: https://bijection.com/components/email-sdk

## Get the source

Bijection repository access is required. Request access at https://bijection.com/contact.

```sh
git clone https://github.com/bijectionhq/email-sdk.git
cd email-sdk
git checkout fe6ec67063930027228f021d6e67ca5cd5d6dbd1
cd packages/convex-email
```

## Before using this component

Read the package README at the recorded revision for setup, dependencies, and API examples. Upstream documentation describes the original package and may differ from the Bijection adaptation. This is a source candidate for evaluation. Catalog inclusion does not establish npm availability or runtime qualification. Check compatibility with your SDK and deployment before adoption. External providers run their own compute.

## Upstream package documentation

Recorded 2026-10-23. This describes @opencoredev/convex-email; check the Bijection adaptation separately.

Email SDK provides a single TypeScript client for sending transactional email across 23 provider adapters including Resend, Postmark, SendGrid, AWS SES, and SMTP. It normalizes the message format across providers, adds retry logic and fallback routing between adapters, and surfaces unsupported field errors before data is silently dropped. Convex actions can use it server-side to trigger emails from mutations, scheduled functions, or webhooks.

### Use cases

- Sending welcome or transactional emails from a Convex action without coupling your code to a single provider's API
- Switching email providers without rewriting send logic, using the same normalized message interface across all 23 adapters
- Configuring fallback routes so that if your primary provider fails, sends automatically retry through a secondary adapter
- Validating that a message's fields are supported by the target provider before the send, avoiding silent data loss
- Running dry-run smoke tests against real provider configs in CI using the built-in test adapters and CLI doctor command

### How it works

Initialize a client with `createEmailClient` from `@opencoredev/email-sdk`, passing an array of adapter instances. Each adapter is imported from its own entry point, for example `import { resend } from '@opencoredev/email-sdk/resend'`, and configured with provider credentials. The client exposes a single `email.send()` method that accepts a normalized message object with `from`, `to`, `subject`, and `html` fields.

Retries and fallback routing are configured at the client level. If the first adapter in the array fails, the SDK can route the send through subsequent adapters. Field-support checks run before the send, so unsupported fields raise an error rather than being silently ignored by the provider.

Because the SDK is server-side only and requires Node 20+ or Bun, it should be called from Convex actions rather than queries or mutations directly. API keys are passed via environment variables and never exposed to client code. Observability hooks for logs, metrics, and traces can be attached at client creation time. Telemetry is disabled automatically when `NODE_ENV=test` or can be opted out via the `EMAIL_SDK_TELEMETRY=0` environment variable.

### Upstream README

<p align="center">
</p>

<p align="center">
  <a href="https://www.npmjs.com/package/@opencoredev/email-sdk"><img alt="npm version" src="https://shieldcn.dev/npm/@opencoredev/email-sdk.svg?variant=secondary&mode=dark" /></a>
  <a href="https://github.com/opencoredev/email-sdk/stargazers"><img alt="GitHub stars" src="https://shieldcn.dev/github/opencoredev/email-sdk/stars.svg?variant=branded&mode=dark" /></a>
  <a href="https://x.com/leodev"><img alt="Follow @leodev on X" src="https://shieldcn.dev/x/follow/leodev.svg?variant=branded&mode=dark" /></a>
</p>

One TypeScript client for transactional email. Pick the providers you actually send through, add retries and fallback routes, catch unsupported fields before they are silently dropped, and keep every send observable.

- Adapters for 22 provider APIs plus SMTP, 23 adapters total, behind one normalized message
- Retries within an adapter, plus fallback routes across adapters
- Fail-fast field-support checks before a provider drops data
- Batch personalization with per-recipient variables, plus provider-side scheduled sends
- Observability hooks for logs, metrics, and traces
- Test adapters that never call real providers
- CLI for adapter discovery, doctor checks, and dry-run sends

## Install

```bash
npm install @opencoredev/email-sdk
```

The SDK is server-side only and needs Node 20+ or Bun. Keep provider API keys out of client code.

## Usage

```ts
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",
  html: "<p>It works.</p>",
});
```

## Adapters

Resend, Postmark, SendGrid, AWS SES, Mailgun, Brevo, MailerSend, SparkPost, Mailchimp, Iterable, Loops, Plunk, Mailtrap, Cloudflare, Unosend, Scaleway, ZeptoMail, MailPace, Sequenzy, JetEmail, Lettermint, Primitive, SMTP, and a testing adapter, each imported from its own entry point. New here? Start with `resend` for the fastest first send.

## CLI

```bash
npx email-sdk doctor --adapter resend
```

Discover adapters, validate setup, and run dry-run smoke sends from any environment.

## Documentation

Full docs live at **[email-sdk.dev/docs](https://email-sdk.dev/docs)**. Good places to start:

- [Production send pipeline](https://email-sdk.dev/docs/guides/production-send-pipeline)
- [Fallbacks and retries](https://email-sdk.dev/docs/concepts/fallbacks-and-retries)
- [Field support](https://email-sdk.dev/docs/adapters/field-support)

## Telemetry

Email SDK collects anonymous usage analytics so we can see which adapters and CLI commands get used and how often sends succeed. The first run prints a notice with opt-out instructions.

What gets collected:

- Built-in adapter names (custom adapters are reported as `custom`) and CLI command names
- Success or failure, error codes, and send duration
- Total recipient counts (`to` + `cc` + `bcc`) and whether a message includes attachments (a boolean only, never the files themselves)
- Whether scheduling was requested
- SDK version, OS, Node.js version, whether the run happens in CI (and which CI provider), and whether usage comes from the library or the bundled CLI
- Redacted error reports: the error type, the Email SDK error code, and stack traces with file paths reduced to package-relative names. Error messages are scrubbed of email addresses, URLs, quoted text, long tokens, and home directories before upload.

Everything is tied to a random anonymous ID stored in `~/.config/email-sdk/telemetry.json`. Email content, subjects, addresses, headers, attachments, API keys, and any other message data are never collected.

Opt out at any time with an environment variable:

```bash
export EMAIL_SDK_TELEMETRY=0   # or DO_NOT_TRACK=1
```

or per client in code:

```ts
const client = createEmailClient({ adapters: [resend({ apiKey })], telemetry: false });
```

Telemetry is also disabled automatically when `NODE_ENV=test`.

## Sponsors

Email SDK is supported by companies that help keep provider integrations practical and maintained. Want your logo here? **[Become a sponsor →](https://github.com/sponsors/opencoredev)**

<p align="center">
  <a href="https://github.com/sponsors/opencoredev">
      <source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/sponsors/opencoredev.svg?special=resend,instatushq,primitivedotdev,lettermint&title=false&mode=dark&preset=surface" />
      <source media="(prefers-color-scheme: light)" srcset="https://shieldcn.dev/sponsors/opencoredev.svg?special=resend,instatushq,primitivedotdev,lettermint&title=false&mode=light&preset=surface" />
    </picture>
  </a>
</p>

<p align="center">
  <a href="https://www.sequenzy.com/?ref=emailsdk"><img src="./apps/fumadocs/public/og/provider-logos/sequenzy.jpeg" width="56" height="56" alt="Sequenzy logo"></a><br>
  <sub>Also sponsored by <a href="https://www.sequenzy.com/?ref=emailsdk"><b>Sequenzy</b></a> · <a href="https://email-sdk.dev/docs/adapters/sequenzy">adapter docs</a></sub>
</p>

## Star History

<p align="center">
  <a href="https://github.com/opencoredev/email-sdk/stargazers"><img alt="Star history" src="https://shieldcn.dev/chart/github/stars/opencoredev/email-sdk.svg?mode=dark" /></a>
</p>

<p align="center"><sub><a href="./LICENSE">MIT License</a> · Built by <a href="https://x.com/leodev">@leodev</a></sub></p>