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

sesmailer-js

v0.1.0

Published

Fast, lightweight transactional email for Node.js — powered by AWS SES

Readme

sesmailer

Fast, lightweight transactional email for Node.js — powered by AWS SES


Features

  • Rate-limited sending — token bucket algorithm keeps you within SES sending limits
  • Batch sending — send multiple emails concurrently via Promise.allSettled
  • SQLite email logging — every send attempt is recorded locally
  • Built-in analytics API — HTTP server with send stats, daily breakdowns, and tag grouping
  • Email masking — obfuscate addresses in logs for privacy
  • Attachment support — send files as Buffer or string
  • Zero-config — reads from .env or .sesmailerrc.json automatically
  • TypeScript-first — full type definitions included

Quick Start

npm install sesmailer

# Optional — enables email logging and analytics
npm install better-sqlite3
import { createMailer } from 'sesmailer';

const mailer = createMailer();

await mailer.send({
  to: '[email protected]',
  subject: 'Welcome!',
  html: '<p>You are in.</p>',
});

Configuration

sesmailer resolves config in this priority order: explicit options → environment variables → .sesmailerrc.json

Option 1 — .env file

SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_USER=AKIAIOSFODNN7EXAMPLE
SMTP_PASS=your-ses-smtp-password
[email protected]
SES_RATE_LIMIT=14
ANALYTICS_PORT=4000
ANALYTICS_API_KEY=your-secret-key
MASK_EMAILS=false

| Variable | Required | Default | Description | |--------------------|----------|---------|----------------------------------------------| | SMTP_HOST | yes | — | SES SMTP endpoint | | SMTP_PORT | yes | — | Usually 587 (STARTTLS) or 465 (SSL) | | SMTP_USER | yes | — | SES SMTP username | | SMTP_PASS | yes | — | SES SMTP password | | FROM_ADDRESS | yes | — | Default sender address | | SES_RATE_LIMIT | no | 14 | Max emails per second (match your SES quota) | | ANALYTICS_PORT | no | — | Port to run the analytics HTTP server on (requires better-sqlite3) | | ANALYTICS_API_KEY| no | — | API key required on all analytics requests | | MASK_EMAILS | no | false | Obfuscate email addresses in logs |

Option 2 — .sesmailerrc.json

{
  "smtp": {
    "host": "email-smtp.us-east-1.amazonaws.com",
    "port": 587,
    "user": "AKIAIOSFODNN7EXAMPLE",
    "pass": "your-ses-smtp-password"
  },
  "from": "[email protected]",
  "rateLimit": 14,
  "analyticsPort": 4000,
  "analyticsApiKey": "your-secret-key",
  "maskEmails": false
}

Place .sesmailerrc.json in your project root. It is loaded automatically if present.

Warning: .sesmailerrc.json may contain SMTP credentials. Add it to your .gitignore.


API Reference

createMailer()

Creates and returns a mailer instance. Loads config from environment variables or .sesmailerrc.json.

const mailer = createMailer({
  smtp: { host: '...', port: 465, user: '...', pass: '...' },
  from: '[email protected]',
});

send(options)

Sends a single email. Returns { messageId, status } on success or { messageId: null, status: 'failed', error } on failure — it never throws.

const result = await mailer.send({
  to: '[email protected]',       // required
  subject: 'Hello',             // required
  html: '<p>Hello</p>',         // required
  text: 'Hello',                // optional — plain-text fallback
  from: '[email protected]',       // optional — overrides FROM_ADDRESS
  tag: 'onboarding',            // optional — used for analytics grouping
  attachments: [],              // optional — see Attachments
});

// { messageId: '<[email protected]>', status: 'sent' }

sendBatch(messages)

Sends an array of emails concurrently using Promise.allSettled. All emails are attempted regardless of individual failures. Returns an array of results in the same order as the input.

const results = await mailer.sendBatch([
  { to: '[email protected]', subject: 'Hi A', html: '<p>Hi</p>' },
  { to: '[email protected]', subject: 'Hi B', html: '<p>Hi</p>' },
]);

// [
//   { messageId: '...', status: 'sent' },
//   { messageId: null, status: 'failed', error: '...' }
// ]

close()

Closes the SMTP transport, SQLite database connection, and analytics server (if running). Call this when your process is done sending — especially in scripts or CLI tools.

await mailer.send({ ... });
mailer.close();

Attachments

Pass a Buffer or base64-encoded string with an optional contentType.

import { readFileSync } from 'fs';

await mailer.send({
  to: '[email protected]',
  subject: 'Your Invoice',
  html: '<p>Please find your invoice attached.</p>',
  attachments: [
    {
      filename: 'invoice.pdf',
      content: readFileSync('./invoice.pdf'),
      contentType: 'application/pdf',
    },
  ],
});

Analytics API

Requires better-sqlite3 to be installed. If not installed, the analytics server will not start.

Enable the analytics server by setting ANALYTICS_PORT (and optionally ANALYTICS_API_KEY). The server starts automatically when the mailer is created.

sesmailer analytics running at http://localhost:4000

All requests require the x-api-key header if ANALYTICS_API_KEY is set:

curl http://localhost:4000/api/stats/overview \
  -H "x-api-key: your-secret-key"

Endpoints

GET /api/stats/overview

{
  "totalSent": 1024,
  "totalFailed": 3,
  "sentToday": 47,
  "sentThisWeek": 312
}

GET /api/stats/daily?days=30

[
  { "date": "2026-03-01", "sent": 42, "failed": 1 },
  { "date": "2026-03-02", "sent": 58, "failed": 0 }
]

GET /api/stats/by-tag

[
  { "tag": "onboarding", "total": 210 },
  { "tag": "password-reset", "total": 88 }
]

GET /api/emails/recent?limit=50

[
  {
    "id": 1,
    "message_id": "<[email protected]>",
    "to": "[email protected]",
    "from": "[email protected]",
    "subject": "Welcome!",
    "status": "sent",
    "tag": "onboarding",
    "error": null,
    "created_at": "2026-03-15T10:22:00.000Z"
  }
]

Email Masking

When MASK_EMAILS=true (or maskEmails: true), email addresses stored in the SQLite log are obfuscated before writing:

[email protected]  →  u***@example.com

The actual email sent to SES is unaffected — only the logged value is masked.


AWS SES Setup

  1. Go to the AWS ConsoleSimple Email ServiceSMTP Settings
  2. Click Create SMTP Credentials — this generates an IAM user with SES send permissions
  3. Copy the SMTP Username and SMTP Password (shown only once)
  4. Use these as SMTP_USER and SMTP_PASS

Note: SES SMTP credentials are not the same as your AWS access keys. Do not use your AWS access key ID and secret access key here.

Sandbox mode: New SES accounts start in sandbox mode, which only allows sending to verified email addresses. Request production access from the SES console to send to arbitrary recipients.


Important Notes

  • Not compatible with serverless — If using better-sqlite3 for logging, a persistent writable file system is required. Logging will not work on Vercel, AWS Lambda, or similar ephemeral environments.
  • Logging is optional — sesmailer works without better-sqlite3. Install it only if you want email logging and the analytics API. Without it, sesmailer still sends emails with full rate limiting and validation.
  • status: 'sent' means SES accepted the message, not that it was delivered to the inbox. Bounces and complaints are handled separately via SES notifications.
  • The sesmailer.db file contains all email metadata including addresses and subjects. Ensure appropriate file permissions on your server, and add it to .gitignore.
  • Set SES_RATE_LIMIT to match your account quota. The default is 14 emails/second, which matches the SES sandbox limit. Check your SES account's sending rate in the console and update accordingly.

License

MIT