npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fmontoya/aws-ses-adapter

v1.2.0

Published

A simple adapter to simplify the AWS SES email sending API

Downloads

36

Readme

@fmontoya/aws-ses-adapter

npm version npm downloads license node

A lightweight TypeScript adapter that simplifies the AWS SES email sending API for Node.js.

  • Zero-boilerplate — one init() call, then just sendEmail()
  • Attachments built-in — multipart MIME constructed for you automatically
  • Typed errors — four distinct error classes for precise error handling
  • ESM + CJS — works in both module systems out of the box
  • Env-var fallbacks — credentials can come from environment variables

Table of Contents


Installation

# npm
npm install @fmontoya/aws-ses-adapter

# pnpm
pnpm add @fmontoya/aws-ses-adapter

# yarn
yarn add @fmontoya/aws-ses-adapter

Requires Node.js 20 or later.


Prerequisites

  1. An AWS account with SES enabled in your chosen region.
  2. A verified sender identity (domain or email address) in SES.
  3. AWS credentials with at least the ses:SendEmail and ses:SendRawEmail IAM permissions.

Quick Start

1. Initialize once (at application startup)

import { init } from '@fmontoya/aws-ses-adapter';

init({
  region: 'us-east-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
  defaultFrom: '[email protected]',
});

2. Send emails anywhere in your app

import { sendEmail } from '@fmontoya/aws-ses-adapter';

const result = await sendEmail({
  to: '[email protected]',
  subject: 'Welcome!',
  html: '<h1>Welcome to our platform!</h1>',
  text: 'Welcome to our platform!',
});

console.log('Sent! Message ID:', result.messageId);

Configuration

Via init() options

| Option | Type | Required | Description | | -------------------------------- | -------- | -------- | ------------------------------------------------------------- | | region | string | Yes* | AWS region where SES is configured (e.g. us-east-1). | | credentials.accessKeyId | string | Yes* | AWS access key ID. | | credentials.secretAccessKey | string | Yes* | AWS secret access key. | | defaultFrom | string | No | Default "From" address used when from is omitted per-email. | | accessKeyId (deprecated) | string | — | Use credentials.accessKeyId instead. | | secretAccessKey (deprecated) | string | — | Use credentials.secretAccessKey instead. |

* Required unless the corresponding environment variable is set.

Via environment variables

If a field is not provided to init(), the adapter automatically falls back to these environment variables:

| Variable | Corresponds to | | ----------------------- | ----------------- | | AWS_SES_REGION | region | | AWS_ACCESS_KEY_ID | accessKeyId | | AWS_SECRET_ACCESS_KEY | secretAccessKey | | AWS_SES_FROM_EMAIL | defaultFrom |

Calling init() with no arguments will rely entirely on environment variables:

// All credentials are read from environment variables
init();

API Reference

init(config?)

Initializes the adapter singleton. Must be called once before any send function.

import { init } from '@fmontoya/aws-ses-adapter';

init({
  region: 'us-east-1',
  credentials: {
    accessKeyId: 'AKIAIOSFODNN7EXAMPLE',
    secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
  },
  defaultFrom: '[email protected]',
});

Calling init() again replaces the existing singleton — useful for reconfiguration in tests.

Throws: SesConfigError when required credentials cannot be resolved.


sendEmail(options)

Sends a standard HTML and/or plain-text email.

const result = await sendEmail({
  to: '[email protected]', // string or string[]
  subject: 'Hello Alice',
  html: '<p>Hi Alice!</p>',
  text: 'Hi Alice!',
  from: '[email protected]', // optional — overrides defaultFrom
  replyTo: '[email protected]', // optional — string or string[]
  cc: ['[email protected]'], // optional — string or string[]
  bcc: '[email protected]', // optional — string or string[]
});

Options (SendEmailOptions):

| Field | Type | Required | Description | | --------- | -------------------- | -------- | --------------------------------------------------------- | | to | string \| string[] | Yes | Recipient(s). | | subject | string | Yes | Email subject line. | | html | string | Yes* | HTML body. | | text | string | Yes* | Plain-text body. | | from | string | No | Sender address. Overrides the defaultFrom from init.. | | replyTo | string \| string[] | No | Reply-To address(es). | | cc | string \| string[] | No | CC address(es). | | bcc | string \| string[] | No | BCC address(es). |

* At least one of html or text is required.

Returns: Promise<SendEmailResult>

Throws: SesNotInitializedError | SesValidationError | SesSendError


sendEmailWithAttachments(options)

Sends an email with one or more file attachments. The MIME message is constructed automatically.

import { sendEmailWithAttachments } from '@fmontoya/aws-ses-adapter';
import { readFileSync } from 'fs';

const result = await sendEmailWithAttachments({
  to: '[email protected]',
  subject: 'Your invoice',
  html: '<p>Please find the invoice attached.</p>',
  attachments: [
    {
      filename: 'invoice.pdf',
      content: readFileSync('./invoice.pdf'), // Buffer or string
      contentType: 'application/pdf',
    },
    {
      filename: 'notes.txt',
      content: 'Some plain text notes.',
      contentType: 'text/plain',
    },
  ],
});

Additional field (EmailAttachment):

| Field | Type | Required | Description | | ------------- | ------------------ | -------- | ------------------------------------------------ | | filename | string | Yes | Filename shown to the recipient. | | content | Buffer \| string | Yes | File content. Use Buffer for binary files. | | contentType | string | Yes | MIME type (e.g. application/pdf, image/png). |

Throws: SesNotInitializedError | SesValidationError | SesSendError


sendRawEmail(rawMessage)

Sends a fully-formed raw MIME message when you need complete control over the email format.

import { sendRawEmail } from '@fmontoya/aws-ses-adapter';

const mime = [
  'From: [email protected]',
  'To: [email protected]',
  'Subject: Raw MIME email',
  'MIME-Version: 1.0',
  'Content-Type: text/plain; charset=UTF-8',
  '',
  'Hello from a raw MIME message.',
].join('\r\n');

const result = await sendRawEmail(mime);

Throws: SesNotInitializedError | SesValidationError | SesSendError


Utility functions

import {
  isInitialized,
  hasDefaultFrom,
  getDefaultFrom,
  getRegion,
} from '@fmontoya/aws-ses-adapter';

isInitialized(); // boolean — true if init() has been called
hasDefaultFrom(); // boolean — true if a defaultFrom address is configured
getDefaultFrom(); // string | undefined — the configured defaultFrom address
getRegion(); // string — the configured AWS region, e.g. 'us-east-1'

SesAdapter class

For advanced use cases — such as managing multiple independent instances or building framework integrations (e.g. NestJS modules) — you can instantiate SesAdapter directly:

import { SesAdapter } from '@fmontoya/aws-ses-adapter';

const adapter = new SesAdapter({
  region: 'eu-west-1',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  },
  defaultFrom: '[email protected]',
});

await adapter.sendEmail({
  to: '[email protected]',
  subject: 'Hello!',
  html: '<p>Hello from a direct instance.</p>',
});

The class exposes the same methods as the singleton API: sendEmail(), sendEmailWithAttachments(), sendRawEmail(), hasDefaultFrom(), getDefaultFrom(), and getRegion().


Error Handling

All errors extend the native Error class and carry a stable name property for programmatic identification.

| Error class | When it is thrown | | ------------------------ | --------------------------------------------------------------------- | | SesNotInitializedError | A send function is called before init(). | | SesConfigError | init() is called with missing/invalid credentials. | | SesValidationError | Required email fields are missing (e.g. no html/text, no from). | | SesSendError | The AWS SES API call fails. The original error is in err.cause. |

import {
  sendEmail,
  SesNotInitializedError,
  SesConfigError,
  SesValidationError,
  SesSendError,
} from '@fmontoya/aws-ses-adapter';

try {
  await sendEmail({
    to: '[email protected]',
    subject: 'Hi',
    html: '<p>Hello</p>',
  });
} catch (err) {
  if (err instanceof SesNotInitializedError) {
    console.error('Call init() before sending emails.');
  } else if (err instanceof SesConfigError) {
    console.error('Invalid configuration:', err.message);
  } else if (err instanceof SesValidationError) {
    console.error('Invalid email options:', err.message);
  } else if (err instanceof SesSendError) {
    console.error('AWS SES send failed:', err.message);
    console.error('Root cause:', err.cause);
  }
}

Usage Examples

Express.js

// app.ts
import express from 'express';
import { init } from '@fmontoya/aws-ses-adapter';

init(); // reads credentials from environment variables

const app = express();
app.use(express.json());

app.listen(3000);
// routes/contact.ts
import { Router } from 'express';
import { sendEmail } from '@fmontoya/aws-ses-adapter';

const router = Router();

router.post('/contact', async (req, res) => {
  const { name, email, message } = req.body;

  await sendEmail({
    to: '[email protected]',
    subject: `Contact form submission from ${name}`,
    html: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`,
    text: `From: ${email}\n\n${message}`,
    replyTo: email,
  });

  res.json({ ok: true });
});

export default router;

NestJS

Create a provider using the SesAdapter class directly so it integrates with NestJS's dependency injection:

// email/email.module.ts
import { Module } from '@nestjs/common';
import { EmailService } from './email.service';

@Module({
  providers: [
    {
      provide: 'SES_ADAPTER',
      useFactory: () => {
        const { SesAdapter } = require('@fmontoya/aws-ses-adapter');
        return new SesAdapter({
          region: process.env.AWS_SES_REGION,
          credentials: {
            accessKeyId: process.env.AWS_ACCESS_KEY_ID,
            secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
          },
          defaultFrom: process.env.AWS_SES_FROM_EMAIL,
        });
      },
    },
    EmailService,
  ],
  exports: [EmailService],
})
export class EmailModule {}
// email/email.service.ts
import { Inject, Injectable } from '@nestjs/common';
import type { SesAdapter, SendEmailOptions } from '@fmontoya/aws-ses-adapter';

@Injectable()
export class EmailService {
  constructor(@Inject('SES_ADAPTER') private readonly ses: SesAdapter) {}

  async send(options: SendEmailOptions) {
    return this.ses.sendEmail(options);
  }
}

TypeScript Types

All public types are exported from the package root:

import type {
  SesAdapterConfig,
  SendEmailOptions,
  SendEmailWithAttachmentsOptions,
  EmailAttachment,
  SendEmailResult,
} from '@fmontoya/aws-ses-adapter';

Contributing

Contributions are welcome! Please read the Contributing Guide to get started.

This project follows the Contributor Covenant code of conduct.


License

MIT © FabianMontoya