New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@impruthvi/nodemail

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@impruthvi/nodemail

A unified mail service for Node.js/TypeScript with Laravel-like simplicity. Support for multiple providers (SMTP, SendGrid, AWS SES, Mailgun, Resend, Postmark) and template engines (Handlebars, EJS, Pug) - just change environment variables, no code change

latest
Source
npmnpm
Version
1.1.6
Version published
Maintainers
1
Created
Source

@impruthvi/nodemail

npm version License: MIT TypeScript Tests Coverage Documentation

@impruthvi/nodemail brings the simplicity and elegance of Laravel's Mail system to the Node.js ecosystem with full TypeScript support.

🎯 Vision

A lightweight, developer-friendly email library where you can:

  • Switch email providers by just changing environment variables
  • Use elegant, class-based Mailable patterns
  • Keep your package lightweight (install only what you need)
  • Write clean, maintainable email code

Inspired by Laravel's Mail system.

✨ Features

✅ Available Now (v1.1.0)

  • 🎯 Multiple Providers - SMTP (Nodemailer), SendGrid, AWS SES, Mailgun, Resend, Postmark
  • 🎨 Template Engines - Handlebars, EJS, Pug support with dynamic loading
  • 📝 Mailable Classes - Reusable email definitions with template support
  • 📋 Markdown Mail - Write emails in Markdown with components (button, panel, table)
  • 📦 Queue Support - Background email sending with Bull/BullMQ
  • 🔄 Provider Failover - Automatic failover chain with retries, delays, and callbacks
  • 🔔 Email Events - sending, sent, failed lifecycle hooks for logging, analytics, and cancellation
  • 🔍 Email Preview - Preview rendered emails without sending (debug templates, verify headers)
  • ⏱️ Rate Limiting - Per-provider rate limiting with sliding window algorithm
  • 🧪 Testing Utilities - Mail::fake() for testing (Laravel-style assertions)
  • 🎨 CLI Tools - Queue management, email preview, code generation, config validation
  • 🪶 Lightweight - Only ~25MB with SMTP, install additional providers as needed
  • 🔒 Type-Safe - Full TypeScript support with strict typing
  • Complete Fluent API - Chain to(), subject(), html(), template(), data(), cc(), bcc(), attachments(), headers()
  • Dynamic Loading - Providers and templates loaded only when installed (peerDependencies)
  • 🛡️ Error Handling - Graceful degradation with helpful error messages

🚧 Coming Soon

  • 🔔 Notifications - Multi-channel notification system
  • 🌍 i18n Support - Multi-language emails
  • 🚀 More Providers - Mailtrap and others

📦 Installation

npm install @impruthvi/nodemail

Or install a specific version:

npm install @impruthvi/nodemail@1.1.0

Lightweight by default! Only includes SMTP support (~25MB).

Adding Providers (Optional)

Currently Supported:

# SendGrid (✅ Implemented)
npm install @sendgrid/mail

# AWS SES (✅ Implemented)
npm install @aws-sdk/client-ses

# Mailgun (✅ Implemented)
npm install mailgun.js form-data

# Resend (✅ Implemented)
npm install resend

# Postmark (✅ Implemented)
npm install postmark

Adding Template Engines (Optional)

Currently Supported:

# Handlebars (✅ Implemented)
npm install handlebars

# EJS (✅ Implemented)
npm install ejs

# Pug (✅ Implemented)
npm install pug

Adding Markdown Mail Support (Optional)

npm install marked juice

🚀 Quick Start

SMTP (Nodemailer)

import { Mail } from 'nodemail';

Mail.configure({
  default: 'smtp',
  from: {
    address: 'noreply@example.com',
    name: 'My App',
  },
  mailers: {
    smtp: {
      driver: 'smtp',
      host: process.env.SMTP_HOST,
      port: 587,
      auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS,
      },
    },
  },
});

// Send emails
await Mail.to('user@example.com').subject('Welcome!').html('<h1>Hello World!</h1>').send();

SendGrid

// npm install @sendgrid/mail
import { Mail } from '@impruthvi/nodemail';

Mail.configure({
  default: 'sendgrid',
  from: { address: 'noreply@example.com', name: 'My App' },
  mailers: {
    sendgrid: {
      driver: 'sendgrid',
      apiKey: process.env.SENDGRID_API_KEY,
    },
  },
});

AWS SES

// npm install @aws-sdk/client-ses
import { Mail } from '@impruthvi/nodemail';

Mail.configure({
  default: 'ses',
  from: { address: 'noreply@example.com', name: 'My App' },
  mailers: {
    ses: {
      driver: 'ses',
      region: 'us-east-1',
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    },
  },
});

Mailgun

// npm install mailgun.js form-data
import { Mail } from '@impruthvi/nodemail';

Mail.configure({
  default: 'mailgun',
  from: { address: 'noreply@yourdomain.com', name: 'My App' },
  mailers: {
    mailgun: {
      driver: 'mailgun',
      domain: process.env.MAILGUN_DOMAIN,
      apiKey: process.env.MAILGUN_API_KEY,
      region: 'us', // or 'eu'
    },
  },
});

Resend

// npm install resend
import { Mail } from '@impruthvi/nodemail';

Mail.configure({
  default: 'resend',
  from: { address: 'noreply@yourdomain.com', name: 'My App' },
  mailers: {
    resend: {
      driver: 'resend',
      apiKey: process.env.RESEND_API_KEY,
    },
  },
});

Postmark

// npm install postmark
import { Mail } from '@impruthvi/nodemail';

Mail.configure({
  default: 'postmark',
  from: { address: 'noreply@yourdomain.com', name: 'My App' },
  mailers: {
    postmark: {
      driver: 'postmark',
      serverToken: process.env.POSTMARK_SERVER_TOKEN,
    },
  },
});

🎨 Template Engines

Using Handlebars

// npm install handlebars
import { Mail } from '@impruthvi/nodemail';

Mail.configure({
  default: 'smtp',
  from: { address: 'noreply@example.com', name: 'My App' },
  mailers: {
    /* your mailer config */
  },
  templates: {
    engine: 'handlebars',
    viewsPath: './views/emails',
    extension: '.hbs',
    cache: true,
  },
});

// Send with template
await Mail.to('user@example.com')
  .subject('Welcome!')
  .template('welcome')
  .data({ name: 'John', appName: 'My App' })
  .send();

Template file (views/emails/welcome.hbs):

<h1>Welcome, {{name}}!</h1>
<p>Thank you for joining {{appName}}.</p>

Using EJS

// npm install ejs
Mail.configure({
  templates: {
    engine: 'ejs',
    viewsPath: './views/emails',
    extension: '.ejs',
  },
});

await Mail.to('customer@example.com')
  .subject('Your Invoice')
  .template('invoice')
  .data({ items: [...], total: 99.99 })
  .send();

Using Pug

// npm install pug
Mail.configure({
  templates: {
    engine: 'pug',
    viewsPath: './views/emails',
    cache: true,
  },
});

await Mail.to('user@example.com')
  .subject('Notification')
  .template('notification')
  .data({ title: 'Update', message: 'New features!' })
  .send();

📋 Markdown Mail

Write beautiful emails in Markdown with built-in components. Requires npm install marked juice.

MarkdownMailable

import { MarkdownMailable, Mail } from '@impruthvi/nodemail';

class WelcomeEmail extends MarkdownMailable {
  constructor(
    private user: { name: string },
    private appName: string
  ) {
    super();
  }

  build(): this {
    return this.subject(`Welcome to ${this.appName}!`)
      .from('noreply@example.com')
      .markdown(
        `# Welcome, {{name}}!

Thank you for joining **{{appName}}**.

[button url="https://example.com/start" color="primary"]Get Started[/button]

[panel]Need help? Contact support@example.com[/panel]`,
        {
          name: this.user.name,
          appName: this.appName,
        }
      );
  }
}

await Mail.to('user@example.com').send(new WelcomeEmail(user, 'My App'));

Components

Button - Call-to-action buttons with color variants:

[button url="https://example.com" color="primary"]Click Here[/button]
[button url="https://example.com" color="success"]Confirm[/button]
[button url="https://example.com" color="error"]Delete[/button]

Panel - Bordered callout sections:

[panel]
**Important:** This is a highlighted notice.
[/panel]

Table - Styled table wrapper:

[table]
| Name | Price |
|-------|--------|
| Item | $9.99 |
[/table]

Custom Themes

class BrandedEmail extends MarkdownMailable {
  build(): this {
    return this.subject('Update').markdown('# News\n\nLatest updates...').theme({
      css: 'h1 { color: #e94560; } .button-primary { background: #e94560; }',
      headerHtml: '<img src="https://example.com/logo.png" alt="Logo">',
      footerHtml: '<p>&copy; 2026 Company</p>',
    });
  }
}

Markdown Configuration

Mail.configure({
  // ... mailer config
  markdown: {
    theme: {
      css: '/* custom global CSS */',
      headerHtml: '<img src="logo.png">',
      footerHtml: '<p>Footer</p>',
    },
    customCss: '.button { border-radius: 8px; }',
  },
});

📦 Queue Support

Send emails in the background with Bull or BullMQ. Requires npm install bullmq (or bull).

Mail.configure({
  // ... mailer config
  queue: {
    driver: 'bullmq',
    connection: { host: 'localhost', port: 6379 },
    retries: 3,
    backoff: { type: 'exponential', delay: 1000 },
  },
});

// Queue immediately
await Mail.to('user@example.com').subject('Welcome!').html('<h1>Welcome!</h1>').queue();

// Delayed sending (60 seconds)
await Mail.to('user@example.com').later(60, new WelcomeEmail(user));

// Scheduled delivery
await Mail.to('user@example.com').at(new Date('2026-12-25'), new ChristmasEmail());

// Process queued emails (in worker)
await Mail.processQueue();

🎨 CLI Tools

The CLI provides commands for queue management, email preview, code generation, and configuration validation.

Quick Reference

# Queue management
npx nodemail queue:work              # Start processing queued emails
npx nodemail queue:status            # Show queue job counts
npx nodemail queue:clear --status failed   # Clear failed jobs
npx nodemail queue:retry             # Retry failed jobs

# Email preview and testing
npx nodemail preview --mailable ./src/mail/WelcomeEmail.ts
npx nodemail send:test --to you@example.com

# Code generation
npx nodemail make:mailable WelcomeEmail
npx nodemail make:mailable NewsletterEmail --markdown

# Configuration
npx nodemail config:check            # Validate configuration
npx nodemail config:check --test     # Validate and test connections

Configuration File

Create a nodemail.config.ts in your project root:

import { defineConfig } from '@impruthvi/nodemail';

export default defineConfig({
  default: 'smtp',
  from: { address: 'noreply@example.com', name: 'My App' },
  mailers: {
    smtp: {
      driver: 'smtp',
      host: process.env.SMTP_HOST,
      port: 587,
      auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
    },
  },
  queue: {
    driver: 'bullmq',
    connection: { host: 'localhost', port: 6379 },
  },
});

For styled terminal output, install chalk: npm install chalk

🔄 Provider Failover

Automatically fail over to backup providers when the primary provider fails. Supports retries, delays, and monitoring callbacks.

Global Failover Configuration

Mail.configure({
  default: 'smtp',
  from: { address: 'noreply@example.com', name: 'My App' },
  mailers: {
    smtp: {
      driver: 'smtp',
      host: process.env.SMTP_HOST,
      port: 587,
      auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
    },
    sendgrid: {
      driver: 'sendgrid',
      apiKey: process.env.SENDGRID_API_KEY,
    },
    ses: {
      driver: 'ses',
      region: 'us-east-1',
      accessKeyId: process.env.AWS_ACCESS_KEY_ID,
      secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    },
  },
  failover: {
    chain: ['sendgrid', 'ses'],
    maxRetriesPerProvider: 2,
    retryDelay: 1000,
    failoverDelay: 500,
  },
});

// Sends via SMTP first; if SMTP fails (after 2 retries), tries SendGrid, then SES
await Mail.to('user@example.com').subject('Hello!').html('<h1>Hello!</h1>').send();

Per-mailer Failover Override

Override the global failover config for a specific mailer:

Mail.configure({
  default: 'smtp',
  mailers: {
    smtp: {
      driver: 'smtp',
      host: process.env.SMTP_HOST,
      port: 587,
      auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
      failover: {
        chain: ['postmark'], // Only fail over to Postmark for SMTP
        maxRetriesPerProvider: 3,
      },
    },
    postmark: {
      driver: 'postmark',
      serverToken: process.env.POSTMARK_SERVER_TOKEN,
    },
  },
});

onFailover Callback

Monitor failover events for logging or alerting:

Mail.configure({
  // ... mailer config
  failover: {
    chain: ['sendgrid', 'ses'],
    onFailover: (event) => {
      console.log(`Failover: ${event.failedMailer}${event.nextMailer}`);
      console.log(`Error: ${event.error}`);
      console.log(`Attempt: ${event.attemptIndex}, Time: ${event.timestamp}`);
    },
  },
});

Response Metadata

After sending, the response includes failover details:

const result = await Mail.to('user@example.com').subject('Hello!').html('<h1>Hello!</h1>').send();

console.log(result.provider); // 'sendgrid' (which provider actually sent)
console.log(result.failoverUsed); // true (failover was triggered)
console.log(result.failoverAttempts); // Array of FailoverDetail objects

FailoverConfig Reference

PropertyTypeDefaultDescription
chainstring[](required)Ordered list of backup mailer names
maxRetriesPerProvidernumber1Retries per provider before moving to the next
retryDelaynumber0Delay (ms) between retries on the same provider
failoverDelaynumber0Delay (ms) before switching to the next provider
onFailover(event: FailoverEvent) => voidCallback fired on each failover transition

🔔 Email Events

Hook into the email lifecycle for logging, analytics, or to modify/cancel emails before sending.

// Log all outgoing emails
Mail.onSending((event) => {
  console.log(`Sending to ${event.options.to} via ${event.mailer}`);
  // Modify options before send
  event.options.headers = { ...event.options.headers, 'X-Tracking': '123' };
});

// Log successful deliveries
Mail.onSent((event) => {
  console.log(`Sent! ID: ${event.response.messageId}`);
});

// Log failures
Mail.onFailed((event) => {
  console.error(`Failed: ${event.error}`);
});

// Cancel a send by returning false
Mail.onSending((event) => {
  if (event.options.to === 'blocked@example.com') return false;
});

// Remove all listeners
Mail.clearListeners();

Event Methods

MethodDescription
Mail.onSending(listener)Register listener before send (can cancel with return false, can mutate event.options)
Mail.onSent(listener)Register listener after successful send
Mail.onFailed(listener)Register listener on send failure
Mail.clearListeners()Remove all event listeners

Events work in both real and fake mode. Listener errors are silently caught and never break email delivery. See docs/email-events.md for the full guide.

🔍 Email Preview

Preview emails without sending — useful for debugging templates, verifying headers, and building preview UIs.

// Preview via fluent builder
const preview = await Mail.to('user@example.com')
  .subject('Hello')
  .html('<p>Hi</p>')
  .priority('high')
  .preview();

console.log(preview.html); // '<p>Hi</p>'
console.log(preview.headers); // { 'X-Priority': '1', ... }

// Preview a Mailable
const preview = await Mail.preview(new WelcomeMail().to('user@example.com'));

Preview applies full preprocessing (markdown, templates, priority headers) but fires no events and stores no messages. Works in both real and fake mode. See docs/email-preview.md for the full guide.

⏱️ Rate Limiting

Per-provider rate limiting to prevent exceeding email provider API limits. Uses an in-memory sliding window algorithm.

// Global rate limit (applies to all mailers)
Mail.configure({
  default: 'smtp',
  from: { address: 'noreply@example.com', name: 'App' },
  mailers: {
    smtp: { driver: 'smtp', host: 'localhost', port: 587 },
  },
  rateLimit: { maxPerWindow: 100, windowMs: 60000 },
});

// Per-mailer override (takes precedence over global)
Mail.configure({
  default: 'smtp',
  from: { address: 'noreply@example.com', name: 'App' },
  mailers: {
    smtp: {
      driver: 'smtp',
      host: 'localhost',
      port: 587,
      rateLimit: { maxPerWindow: 10, windowMs: 1000 },
    },
    sendgrid: {
      driver: 'sendgrid',
      apiKey: '...',
      rateLimit: { maxPerWindow: 100, windowMs: 1000 },
    },
  },
});

// When exceeded — returns { success: false }, no throw
const result = await Mail.to('user@example.com').subject('Hi').html('<p>Hi</p>').send();
// result = { success: false, error: 'Rate limit exceeded for mailer "smtp". Try again in 450ms.' }

// Optional callback
Mail.configure({
  rateLimit: {
    maxPerWindow: 10,
    windowMs: 1000,
    onRateLimited: (event) => {
      console.log(`Rate limited on ${event.mailer}, retry in ${event.retryAfterMs}ms`);
    },
  },
});

Rate-limited sends don't fire sending/sent/failed events. See docs/rate-limiting.md for the full guide.

📨 Complete Fluent API

await Mail.to('user@example.com')
  .subject('Complete Example')
  .html('<h1>Hello!</h1>')
  .text('Hello!')
  .from('custom@example.com')
  .cc(['manager@example.com', 'team@example.com'])
  .bcc('archive@example.com')
  .replyTo('support@example.com')
  .attachments([
    { filename: 'report.pdf', path: './files/report.pdf' },
    { filename: 'image.png', content: buffer },
  ])
  .priority('high')
  .headers({ 'X-Custom-Header': 'value' })
  .send();

📝 Mailable Classes

Create reusable email classes with Laravel-like syntax:

import { Mailable } from '@impruthvi/nodemail';

class WelcomeEmail extends Mailable {
  constructor(
    private user: { name: string; email: string },
    private appName: string
  ) {
    super();
  }

  build() {
    return this.subject(`Welcome to ${this.appName}!`).view('welcome', {
      name: this.user.name,
      email: this.user.email,
      appName: this.appName,
    });
  }
}

// Method 1: Laravel-style (recommended)
await Mail.to('user@example.com').send(new WelcomeEmail(user, 'My App'));

// Method 2: Direct sending
await new WelcomeEmail(user, 'My App').to('user@example.com').send();

🧪 Testing with Mail::fake()

Test your emails without actually sending them - just like Laravel's Mail::fake():

import { Mail, Mailable } from '@impruthvi/nodemail';

// Your Mailable class
class WelcomeEmail extends Mailable {
  constructor(public userName: string) {
    super();
  }

  build() {
    return this.subject(`Welcome, ${this.userName}!`).html(`<h1>Hello ${this.userName}!</h1>`);
  }
}

// In your tests
describe('User Registration', () => {
  beforeEach(() => {
    Mail.fake(); // Enable fake mode
  });

  afterEach(() => {
    Mail.restore(); // Restore real mailer
  });

  it('sends welcome email on registration', async () => {
    // Your application code that sends email
    await Mail.to('user@example.com').send(new WelcomeEmail('John'));

    // Assert email was sent
    Mail.assertSent(WelcomeEmail);

    // Assert with conditions
    Mail.assertSent(WelcomeEmail, (mail) => {
      return mail.hasTo('user@example.com') && mail.subjectContains('Welcome');
    });

    // Assert sent count
    Mail.assertSentCount(WelcomeEmail, 1);

    // Assert other mailables were NOT sent
    Mail.assertNotSent(PasswordResetEmail);
  });

  it('does not send email when validation fails', async () => {
    // Code that doesn't send email
    Mail.assertNothingSent();
  });
});

Available Assertions

MethodDescription
Mail.fake()Enable fake mode (store emails instead of sending)
Mail.restore()Restore real mailer
Mail.assertSent(Mailable)Assert mailable was sent
Mail.assertSent(Mailable, callback)Assert with custom conditions
Mail.assertSentCount(Mailable, count)Assert sent exactly N times
Mail.assertNotSent(Mailable)Assert mailable was NOT sent
Mail.assertNothingSent()Assert no emails were sent
Mail.assertQueued(Mailable)Assert mailable was queued
Mail.assertNothingQueued()Assert nothing was queued
Mail.sent()Get all sent messages
Mail.sent(Mailable)Get sent messages of specific type
Mail.hasSent()Check if any messages were sent
Mail.hasQueued()Check if any messages were queued
Mail.simulateFailures(n)Simulate failures for the first N sends
Mail.resetFailures()Clear failure simulation state

AssertableMessage Methods

When inspecting sent messages, you can use these helper methods:

const sent = Mail.sent(WelcomeEmail)[0];

// Check recipients
sent.hasTo('user@example.com'); // Check TO
sent.hasCc('cc@example.com'); // Check CC
sent.hasBcc('bcc@example.com'); // Check BCC

// Check content
sent.hasSubject('Welcome!'); // Exact subject match
sent.subjectContains('Welcome'); // Subject contains
sent.htmlContains('Hello'); // HTML contains
sent.textContains('Hello'); // Plain text contains

// Check markdown
sent.isMarkdown(); // Was built from markdown
sent.getMarkdown(); // Get raw markdown source
sent.markdownContains('[button'); // Markdown source contains

// Check failover
sent.wasFailoverUsed(); // Whether failover was triggered
sent.getProvider(); // Provider that actually sent
sent.getFailoverAttempts(); // Array of FailoverDetail objects

// Check attachments
sent.hasAttachments(); // Has any attachments
sent.hasAttachment('file.pdf'); // Has specific attachment

// Check priority
sent.hasPriority('high'); // Has specific priority
sent.getPriority(); // Get priority level

// Check headers
sent.hasHeader('X-Custom'); // Has header
sent.hasHeader('X-Custom', 'value'); // Header with value

// Get values
sent.getTo(); // Get recipients array
sent.getSubject(); // Get subject
sent.getHtml(); // Get HTML content

🛠️ Current Status

Phase 1: Project Setup ✅ Complete

  • TypeScript 5.6 configuration
  • ESLint 9 (flat config)
  • Modern tooling setup
  • Package structure
  • Core type definitions
  • Lightweight architecture (peerDependencies)

Phase 2: Core Implementation ✅ Complete

  • ✅ Mail Manager & Facade
  • ✅ SMTP Provider (nodemailer)
  • ✅ SendGrid Provider (@sendgrid/mail)
  • ✅ AWS SES Provider (@aws-sdk/client-ses)
  • ✅ Message builder with complete fluent API
  • ✅ Configuration system
  • ✅ Error handling & graceful degradation

Phase 3: Additional Providers ✅ Complete

  • ✅ Mailgun Provider (mailgun.js)
  • ✅ Resend Provider (resend)
  • ✅ Postmark Provider (postmark)
  • ✅ Dynamic loading for all providers
  • ✅ Comprehensive provider tests

Phase 4: Template Engines & Mailable ✅ Complete

  • ✅ Template engines (Handlebars, EJS, Pug)
  • ✅ Laravel-like Mailable classes with template support
  • ✅ Complete fluent API (cc, bcc, replyTo, attachments, headers)
  • ✅ Dynamic template loading with caching

Phase 5: Testing Utilities ✅ Complete (v0.5.0)

  • ✅ Mail::fake() for testing
  • ✅ assertSent(), assertNotSent(), assertNothingSent()
  • ✅ assertQueued(), assertNothingQueued()
  • ✅ AssertableMessage with inspection methods

Phase 6: Queue Management ✅ Complete (v0.6.0)

  • ✅ QueueManager with Bull and BullMQ drivers
  • ✅ Immediate, delayed, and scheduled sending
  • ✅ Automatic retries with configurable backoff
  • ✅ MailFake queue assertion support

Phase 7: Markdown Mail ✅ Complete (v0.7.0)

  • ✅ MarkdownMailable base class
  • ✅ MarkdownRenderer with CSS inlining
  • ✅ Components: button, panel, table
  • ✅ Default responsive email theme
  • ✅ Custom themes and CSS support
  • ✅ AssertableMessage markdown assertions

Phase 8: Provider Failover ✅ Complete (v1.0.0)

  • ✅ FailoverManager with automatic provider chain
  • ✅ Configurable retries per provider (maxRetriesPerProvider)
  • ✅ Retry and failover delays (retryDelay, failoverDelay)
  • onFailover callback for monitoring/logging
  • ✅ Per-mailer failover overrides
  • ✅ MailFake simulateFailures() / resetFailures() for testing
  • ✅ Response metadata: provider, failoverUsed, failoverAttempts
  • ✅ 269 passing tests

Post v1.0.0: Incremental Features ✅ Complete (v1.0.1)

  • ✅ Embedded Images (CID support) for inline images in HTML
  • ✅ Email Priority Levels (high, normal, low) with X-Priority headers
  • ✅ Email Events System (sending, sent, failed lifecycle hooks)
  • ✅ Email Preview — render emails without sending (debug templates, verify headers)
  • ✅ Rate Limiting — per-provider sliding window algorithm
  • ✅ 522 passing tests

Phase 9: Enhanced CLI ✅ Complete (v1.1.0)

  • ✅ CLI tool with 8 commands for queue management, email preview, and code generation
  • queue:work - Start processing queued emails with concurrency control
  • queue:status - Show queue job counts
  • queue:clear - Clear jobs by status (completed, failed, delayed, waiting)
  • queue:retry - Retry failed jobs with optional limit
  • preview - Preview email in browser without sending
  • send:test - Send test email to verify configuration
  • make:mailable - Generate Mailable class (with markdown/template options)
  • config:check - Validate configuration with optional connection testing
  • defineConfig helper for TypeScript autocomplete in config files
  • ✅ Auto-detection of nodemail.config.ts/js config files

Phase 10+ 🚧 Coming Soon

  • 🔔 Notifications - Multi-channel notification system
  • 🌍 i18n Support - Multi-language emails
  • 🚀 More Providers - Mailtrap and others

🤝 Contributing

This project is in early development. Contributions, ideas, and feedback are welcome!

  • Fork the repository
  • Create your feature branch (git checkout -b feature/amazing-feature)
  • Commit your changes (git commit -m 'Add some amazing feature')
  • Push to the branch (git push origin feature/amazing-feature)
  • Open a Pull Request

Development Setup

# Clone the repository
git clone https://github.com/impruthvi/nodemail.git
cd nodemail

# Install dependencies
npm install

# Build
npm run build

# Lint
npm run lint

# Format code
npm run format

💡 Why nodemail?

Inspired by Laravel, Built for Node.js

If you've used Laravel's Mail system, you know how elegant it is:

// Laravel (PHP)
Mail::to($user->email)->send(new WelcomeEmail($user));

@impruthvi/nodemail brings this same elegance to Node.js/TypeScript:

// @impruthvi/nodemail (TypeScript)
await Mail.to(user.email).send(new WelcomeEmail(user));

Lightweight by Design

Unlike other packages that bundle everything:

  • Base package: ~25MB (SMTP only)
  • Add providers as needed: npm install @sendgrid/mail
  • No bloat: Only install what you use

📊 Package Philosophy

  • Modular: Install only the providers you need
  • Type-Safe: Full TypeScript support with strict typing
  • Developer-Friendly: Clean, intuitive API
  • Production-Ready: Built with best practices
  • Well-Tested: 269 passing tests with 85%+ coverage

📄 License

MIT © Pruthvi

🙏 Acknowledgments

Inspired by Laravel's Mail system - bringing elegant email handling to Node.js.

📞 Support & Community

📦 Postinstall Message

After installation, nodemail displays a short thank-you message in your terminal. To suppress it, set one of these environment variables:

# Disable the postinstall message
NODEMAIL_NO_POSTINSTALL=1 npm install @impruthvi/nodemail

# Also auto-suppressed in CI environments (CI, GITHUB_ACTIONS, TRAVIS, etc.)

⭐ If you like this idea, please star the repo! It helps gauge interest and motivates development.

🚀 Want to contribute? Check out the issues labeled good first issue or help wanted.

Keywords

email

FAQs

Package last updated on 09 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts