Skip to content

FRD: Email Provider Real Implementation

FieldValue
IDFRD-043
OwnerDavid Holmes
StatusDraft
Last Updated2026-06-02
Open Source Librariesresend
DocumentationResend Docs · Node.js Quickstart · API Reference
RelatedADR-027 (Default Tech Stack), ADR-014 (Open Source First)
Target Releasev2.1.0
TypeLibrary
ComplexityM

Document Summary

This FRD ships @dmwd-io/email as an optional package that re-exports resend as the platform standard for transactional email. The value is standards and drift prevention, not a custom abstraction — consuming apps get a canonical import path and documented env var conventions rather than each wiring up the SDK independently.


Introduction

Overview

Per ADR-014 (Open Source First), we designate resend as the community library for transactional email and re-export it through @dmwd-io/email. This gives the platform a single canonical import path, documents RESEND_API_KEY as the standard env var, and prevents drift across services. No custom EmailProvider interface or adapter layer is built — the resend library’s own API is the interface.

Goals

  • Designate resend as the platform standard for transactional email.
  • Re-export resend via @dmwd-io/email so consuming apps use a single import path.
  • Document RESEND_API_KEY as the platform env var convention.
  • Add only platform conventions (PII sanitization guidance, default from-address) on top of the library’s own API.

Non-Goals

  • Marketing email or bulk-send capabilities.
  • Email template authoring or storage (templates are owned by consuming applications).
  • Building a custom provider interface or adapter layer — the library’s own API is the interface (per ADR-014).

Scope

In Scope

ItemDescription
packages/@dmwd-io/email/New package directory.
packages/@dmwd-io/email/package.jsonPackage manifest with resend as a peer dependency.
packages/@dmwd-io/email/src/index.tsRe-exports all named exports from resend.
Env var documentationRESEND_API_KEY documented in .env.example and the package README.
Unit testsVerify the re-export surface matches the upstream package.

Out of Scope

ItemReason
Email template designApplication concern, not provider concern.
Bounce/complaint webhooksPhase 2 work; this FRD covers send-only.
Rate limitingHandled by the provider’s built-in rate limiting.

Users and Pain Points

UserPain Point
Application developerNo platform-standard import path for email; each service picks its own integration pattern.
Platform maintainerDrift across services makes it impossible to enforce PII log hygiene or update the SDK in one place.
OperationsNo standardized email sending means no unified logging or monitoring for email delivery.

Definitions

TermDefinition
resendThe community library designated as the platform standard for transactional email.
@dmwd-io/emailThe thin re-export package that makes resend the canonical import for platform services.
Transient errorA temporary failure (HTTP 429 or 5xx) that may succeed on retry.

Current State

src/lib/providers/email/email-provider.ts contains:

  • The EmailProvider interface with send() and sendBatch() methods.
  • An in-memory mock implementation (createInMemoryEmailProvider) that records sent messages for test assertions.
  • A TODO at line 102: // TODO: Replace with real provider (e.g. Resend, SendGrid).

No production adapter exists. Applications that need email either call Resend directly (without going through the provider abstraction) or skip email in development.


Proposed Solution

@dmwd-io/email is a thin re-export package. It adds no custom interface or adapter layer.

Package structure

packages/@dmwd-io/email/
package.json # resend listed as peerDependency
src/
index.ts # export * from 'resend'

Usage in consuming apps

import { Resend } from '@dmwd-io/email';
const resend = new Resend(process.env.RESEND_API_KEY);
await resend.emails.send({ from, to, subject, html });

No custom interface is built — the library’s API is the interface.

Platform conventions

  • RESEND_API_KEY is the standard env var name across all platform services.
  • Logs must not include the API key or recipient email addresses (PII sanitization is the responsibility of the calling code).
  • defaultFrom for each service is documented in that service’s own configuration, not in this package.

Requirements

IDPriorityRequirement
EMAIL-01P0@dmwd-io/email re-exports all named exports from resend.
EMAIL-02P0resend is listed as a peer dependency, not a bundled dependency.
EMAIL-03P0RESEND_API_KEY is documented in .env.example and the package README.
EMAIL-04P1TSDoc on the index.ts re-export module explains the platform convention.

Functional Requirements

  1. import { Resend } from '@dmwd-io/email' resolves correctly in consuming packages.
  2. The package does not add runtime overhead beyond a re-export.
  3. The package README documents the standard env var name and a minimal usage example.

Non-Functional Requirements

CategoryRequirement
Dependency sizePackage adds no runtime code beyond a re-export shim.
SecretsAPI keys are passed via RESEND_API_KEY env var, never hardcoded.
ObservabilityCalling code must not log the API key or recipient addresses (PII).
TestabilityConsumers use resend’s own test utilities or mock the module at the import boundary.

API/Interface Requirements

The resend library’s own API is the interface. No custom wrapper types are defined in this package. See the resend Node.js SDK docs for the full API surface.


Accessibility Requirements

Not applicable. This is a headless library with no UI surface.


Content and Documentation Requirements

  • Package README with a minimal usage example and RESEND_API_KEY setup instructions.
  • Add RESEND_API_KEY to the project’s .env.example.

Dependencies

DependencyTypeNotes
resendPeer (npm)Official Resend Node SDK. Listed as peerDependency so consuming apps control the version.
ADR-014GovernanceOpen Source First principle — designate community library, thin re-export only.
ADR-051GovernanceProvider pattern architecture.

Risks and Tradeoffs

RiskLikelihoodImpactMitigation
Resend SDK has breaking changes.LowMediumPin to a specific major version range in the peerDependency.
Re-export pattern offers no enforcement of PII hygiene.MediumMediumDocument in README; enforce via lint rule or code-review checklist.
API key leaked in error logs.LowHighCalling code is responsible; README documents this explicitly.

Open Questions

  1. Should the package expose a pre-configured factory (e.g. createResendClient()) that reads RESEND_API_KEY automatically, or leave instantiation fully to the caller?
  2. Should we add a rate-limiter wrapper in the package, or rely on the provider’s built-in rate limiting?

Acceptance Criteria

  • import { Resend } from '@dmwd-io/email' resolves and types correctly.
  • resend is a peerDependency in package.json, not a direct dependency.
  • RESEND_API_KEY is present in .env.example with a comment.
  • Package README includes a minimal usage example.
  • pnpm typecheck passes.
  • pnpm vitest run --project unit passes.

LLM Handoff Instructions

When implementing this FRD:

  1. Create packages/@dmwd-io/email/ if the packages directory does not already exist.
  2. Create packages/@dmwd-io/email/package.json with resend listed under peerDependencies (not dependencies). Set main, module, and types fields appropriately.
  3. Create packages/@dmwd-io/email/src/index.ts containing export * from 'resend';.
  4. Add RESEND_API_KEY= to the project’s .env.example with a brief comment.
  5. Create a minimal README.md in the package directory documenting the env var and a usage example.
  6. Run pnpm typecheck and pnpm vitest run --project unit.

Decision Log

DateDecisionRationale
2026-05-26Resend as primary, SendGrid as fallback.Resend has a simpler API and better developer experience. SendGrid provides a widely-adopted fallback for enterprise environments.
2026-05-26Separate entry points per adapter.Avoids bundling unused SDKs. Each app imports only the adapter it configures.
2026-05-26Defer attachments to follow-up.Current use cases (password reset, verification, notifications) are text/HTML only.
2026-06-02Reframed per ADR-014 (Open Source First): adopt resend as thin re-export rather than building a custom provider interface. Library API is the interface.ADR-014 establishes that we designate community libraries as standards and avoid building custom abstractions on top of them.

Document History

VersionDateAuthorChanges
0.12026-05-26David HolmesInitial draft.
0.22026-06-02David HolmesReframed per ADR-014: ship as thin re-export of resend, drop custom interface.