Email SDK
Plugins

Plugin system

Transform send options, select routes, observe lifecycle events, enforce time bounds, and extend the typed client.

Plugins compose around createEmailClient without changing adapter implementations. Choose a built-in by the job it owns; do not stack plugins that solve the same problem.

Built-in plugins

PluginUse it forSurfaceImport
DefaultsShared reply-to, headers, tags, metadata, and idempotency prefixesbeforeSend@opencoredev/email-sdk/plugins/defaults
RoutingSelect a registered adapter from the prepared message or send metadatabeforeSend@opencoredev/email-sdk/plugins/routing
TimeoutBound one logical send, including retries and fallback, with caller cancellation preservedbeforeSend@opencoredev/email-sdk/plugins/timeout
ObservabilityEmit redacted logs, metrics, and traceshooks + middleware@opencoredev/email-sdk/plugins/observability
CaptureRecord lifecycle events for tests and local inspectionhooks + middleware + client extension@opencoredev/email-sdk/plugins/capture
src/email.ts
const email = createEmailClient({
  adapters: [primary, transactional],
  plugins: [
    defaultsPlugin({ replyTo: "support@example.com" }),
    routingPlugin({
      select: ({ message }) =>
        message.tags?.some((tag) => tag.name === "transactional")
          ? "transactional"
          : undefined,
    }),
    timeoutPlugin({ timeoutMs: 10_000 }),
  ],
});

Plugin surfaces

SurfacePurposeFailure behavior
adaptersRegister additional routes synchronously.Duplicate names fail client construction.
hooksObserve attempts, retries, success, and terminal errors.Exceptions are swallowed.
middlewareTransform messages/options and react after success or failure.Exceptions become EmailMiddlewareError.
extendClientAdd a typed application-facing property or method.Reserved-key collisions fail client construction.

Plugin ids must be unique. Adapter registration and client construction stay synchronous. Order matters for beforeSend: each middleware receives the output of the previous one.

Build or install a plugin

Community packages remain outside the core support boundary. Review source, dependency versions, field validation, secret handling, and maintenance status before use.

Write a plugin

Build a typed plugin with middleware and a client extension.

Plugin API

Look up every plugin field and event type.

On this page