Email SDK
Concepts

Fallbacks and retries

Retry transient failures and use a backup adapter.

Retries happen inside one adapter. Fallbacks happen after an adapter fails.

const email = createEmailClient({
  adapters: [
    resend({ apiKey: process.env.RESEND_API_KEY! }),
    smtp({
      host: "smtp.purelymail.com",
      port: 587,
      auth: {
        user: process.env.SMTP_USER!,
        pass: process.env.SMTP_PASS!,
      },
    }),
  ],
  retry: {
    retries: 1,
  },
  fallback: ["smtp"],
});

In this setup, Email SDK tries Resend first. If Resend fails with a retryable error, it retries once. If it still fails, it tries SMTP.

Override fallback for one send

await email.send(message, {
  provider: "resend",
  fallbackAdapters: ["smtp"],
});

Override retries for one send

await email.send(message, {
  retries: 2,
});

Retryable HTTP responses

The fetch-based adapters mark these responses as retryable:

StatusMeaning
408Request timeout
409Conflict
425Too early
429Rate limited
5xxAdapter or network-side failure

Use an idempotency key for email that may be retried.

await email.send(message, {
  idempotencyKey: "receipt:order_123",
});

On this page