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

@kandleconsultinggroup/email-blaster

v0.1.3

Published

Production-ready email blast system with queue management, templates, and unsubscribe handling.

Downloads

427

Readme

@kandleconsultinggroup/email-blaster

Production-ready email blast system with queue management, templates, and unsubscribe handling.

Features

  • ✉️ Email blast campaigns with draft/send workflow
  • 📝 Reusable email templates with token replacement
  • 🚫 Automatic unsubscribe management
  • 📊 Send logs and tracking
  • ⚡ Optional Redis queue for rate limiting
  • 🔌 Multi-provider support (SendGrid, AWS SES, SMTP)
  • 🎨 Token replacement ({{firstName}}, {{companyName}}, etc.)

Installation

npm install @kandleconsultinggroup/email-blaster mongoose express
npm install ioredis --save-optional  # Optional for queue

Quick Start

const express = require("express");
const mongoose = require("mongoose");
const {
  initMailBlaster,
  routes,
} = require("@kandleconsultinggroup/email-blaster");

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

// Connect MongoDB
mongoose.connect(process.env.MONGODB_URI);

// Initialize email blaster
initMailBlaster({
  mongoUri: process.env.MONGODB_URI,
  provider: "nodemailer",
  rateLimit: { perMinute: 30 },
  unsubscribe: {
    enabled: true,
    baseUrl: "http://localhost:3000",
  },
  nodemailer: {
    host: "smtp.gmail.com",
    port: 587,
    user: "[email protected]",
    pass: "your-app-password",
  },
});

// Mount routes
app.use("/api/email/blasts", routes.blasts);
app.use("/api/email/templates", routes.templates);
app.use("/api/email/unsubscribe", routes.unsubscribe);
app.use("/api/email/logs", routes.logs);

app.listen(3000);

API Endpoints

Email Blasts

Create Blast (Draft)

POST /api/email/blasts
Content-Type: application/json

{
  "subject": "Welcome to our platform!",
  "bodyHtml": "<h1>Hello {{firstName}}!</h1>",
  "sender": {
    "email": "[email protected]",
    "name": "Your App"
  },
  "recipients": [
    {
      "email": "[email protected]",
      "firstName": "John",
      "companyName": "Acme Corp"
    }
  ]
}

Get All Blasts

GET /api/email/blasts

Get Single Blast

GET /api/email/blasts/:id

Update Blast

PUT /api/email/blasts/:id
Content-Type: application/json

{
  "subject": "Updated subject"
}

Send Blast

POST /api/email/blasts/:id/send

Response:

{
  "queued": 100,
  "skipped": 5
}

Delete Blast

DELETE /api/email/blasts/:id

Templates

Create Template

POST /api/email/templates
Content-Type: application/json

{
  "name": "Welcome Email",
  "subject": "Welcome {{firstName}}!",
  "bodyHtml": "<h1>Hi {{firstName}}</h1>"
}

Get All Templates

GET /api/email/templates

Get Single Template

GET /api/email/templates/:id

Update Template

PUT /api/email/templates/:id

Delete Template

DELETE /api/email/templates/:id

Send Logs

Get All Logs

GET /api/email/logs
GET /api/email/logs?status=sent
GET /api/email/logs?blastId=123
GET /api/email/[email protected]

Get Logs for Blast

GET /api/email/logs/blast/:blastId

Unsubscribes

Public Unsubscribe (from email link)

GET /api/email/[email protected]

Admin: Get Unsubscribe List

GET /api/email/unsubscribe/list

Admin: Add to Unsubscribe List

POST /api/email/unsubscribe
Content-Type: application/json

{
  "email": "[email protected]"
}

Admin: Remove from Unsubscribe List

DELETE /api/email/unsubscribe/:email

Configuration

Required Options

initMailBlaster({
  provider: "sendgrid" | "ses" | "nodemailer",
  rateLimit: {
    perMinute: 30, // Required
    perDay: 10000, // Optional
  },
  unsubscribe: {
    enabled: true,
    baseUrl: "https://yourapp.com",
  },
});

Provider Configurations

SendGrid

initMailBlaster({
  provider: "sendgrid",
  sendgrid: {
    apiKey: process.env.SENDGRID_API_KEY,
  },
});

AWS SES

initMailBlaster({
  provider: "ses",
  ses: {
    region: "us-east-1",
    credentials: {
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    },
  },
});

SMTP (Nodemailer)

initMailBlaster({
  provider: "nodemailer",
  nodemailer: {
    host: "smtp.gmail.com",
    port: 587,
    secure: false,
    user: process.env.SMTP_USER,
    pass: process.env.SMTP_PASS,
  },
});

Optional: Redis Queue

For production deployments with high volume:

const Redis = require("ioredis");

initMailBlaster({
  // ...other config
  redis: new Redis({
    host: "localhost",
    port: 6379,
  }),
});

Token Replacement

Tokens in email templates are automatically replaced with recipient data:

{
  subject: "Hello {{firstName}}!",
  bodyHtml: "<p>Welcome to {{companyName}}</p>",
  recipients: [
    {
      email: "[email protected]",
      firstName: "John",
      companyName: "Acme Corp"
    }
  ]
}

Result: "Hello John!" and "Welcome to Acme Corp"

Workflow

  1. Create Blast - Save as draft with recipients
  2. Edit Blast - Modify subject, body, or recipients
  3. Send Blast - Trigger email sending
  4. View Logs - Track delivery status

Models

EmailBlast

  • subject: String
  • bodyHtml: String
  • sender: { email, name }
  • recipients: Array of { email, ...custom fields }
  • status: 'draft' | 'sent'
  • timestamps: createdAt, updatedAt

EmailTemplate

  • name: String
  • subject: String
  • bodyHtml: String
  • timestamps: createdAt, updatedAt

EmailSendLog

  • blastId: ObjectId
  • to: String
  • status: 'pending' | 'sent' | 'failed' | 'unsubscribed'
  • timestamps: createdAt, updatedAt

Unsubscribe

  • email: String (unique)
  • timestamps: createdAt, updatedAt

License

MIT