SMEDRECSMEDREC
Home
Get Started
AI Agents
Development Resources
Home
Get Started
AI Agents
Development Resources
  • Introduction

    • Get Started
  • AI Agents

    • FHIR Test Agent
    • Assistant Agent
    • Patient Report Agent
    • Scheduling Agent
  • Development

    • Development Resources
    • MCP FHIR Server Overview
    • Authentication and Authorization Flow (MCP Server)
    • FHIR Client (@repo/fhir)
    • MCP FHIR Tools
    • Security Considerations
    • Deployment and Configuration
  • Applications

    • API Application (apps/api)
    • Audit Worker (apps/audit)
  • Packages

    • Audit Package (@repo/audit)
    • @repo/auditdb
    • Mailer Package (@repo/mailer)
    • Cerbos Client (@repo/cerbos)
  • Databases

    • Transparent Field Encryption in PostgreSQL

Mailer Package (@repo/mailer)

The @repo/mailer package provides a unified interface for sending emails through various providers. It's designed to be flexible and usable in different JavaScript environments, including Node.js and Cloudflare Workers.

Table of Contents

  • Installation
  • Core Concepts
    • MailerProvider Interface
    • MailerSendOptions
  • Available Providers
    • NodeMailer (SMTP)
      • Configuration (NodeMailerSmtpOptions)
      • Usage Example
    • WorkersMailer (SMTP for Cloudflare Workers)
      • Configuration (WorkerMailerOptions)
      • Usage Example
      • DKIM Signing
    • ResendMailer
      • Configuration (ResendMailerOptions)
      • Usage Example
    • SendGridMailer
      • Configuration (SendGridMailerOptions)
      • Usage Example
  • Choosing a Provider
  • Error Handling
  • Advanced Usage
    • Dynamic Provider Selection
  • Contributing

Installation

To use this package in your application or another package within the monorepo:

pnpm add '@repo/mailer@workspace:*'
# or
# yarn add '@repo/mailer@workspace:*'
# npm install '@repo/mailer@workspace:*'

Core Concepts

MailerProvider Interface

All mailer classes implement the MailerProvider interface, which defines a single method:

interface MailerProvider {
	send(options: MailerSendOptions): Promise<void>
}

This ensures that switching between providers is seamless, as the method for sending emails remains consistent.

MailerSendOptions

The send method across all providers accepts an object of type MailerSendOptions:

interface MailerSendOptions {
	from: string // Sender's email address
	to: string | string[] // Recipient's email address or an array of addresses
	subject: string // Email subject
	html: string // HTML content of the email
	text?: string // Optional plain text content of the email
}

Available Providers

NodeMailer (SMTP)

Uses the popular nodemailer library for sending emails via SMTP. Suitable for Node.js environments.

Configuration (NodeMailerSmtpOptions)

These are the standard nodemailer SMTP transport options.

import type { NodeMailerSmtpOptions } from '@repo/mailer'

const nodeMailerConfig: NodeMailerSmtpOptions = {
	host: 'smtp.example.com',
	port: 587, // Or 465 for SSL
	secure: false, // true for 465, false for other ports like 587 (STARTTLS)
	auth: {
		user: 'your-smtp-username',
		pass: 'your-smtp-password',
	},
	// Other nodemailer options can be added here
}

Usage Example

import { NodeMailer } from '@repo/mailer'

import type { MailerSendOptions, NodeMailerSmtpOptions } from '@repo/mailer'

const config: NodeMailerSmtpOptions = {
	/* ... your config ... */
}
const mailer = new NodeMailer(config)

const emailDetails: MailerSendOptions = {
	from: 'no-reply@yourdomain.com',
	to: 'recipient@example.com',
	subject: 'Test Email from NodeMailer',
	html: '<h1>Hello World!</h1><p>This is a test email sent via NodeMailer.</p>',
	text: 'Hello World! This is a test email sent via NodeMailer.',
}

mailer
	.send(emailDetails)
	.then(() => console.log('Email sent successfully using NodeMailer!'))
	.catch((error) => console.error('NodeMailer send error:', error))

WorkersMailer (SMTP for Cloudflare Workers)

Uses the worker-mailer library, which is specifically designed for sending emails from Cloudflare Workers environments where traditional Node.js SMTP modules might have compatibility issues.

Configuration (WorkerMailerOptions)

import type { WorkerMailerOptions } from '@repo/mailer'

const workersMailerConfig: WorkerMailerOptions = {
	host: 'smtp.yourprovider.com',
	port: 587, // Or 465, 25
	secure: false, // Set to true if port is 465
	auth: {
		user: 'your-smtp-username',
		pass: 'your-smtp-password',
	},
	from: 'default-from@yourdomain.com', // Default from address if not specified in send options
	// Optional DKIM configuration
	dkim: {
		privateKey: `-----BEGIN PRIVATE KEY-----\nYOUR_DKIM_PRIVATE_KEY\n-----END PRIVATE KEY-----`,
		domainName: 'yourdomain.com',
		keySelector: 'default', // Your DKIM selector
	},
}

Note on secure option: For worker-mailer, the secure option behaves slightly differently than nodemailer. If port is 465, secure is implicitly true. For other ports like 587 (STARTTLS), secure should generally be false as worker-mailer handles STARTTLS automatically.

Usage Example

import { WorkersMailer } from '@repo/mailer'

import type { MailerSendOptions, WorkerMailerOptions } from '@repo/mailer'

const config: WorkerMailerOptions = {
	/* ... your config ... */
}
const mailer = new WorkersMailer(config)

const emailDetails: MailerSendOptions = {
	from: 'worker-sender@yourdomain.com', // Overrides default if set in config
	to: 'recipient@example.com',
	subject: 'Test Email from WorkersMailer',
	html: '<h1>Hello from a Cloudflare Worker!</h1>',
}

// Within your Worker's fetch handler or scheduled event:
// await mailer.send(emailDetails);
// console.log('Email sent successfully using WorkersMailer!');

DKIM Signing

WorkersMailer supports DKIM signing. Provide the dkim object in the configuration with your private key, domain name, and key selector. Ensure your DNS records are correctly set up for DKIM.

ResendMailer

Integrates with the Resend API for sending emails.

Configuration (ResendMailerOptions)

import type { ResendMailerOptions } from '@repo/mailer'

const resendConfig: ResendMailerOptions = {
	apiKey: 'YOUR_RESEND_API_KEY', // Obtain from your Resend dashboard
}

Usage Example

import { ResendMailer } from '@repo/mailer'

import type { MailerSendOptions, ResendMailerOptions } from '@repo/mailer'

const config: ResendMailerOptions = { apiKey: 're_yourActualApiKey' }
const mailer = new ResendMailer(config)

const emailDetails: MailerSendOptions = {
	from: 'onboarding@resend.dev', // Must be a verified domain/sender in Resend
	to: 'recipient@example.com',
	subject: 'Test Email from ResendMailer',
	html: '<h1>Hello from Resend!</h1>',
}

mailer
	.send(emailDetails)
	.then(() => console.log('Email sent successfully using ResendMailer!'))
	.catch((error) => console.error('ResendMailer send error:', error))

SendGridMailer

Integrates with the SendGrid API for sending emails.

Configuration (SendGridMailerOptions)

import type { SendGridMailerOptions } from '@repo/mailer'

const sendGridConfig: SendGridMailerOptions = {
	apiKey: 'YOUR_SENDGRID_API_KEY', // Obtain from your SendGrid dashboard
}

Usage Example

import { SendGridMailer } from '@repo/mailer'

import type { MailerSendOptions, SendGridMailerOptions } from '@repo/mailer'

const config: SendGridMailerOptions = { apiKey: 'SG.yourActualApiKey' }
const mailer = new SendGridMailer(config)

const emailDetails: MailerSendOptions = {
	from: 'verified-sender@yourdomain.com', // Must be a verified sender in SendGrid
	to: 'recipient@example.com',
	subject: 'Test Email from SendGridMailer',
	html: '<h1>Hello from SendGrid!</h1>',
}

mailer
	.send(emailDetails)
	.then(() => console.log('Email sent successfully using SendGridMailer!'))
	.catch((error) => console.error('SendGridMailer send error:', error))

Choosing a Provider

  • NodeMailer: Best for traditional Node.js applications where you have direct access to SMTP servers or services like Amazon SES (via SMTP).
  • WorkersMailer: Essential for Cloudflare Workers environments due to limitations with standard Node.js TCP socket-based libraries.
  • Resend/SendGrid: Good choices if you prefer using a dedicated email API provider, which often offer better deliverability, analytics, and template management. They are also suitable for serverless environments where managing SMTP connections can be complex.

Error Handling

Each provider's send method returns a Promise. If an error occurs during the sending process, the promise will be rejected. It's crucial to implement .catch() blocks to handle these errors appropriately.

The error messages are generally prefixed with the mailer's name (e.g., "NodeMailer: Failed to send email...") to help identify the source of the error. API-based mailers (Resend, SendGrid) may include more specific error details from the API response.

try {
	await mailer.send(emailDetails)
	console.log('Email sent!')
} catch (error) {
	console.error('Detailed error:', error)
	// You might want to log this error to a monitoring service
}

Advanced Usage

Dynamic Provider Selection

You can dynamically choose a mailer provider based on environment variables or other configuration.

import { NodeMailer, ResendMailer, WorkersMailer } from '@repo/mailer'

import type { MailerProvider } from '@repo/mailer'

function getMailer(): MailerProvider {
	const providerType = process.env.EMAIL_PROVIDER // e.g., 'nodemailer', 'workersmailer', 'resend'
	const apiKey = process.env.EMAIL_API_KEY
	const smtpHost = process.env.SMTP_HOST
	// ... other config from env

	if (providerType === 'resend' && apiKey) {
		return new ResendMailer({ apiKey })
	} else if (providerType === 'workersmailer' && smtpHost /* ... other smtpConfig */) {
		// return new WorkersMailer({ /* ... construct WorkerMailerOptions ... */ });
	}
	// Fallback to NodeMailer or throw error
	// return new NodeMailer({ /* ... construct NodeMailerSmtpOptions ... */ });
	throw new Error('Email provider not configured correctly.')
}

// const mailer = getMailer();
// mailer.send(...);

Contributing

Contributions to improve the @repo/mailer package are welcome. Please ensure that:

  • New providers implement the MailerProvider interface.
  • Configuration options are clearly typed and documented.
  • Unit tests are added for new functionality.
  • The existing code style is followed.

Last Updated: 7/9/25, 5:13 AM
Contributors: google-labs-jules[bot], José Cordeiro
Prev
@repo/auditdb
Next
Cerbos Client (@repo/cerbos)