I just launched Social SDK. Come check it out →
Email SDK
GuidesMigration guides

Upgrade from Email SDK 2.x to v3

Update send-option metadata, webhook payload reads, and SMTP TLS options for the stricter v3 types.

v3 tightens the TypeScript types at the SDK's input boundaries. Most apps upgrade without code changes. The ones that need edits pass send-option metadata that isn't plain data, and TypeScript reports each spot as a compile error, so the type checker gives you the full list.

Upgrade the package, then run your type check:

Send-option metadata

metadata on send() options, hook events, adapter contexts, and the capture and observability plugins is now typed as EmailSendMetadata. Unless you register your own shape, that is EmailMetadataRecord: strings, numbers, booleans, null, undefined, Date, and arrays or plain objects of those.

Three patterns that compiled in 2.x now fail:

ValueWhy it failsFix
A value typed by an interfaceInterfaces have no index signatureSpread it, { ...audit }, or declare it with type
A class instance such as URLNot plain dataConvert it, for example url.toString()
A Record<string, unknown>unknown values aren't checkedType it as EmailMetadataRecord or register a shape

Before:

After:

The same rules apply to metadata on the @opencoredev/email-sdk/compat client's send options, hook events, and provider contexts. Provider-facing message.metadata is a separate field and keeps its existing type.

Register your own metadata shape

When every send carries the same context, register it once. send() then requires that shape, and hooks and plugins read its fields with their real types.

Other type changes

  • The Iterable adapter's dataFields option, or the function that returns it, is typed as EmailMetadataRecord instead of Record<string, unknown>. Apply the same fixes as for send-option metadata.
  • NormalizedWebhookEvent.payload is a parsed JsonObject instead of Record<string, unknown>. Code that builds a NormalizedWebhookEvent, such as a custom normalizer or a test fixture, must pass a JsonObject payload. JsonObject and JsonValue are exported from @opencoredev/email-sdk/webhooks.
  • The SMTP adapter's tls option uses Nodemailer's own TLS options type. Options Nodemailer doesn't accept no longer type-check.
  • createEmailAgentTools returns EmailAgentTools, and sendEmail.execute resolves to EmailSendResult instead of unknown. Existing code keeps working and can drop its casts.

Runtime changes

Provider responses now go through shared JSON parsing. A malformed or null success body is treated like an empty body, and non-string entries in accepted or rejected recipient lists are ignored instead of passed through to your result.

Client reference

Send options, metadata, and the EmailMetadataRegister interface.

On this page