Skip to content

Repository files navigation

@goobits/email

Provider-agnostic email delivery with a small, result-based contract.

Use AWS SES v2, Resend, SMTP, the in-memory test provider, or an application-owned transport without coupling message workflows to one vendor.

Why Email · Quick start · Providers · Boundaries


Why Email

@goobits/email standardizes message validation, sender defaults, sequential batch delivery, verification, failure classification, and privacy-aware logging while leaving credentials and provider lifecycle with the application.

Provider dependencies are optional peers. Consumers pay for only the transport they import, and custom providers need none of the bundled vendor SDKs.

Quick start

The declared package contract requires Node.js 22 or newer. Other runtimes need a compatible toolchain and provider implementation and are not promised by the package metadata.

pnpm add @goobits/email
import{createEmailService,createMockProvider}from'@goobits/email'constprovider=createMockProvider()constemail=createEmailService({
provider,from: 'no-reply@example.com',})constresult=awaitemail.send({to: 'person@example.com',subject: 'Welcome',text: 'Hello.',})if(!result.success){console.error(result.reason)}

The package publishes TypeScript source entrypoints directly; consumers need a toolchain that can compile them.

Providers

ImportRequired peerResponsibility
@goobits/emailnoneService, contracts, and in-memory mock
@goobits/email/ses@aws-sdk/client-sesv2AWS SES v2 adapter
@goobits/email/resendresendResend adapter
@goobits/email/smtpnodemailerSMTP adapter

The application creates and owns each SDK client or SMTP transporter, including credentials, region, retries, TLS, pooling, and shutdown.

Contract and boundaries

createEmailService requires a provider and default from address. Each message needs at least one of html or text. The service accepts multiple recipients, reply-to, CC, BCC, attachments, inline CIDs, and custom headers. Transport support for inline attachments and custom headers varies by provider.

EmailProvider.send() is required to resolve with an EmailResult. The built-in providers translate transport failures into unsuccessful results; a custom provider that rejects violates the interface and that rejection propagates through EmailService.send(). Failure reasons form a closed set: configuration-missing, invalid-recipient, transport-error, rate-limited, or unknown. Batch sends are sequential and return one result per recipient.

When a logger is supplied, the package records operational categories and provider identifiers without recipient addresses, subjects, bodies, or raw provider errors. The application still owns redaction of any context it adds.

The package does not render templates, queue or schedule messages, or process bounces and complaints. Pass pre-rendered HTML or text, wrap delivery in an application queue when needed, and handle provider webhooks separately.

Development

pnpm install --frozen-lockfile
pnpm typecheck
pnpm test

License

MIT © Goobits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages