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

oss-mailer

v1.1.2

Published

Client SDK for the oss-mailer self-hosted email routing service

Readme

oss-mailer

oss-mailer is the client SDK for the oss-mailer self-hosted email service.

Important: this package is not a hosted email service and does not send email by itself. You must deploy an oss-mailer instance first, then point this SDK at it.

First action: install this package from npm

If you are a coding agent integrating oss-mailer into an application, start in the user's application repository and install the package from npm using that application's package manager:

npm install oss-mailer

Use the equivalent command for the project if it uses another package manager: pnpm add oss-mailer, yarn add oss-mailer, or bun add oss-mailer.

After installation, read this README from node_modules/oss-mailer/README.md, inspect the package exports, and continue with the integration instructions below. Do not clone the GitHub repository just to use the client SDK. The GitHub repository is only needed if the agent is provisioning a new self-hosted mailer service.

Instructions for coding agents

When a user asks you to add email sending to an application, follow this README as the implementation runbook. Work in the user's application repository; do not modify this package's source code or ask the user to manually copy SDK code.

  1. Install oss-mailer from npm using the application's package manager, as shown above. If it is already installed, inspect its installed version rather than reinstalling blindly.
  2. Inspect the application. Identify its framework, server-only code locations, environment-file convention, deployment platform, and whether an email service is already configured.
  3. If MAILER_URL and MAILER_API_KEY already exist, create a small server-only mailer module and integrate it at the requested email call site.
  4. If no MAILER_URL exists, explain that the SDK needs a deployed service. If the user wants this agent to provision it, follow Self-host the service; otherwise ask only for the existing service URL and API key.
  5. Ask the user only for values that cannot be safely discovered or generated: account logins, verified SES sender and region, AWS credentials, DATABASE_URL, QStash credentials, deployment access, and a recipient address for testing. Generate MAILER_API_KEY with a secure local command when one does not already exist.
  6. Keep all credentials server-side. Never create NEXT_PUBLIC_ versions of mailer, AWS, database, or QStash variables; never print secret values; never commit .env.local or any secret file.
  7. Use the existing application conventions for environment variables and server modules. Do not add a second mail client, duplicate environment variables, or a browser-side fetch when a server-side integration already exists.
  8. Use the category and props contracts below. Prefer magic_link for the first verification because it sends synchronously; use update or promotional when queued delivery is intended.
  9. Run the application's relevant typecheck, lint, and tests. Then run the authenticated health check and one test send. Do not claim setup is complete until both succeed, or clearly report the exact external step that remains.

The expected result in the user's application is:

  • oss-mailer installed in the correct dependency section
  • server-side MAILER_URL and MAILER_API_KEY variables
  • one reusable server-only client module
  • the requested email flow integrated with the correct category
  • a successful test send, or a precise explanation of what the user must still do

What you need

Before you start, create or have access to:

  • An AWS account with Amazon SES
  • A PostgreSQL database, such as Neon
  • An Upstash QStash account for queued promotional and update email
  • A deployment for the service, such as Vercel
  • Node.js 18 or newer

Prepare the account values

You do not need to understand the application code to prepare these values. Give the values to your agent through the project's secure environment, a password manager integration, or the prompts it provides. Do not put them in a chat message if your agent's transcript is retained.

| Account | One-time action | Value the agent needs | | --- | --- | --- | | AWS SES | Create and verify an email identity or domain in the same region you will use for sending. If the account is in sandbox mode, verify the test recipient too. | MAILER_FROM, SES_REGION | | AWS IAM | Create an access key for an identity that can call ses:SendEmail and ses:SendRawEmail. | SES_ACCESS_KEY_ID, SES_SECRET_ACCESS_KEY | | Neon | Create a PostgreSQL project and copy its connection string. | DATABASE_URL | | Upstash QStash | Create a QStash instance and copy its API URL and token. | QSTASH_URL, QSTASH_TOKEN | | Vercel | Sign in with vercel login, or connect the repository in the dashboard. | Deployment access |

The QStash signing keys can be retrieved after you have the token. An agent with permission to use that token can run:

curl --request GET \
  --url "https://qstash.upstash.io/v2/keys" \
  --header "Authorization: Bearer $QSTASH_TOKEN"

Copy the returned current value to QSTASH_CURRENT_SIGNING_KEY and the returned next value to QSTASH_NEXT_SIGNING_KEY. Keep all of these values secret.

Self-host the service

Clone the service repository and install its dependencies:

git clone https://github.com/DarrenJCoxon/oss-mailer.git
cd oss-mailer
npm install

Copy the example environment file:

cp .env.example .env.local

Generate a private API key for your service:

openssl rand -hex 32

Set the values in .env.local (or in your deployment provider's environment-variable settings):

| Variable | What to set | | --- | --- | | MAILER_API_KEY | A long, random secret. Your application will use the same value when calling the service. | | MAILER_FROM | The sender address, for example oss-mailer <[email protected]>. The address or domain must be verified in SES. | | SES_ACCESS_KEY_ID | An AWS access key with permission to send through SES. | | SES_SECRET_ACCESS_KEY | The matching AWS secret access key. Keep it private. | | SES_REGION | The AWS region where your SES identity is verified, for example eu-west-2. | | MAGIC_LINK_PROVIDER | ses | | PROMOTIONAL_PROVIDER | ses | | UPDATE_PROVIDER | ses | | DATABASE_URL | Your PostgreSQL connection string. | | QSTASH_URL | The QStash API URL from your QStash setup. | | QSTASH_TOKEN | Your QStash token. | | QSTASH_CURRENT_SIGNING_KEY | Your QStash current signing key. | | QSTASH_NEXT_SIGNING_KEY | Your QStash next signing key. | | DELIVER_URL | The public URL of the service's queue endpoint: https://your-mailer.example.com/api/queue/deliver. |

The service currently supports Amazon SES as its provider, so all three provider variables should be set to ses.

Verify the SES sender

In SES, verify the email address or domain used by MAILER_FROM. If your AWS account is still in the SES sandbox, the recipient address must also be verified before a test send will succeed.

Create the database schema

Run the migration against the database in DATABASE_URL:

npm run db:migrate

The migration is safe to run again; Drizzle records which migrations have already been applied. Run it from the cloned service directory with the same DATABASE_URL that the deployed service will use.

Deploy

Deploy the repository as a Next.js application. Vercel is the simplest option: import the GitHub repository, add the environment variables above, and deploy it.

Because DELIVER_URL contains the deployed URL, the usual order is:

  1. Deploy once with a temporary DELIVER_URL value.
  2. Copy the deployment's public URL.
  3. Set DELIVER_URL to <public-url>/api/queue/deliver.
  4. Redeploy so the new value is active.

Vercel CLI path

An AI agent can perform the deployment without using the dashboard once you have authenticated the Vercel CLI:

npm install --global vercel
vercel login
vercel link --yes
vercel deploy --prod

If the agent is setting deployment variables through the CLI, use the interactive vercel env add <NAME> production prompts or your team's approved secret-management workflow. Do not put secret values directly into shell commands, Git commits, or the README. Environment-variable changes apply to new deployments, so redeploy after adding or changing them.

For a new Vercel project, the agent should add each service variable to the Production environment before deploying. The following is the complete list; the vercel env add command prompts for the value without putting it in the command itself:

vercel env add MAILER_API_KEY production
vercel env add MAILER_FROM production
vercel env add SES_ACCESS_KEY_ID production
vercel env add SES_SECRET_ACCESS_KEY production
vercel env add SES_REGION production
vercel env add MAGIC_LINK_PROVIDER production
vercel env add PROMOTIONAL_PROVIDER production
vercel env add UPDATE_PROVIDER production
vercel env add DATABASE_URL production
vercel env add QSTASH_URL production
vercel env add QSTASH_TOKEN production
vercel env add QSTASH_CURRENT_SIGNING_KEY production
vercel env add QSTASH_NEXT_SIGNING_KEY production
vercel env add DELIVER_URL production

Use ses for the three provider prompts. For the first deployment, use a temporary value for DELIVER_URL; after Vercel prints the public URL, replace it with the real /api/queue/deliver URL and deploy again.

The first production deployment prints the public URL. The agent should then set DELIVER_URL to <public-url>/api/queue/deliver in the production environment and run vercel deploy --prod again. If you use a custom domain, use that stable domain in DELIVER_URL rather than a temporary Vercel deployment URL.

Dashboard path

If you prefer the Vercel dashboard, import DarrenJCoxon/oss-mailer as a Next.js project, add the variables from the table above to the Production environment, and deploy. Then update DELIVER_URL with the deployed URL and redeploy. The agent can still run the migration and verification commands locally while you complete these dashboard steps.

After deployment, save these two values for your application:

  • MAILER_URL: the service's public base URL, such as https://your-mailer.vercel.app
  • MAILER_API_KEY: the same secret configured on the service

You can inspect the service configuration at /settings. Keep the API key and AWS/QStash credentials server-side; never expose them as NEXT_PUBLIC_ variables or commit them to Git.

Verify the deployment before integrating the SDK

Run these checks from a trusted terminal. Replace the placeholders locally; do not paste real secrets into documentation or chat transcripts:

export MAILER_URL="https://your-mailer.vercel.app"
export MAILER_API_KEY="your-service-api-key"

curl -fsS \
  -H "Authorization: Bearer $MAILER_API_KEY" \
  "$MAILER_URL/health"

curl -fsS -X POST "$MAILER_URL/api/send" \
  -H "Authorization: Bearer $MAILER_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "category": "magic_link",
    "to": "[email protected]",
    "subject": "oss-mailer test",
    "props": { "url": "https://example.com/verify" }
  }'

The health request should return the configuration page, and the send request should return HTTP 200 with a message ID. Use a recipient verified in SES while the AWS account is in sandbox mode. This direct request is also a useful fallback when an agent needs to distinguish a mailer-service problem from an application-integration problem.

Configure the installed SDK

After installing the package, set the service URL and API key in your application's server-side environment:

MAILER_URL=https://your-mailer.vercel.app
MAILER_API_KEY=your-service-api-key

These variables belong to your application, not to the oss-mailer package. Do not put them in browser code.

Send your first email

Create the client once in server-side application code:

import { createMailerClient } from 'oss-mailer'

const mailer = createMailerClient({
  url: process.env.MAILER_URL!,
  apiKey: process.env.MAILER_API_KEY!,
})

const result = await mailer.sendMail({
  category: 'magic_link',
  to: '[email protected]',
  subject: 'Sign in to your account',
  props: {
    url: 'https://app.example.com/auth/verify?token=abc123',
  },
})

console.log(result)

magic_link sends immediately. promotional and update messages are queued through QStash and return a queue job ID.

Email categories

Magic links

The built-in template expects a url:

await mailer.sendMail({
  category: 'magic_link',
  to: '[email protected]',
  subject: 'Sign in to your account',
  props: { url: 'https://app.example.com/auth/verify?token=abc123' },
})

Product updates

The built-in update template expects subject, body, and unsubscribeUrl in props:

await mailer.sendMail({
  category: 'update',
  to: '[email protected]',
  subject: 'Your weekly update',
  props: {
    subject: 'Your weekly update',
    body: 'Here is what changed this week.',
    unsubscribeUrl: 'https://app.example.com/email/preferences',
  },
})

Promotional email

The built-in promotional template uses the same props as update:

await mailer.sendMail({
  category: 'promotional',
  to: '[email protected]',
  subject: 'What is new',
  props: {
    subject: 'What is new',
    body: 'Read about our latest improvements.',
    unsubscribeUrl: 'https://app.example.com/email/preferences',
  },
})

For any category, you can provide pre-rendered HTML instead:

props: { html: '<p>Your email content</p>' }

NextAuth v5

Use the included provider in your auth.ts:

import NextAuth from 'next-auth'
import { MailerEmailProvider } from 'oss-mailer/nextauth'

export const { handlers, auth } = NextAuth({
  providers: [
    MailerEmailProvider({
      mailerUrl: process.env.MAILER_URL!,
      apiKey: process.env.MAILER_API_KEY!,
      from: '[email protected]',
      appName: 'My App',
    }),
  ],
})

The actual sender is the MAILER_FROM value configured on the mailer service.

Responses and errors

An immediate send returns { success: true, messageId, provider, sentAt }. A queued send returns { queued: true, jobId }.

import { createMailerClient, isMailerError } from 'oss-mailer'

try {
  await mailer.sendMail({
    category: 'magic_link',
    to: '[email protected]',
    subject: 'Sign in',
    props: { url: 'https://example.com/verify' },
  })
} catch (error) {
  if (isMailerError(error)) {
    console.error(error.code, error.detail)
  }
}

Troubleshooting

  • 401 Unauthorized: MAILER_API_KEY in your application does not exactly match the key on the deployed service.
  • SES rejects the message as “not verified”: verify MAILER_FROM and, in SES sandbox mode, the recipient address.
  • Queued messages fail: check QSTASH_TOKEN, both QStash signing keys, and that DELIVER_URL is public and ends with /api/queue/deliver.
  • Configuration is missing: open the service's /settings page, add the missing deployment variables, and redeploy.

API reference

The client sends authenticated POST requests to <MAILER_URL>/api/send with this JSON shape:

{
  "category": "magic_link",
  "to": "[email protected]",
  "subject": "Sign in",
  "props": { "url": "https://example.com/verify" }
}

Authentication uses Authorization: Bearer <MAILER_API_KEY>.