npm package: @kandleconsultinggroup/email-blaster
Description: Production-ready email blast system with queue management, templates, and unsubscribe handling.
Latest version: 0.1.3

# @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

```bash
npm install @kandleconsultinggroup/email-blaster mongoose express
npm install ioredis --save-optional  # Optional for queue
```

## Quick Start

```javascript
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: "your-email@gmail.com",
    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)

```http
POST /api/email/blasts
Content-Type: application/json

{
  "subject": "Welcome to our platform!",
  "bodyHtml": "<h1>Hello {{firstName}}!</h1>",
  "sender": {
    "email": "noreply@yourapp.com",
    "name": "Your App"
  },
  "recipients": [
    {
      "email": "user@example.com",
      "firstName": "John",
      "companyName": "Acme Corp"
    }
  ]
}
```

#### Get All Blasts

```http
GET /api/email/blasts
```

#### Get Single Blast

```http
GET /api/email/blasts/:id
```

#### Update Blast

```http
PUT /api/email/blasts/:id
Content-Type: application/json

{
  "subject": "Updated subject"
}
```

#### Send Blast

```http
POST /api/email/blasts/:id/send
```

Response:

```json
{
  "queued": 100,
  "skipped": 5
}
```

#### Delete Blast

```http
DELETE /api/email/blasts/:id
```

### Templates

#### Create Template

```http
POST /api/email/templates
Content-Type: application/json

{
  "name": "Welcome Email",
  "subject": "Welcome {{firstName}}!",
  "bodyHtml": "<h1>Hi {{firstName}}</h1>"
}
```

#### Get All Templates

```http
GET /api/email/templates
```

#### Get Single Template

```http
GET /api/email/templates/:id
```

#### Update Template

```http
PUT /api/email/templates/:id
```

#### Delete Template

```http
DELETE /api/email/templates/:id
```

### Send Logs

#### Get All Logs

```http
GET /api/email/logs
GET /api/email/logs?status=sent
GET /api/email/logs?blastId=123
GET /api/email/logs?email=user@example.com
```

#### Get Logs for Blast

```http
GET /api/email/logs/blast/:blastId
```

### Unsubscribes

#### Public Unsubscribe (from email link)

```http
GET /api/email/unsubscribe?email=user@example.com
```

#### Admin: Get Unsubscribe List

```http
GET /api/email/unsubscribe/list
```

#### Admin: Add to Unsubscribe List

```http
POST /api/email/unsubscribe
Content-Type: application/json

{
  "email": "user@example.com"
}
```

#### Admin: Remove from Unsubscribe List

```http
DELETE /api/email/unsubscribe/:email
```

## Configuration

### Required Options

```javascript
initMailBlaster({
  provider: "sendgrid" | "ses" | "nodemailer",
  rateLimit: {
    perMinute: 30, // Required
    perDay: 10000, // Optional
  },
  unsubscribe: {
    enabled: true,
    baseUrl: "https://yourapp.com",
  },
});
```

### Provider Configurations

#### SendGrid

```javascript
initMailBlaster({
  provider: "sendgrid",
  sendgrid: {
    apiKey: process.env.SENDGRID_API_KEY,
  },
});
```

#### AWS SES

```javascript
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)

```javascript
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:

```javascript
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:

```javascript
{
  subject: "Hello {{firstName}}!",
  bodyHtml: "<p>Welcome to {{companyName}}</p>",
  recipients: [
    {
      email: "john@example.com",
      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