# @suaveplan/emailer - Universal email service with plugin transports (Dummy / SMTP via injectable SmtpClientLike / Gmail REST via FetchLike), nine lifecycle hooks, retry, queue dispatch, Zod-validated boundaries, OpenTelemetry-instrumented hot paths, injectable Clock/Rng/Logger/FetchLike/TimersLike, stable defineCodes('EMAILER', [...]) error registry. Universal email service with pluggable transports. Ships `EmailService`, three transports (Dummy / SMTP via injectable `SmtpClientLike` / Gmail REST via injectable `FetchLike`), nine lifecycle hooks, deterministic retry, structural queue dispatch, Zod-validated option boundaries, OpenTelemetry-instrumented hot paths, and a stable `defineCodes("EMAILER", [...])` error registry. ## Documentation tree - [email-service](./src/core/email-service/email-service.md) — `EmailService` is the public entry point for `@suaveplan/emailer`. It orchestrates message validation, life… - [base-email-transport](./src/core/email-service/base-email-transport.md) — `BaseEmailTransport` is the abstract helper that every concrete transport (`DummyTransport`, `SmtpTransport`, `GmailRes… - [email-service](./src/core/email-service/email-service.md) — `EmailService` is the public entry point for `@suaveplan/emailer`. It orchestrates message validation, life… - [retry](./src/core/retry/retry.md) — Deterministic retry helper used by `EmailService.send`. The helper takes a `RetryPolicy`, an injectable `TimersLike`, a… - [retry](./src/core/retry/retry.md) — Deterministic retry helper used by `EmailService.send`. The helper takes a `RetryPolicy`, an injectable `TimersLike`, a… - [validate](./src/core/validate/validate.md) — Shared address-formatting and message-validation helpers used by every concrete transport and by `EmailService` itself.… - [validate](./src/core/validate/validate.md) — Shared address-formatting and message-validation helpers used by every concrete transport and by `EmailService` itself.… - [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/emailer` ships a single stable error-code registry that every failure path in the package routes through. T… - [error-codes](./src/error-codes/error-codes.md) — `@suaveplan/emailer` ships a single stable error-code registry that every failure path in the package routes through. T… - [fake-fetch](./src/fakes/fake-fetch.md) — Deterministic test double for `FetchLike`, used by `GmailRestTransport` tests. Queues scripted responses and captures e… - [fake-smtp-client](./src/fakes/fake-smtp-client.md) — Deterministic test double for `SmtpClientLike`. Tests queue scripted responses, invoke the wrapped `SmtpTransport`, and… - [otel](./src/otel/metrics.md) — Single source of truth for every OpenTelemetry instrument emitted by `@suaveplan/emailer`. Every production path that t… - [metrics](./src/otel/metrics.md) — Single source of truth for every OpenTelemetry instrument emitted by `@suaveplan/emailer`. Every production path that t… - [schemas](./src/schemas/schemas.md) — Centralised Zod schemas for every public option bundle and wire payload in `@suaveplan/emailer`. The schemas exist to e… - [schemas](./src/schemas/schemas.md) — Centralised Zod schemas for every public option bundle and wire payload in `@suaveplan/emailer`. The schemas exist to e… - [dummy](./src/transports/dummy/dummy-transport.md) — `DummyTransport` is a deterministic in-memory transport designed for tests, fixtures, and local development. It records… - [dummy-transport](./src/transports/dummy/dummy-transport.md) — `DummyTransport` is a deterministic in-memory transport designed for tests, fixtures, and local development. It records… - [gmail-rest](./src/transports/gmail-rest/gmail-rest-transport.md) — `GmailRestTransport` sends mail through Gmail's REST API directly, over an injectable `FetchLike`. The transport builds… - [gmail-rest-transport](./src/transports/gmail-rest/gmail-rest-transport.md) — `GmailRestTransport` sends mail through Gmail's REST API directly, over an injectable `FetchLike`. The transport builds… - [smtp](./src/transports/smtp/smtp-transport.md) — `SmtpTransport` is a structural SMTP transport: it accepts a caller-supplied `SmtpClientLike` adapter (the contract is… - [smtp-transport](./src/transports/smtp/smtp-transport.md) — `SmtpTransport` is a structural SMTP transport: it accepts a caller-supplied `SmtpClientLike` adapter (the contract is… ## Why universal The upstream `@suaveplan/emailer` was server-only because it imported `nodemailer` and `googleapis` directly. The rewrite drops both hard dependencies in favour of injectable contracts: - **SMTP**: callers supply a thin `SmtpClientLike` adapter so nodemailer (or any other library) lives in the consumer's app shell, not in this package. - **Gmail**: send is implemented directly against the Gmail REST API via `FetchLike`, so token acquisition is the caller's concern and the transport runs unchanged in Bun, Node, and the browser. ## Modules - [`src/core/email-service/email-service.md`](src/core/email-service/email-service.md) — `EmailService` orchestrator - [`src/core/email-service/base-email-transport.md`](src/core/email-service/base-email-transport.md) — abstract helper - [`src/core/retry/retry.md`](src/core/retry/retry.md) — deterministic retry helper - [`src/core/validate/validate.md`](src/core/validate/validate.md) — address-formatting helpers - [`src/transports/dummy/dummy-transport.md`](src/transports/dummy/dummy-transport.md) — in-memory test transport - [`src/transports/smtp/smtp-transport.md`](src/transports/smtp/smtp-transport.md) — SMTP via adapter - [`src/transports/smtp/smtp-client-like.types.md`](src/transports/smtp/smtp-client-like.types.md) — adapter contract - [`src/transports/gmail-rest/gmail-rest-transport.md`](src/transports/gmail-rest/gmail-rest-transport.md) — Gmail REST transport - [`src/error-codes.md`](src/error-codes.md) — error registry - [`src/schemas/schemas.md`](src/schemas/schemas.md) — Zod boundary schemas - [`src/types/emailer.types.md`](src/types/emailer.types.md) — public types - [`src/otel/metrics.md`](src/otel/metrics.md) — OTel instruments - [`src/fakes/fake-smtp-client.md`](src/fakes/fake-smtp-client.md) — deterministic SMTP fake - [`src/fakes/fake-fetch.md`](src/fakes/fake-fetch.md) — deterministic fetch fake ## Quick start ```ts import { EmailService } from "@suaveplan/emailer"; import { createDummyTransport } from "@suaveplan/emailer/transports/dummy"; const transport = createDummyTransport(); const service = new EmailService({ transport, transportOptions: {}, defaultFrom: "no-reply@example.com", }); await service.initialize(); const result = await service.send({ to: "user@example.com", subject: "hello", html: "

hi

", }); ``` ## License MIT