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

@flusys/nestjs-email

v4.1.1

Published

Modular email package with SMTP, SendGrid, and Mailgun providers

Readme

@flusys/nestjs-email

Production-grade email management for NestJS — multi-provider (SMTP, SendGrid, Mailgun), database-driven template engine with {{variable}} interpolation, company scoping, and multi-tenant support.

npm version License: MIT NestJS TypeScript Node.js


Table of Contents


Overview

@flusys/nestjs-email provides a complete email management system. Email provider configurations and templates are stored in the database — no code changes are needed to add new email templates or switch providers. Providers are loaded dynamically, so you only install the SDK for the providers you use.


Features

  • Multi-provider — SMTP (nodemailer), SendGrid, Mailgun with a pluggable custom provider interface
  • Database-driven templates — Templates stored in PostgreSQL with {{variable}} interpolation
  • HTML XSS protection — All variable values are HTML-escaped before interpolation
  • Provider caching — SHA-256 config hash prevents duplicate provider instances
  • Test email — Verify a provider configuration before using it in production
  • Company scoping — Optional companyId on configs and templates for multi-company setups
  • Multi-tenant — Per-tenant DataSource isolation via the DataSource Provider pattern
  • Attachments — Base64-encoded file attachments supported

Compatibility

| Package | Version | |---------|---------| | @flusys/nestjs-core | ^4.0.0 | | @flusys/nestjs-shared | ^4.0.0 | | nodemailer | ^6.0.0 | | @sendgrid/mail | ^8.0.0 (optional) | | mailgun.js | ^10.0.0 (optional) | | Node.js | >= 18.x |


Installation

npm install @flusys/nestjs-email @flusys/nestjs-shared @flusys/nestjs-core

# Provider-specific SDKs (install only what you use)
npm install nodemailer                   # SMTP (recommended default)
npm install @sendgrid/mail               # SendGrid
npm install mailgun.js form-data         # Mailgun

Quick Start

Minimal Setup (SMTP, Single Database)

import { Module } from '@nestjs/common';
import { EmailModule } from '@flusys/nestjs-email';

@Module({
  imports: [
    EmailModule.forRoot({
      global: true,
      includeController: true,
      bootstrapAppConfig: {
        databaseMode: 'single',
        enableCompanyFeature: false,
      },
      config: {
        defaultDatabaseConfig: {
          type: 'postgres',
          host: process.env.DB_HOST,
          port: Number(process.env.DB_PORT ?? 5432),
          username: process.env.DB_USER,
          password: process.env.DB_PASSWORD,
          database: process.env.DB_NAME,
        },
      },
    }),
  ],
})
export class AppModule {}

After startup, create an email config via the API and then send emails using EmailSendService.


Module Registration

forRoot (Sync)

EmailModule.forRoot({
  global: true,
  includeController: true,
  bootstrapAppConfig: {
    databaseMode: 'single',          // 'single' | 'multi-tenant'
    enableCompanyFeature: false,     // true = company-scoped templates & configs
  },
  config: {
    defaultDatabaseConfig: { /* TypeORM DataSourceOptions */ },
    defaultProvider: 'smtp',         // Optional: default provider type
    rateLimitPerMinute: 100,         // Optional: rate limit on send endpoint
    enableLogging: false,            // Optional: debug logging
  },
})

forRootAsync (Factory)

import { ConfigService } from '@nestjs/config';

EmailModule.forRootAsync({
  global: true,
  includeController: true,
  bootstrapAppConfig: {
    databaseMode: 'single',
    enableCompanyFeature: true,
  },
  imports: [ConfigModule],
  useFactory: (configService: ConfigService) => ({
    defaultDatabaseConfig: {
      type: 'postgres',
      host: configService.get('DB_HOST'),
      port: configService.get<number>('DB_PORT'),
      username: configService.get('DB_USER'),
      password: configService.get('DB_PASSWORD'),
      database: configService.get('DB_NAME'),
    },
  }),
  inject: [ConfigService],
})

forRootAsync (Class)

import { EmailOptionsFactory, IEmailModuleConfig } from '@flusys/nestjs-email';

@Injectable()
export class MyEmailConfigFactory implements EmailOptionsFactory {
  createEmailOptions(): IEmailModuleConfig {
    return { defaultDatabaseConfig: { /* ... */ } };
  }
  createOptions() { return this.createEmailOptions(); }
}

EmailModule.forRootAsync({
  bootstrapAppConfig: { databaseMode: 'single', enableCompanyFeature: false },
  useClass: MyEmailConfigFactory,
})

Configuration Reference

interface IEmailModuleConfig extends IDataSourceServiceOptions {
  /** Optional: default provider type when no config is specified */
  defaultProvider?: 'smtp' | 'sendgrid' | 'mailgun';

  /** Optional: max emails per minute (default: unlimited) */
  rateLimitPerMinute?: number;

  /** Optional: enable debug logging for send operations */
  enableLogging?: boolean;
}

Feature Toggles

| Feature | Config Key | Default | Effect | |---------|-----------|---------|--------| | Company scoping | enableCompanyFeature: true | false | Uses EmailConfigWithCompany and EmailTemplateWithCompany entities; filters all queries by companyId | | Multi-tenant | databaseMode: 'multi-tenant' | 'single' | Creates per-tenant DataSource connections |


API Endpoints

All endpoints use POST. All require JWT authentication unless noted.

Email Config — POST /email/email-config/*

| Endpoint | Permission | Description | |----------|-----------|-------------| | POST /email/email-config/insert | email-config.create | Create a provider configuration | | POST /email/email-config/get-all | email-config.read | List all configs | | POST /email/email-config/get/:id | email-config.read | Get config by ID | | POST /email/email-config/update | email-config.update | Update config | | POST /email/email-config/delete | email-config.delete | Delete config | | POST /email/email-config/test | email-config.create | Send a test email to verify config | | POST /email/email-config/set-default | email-config.update | Set as default provider |

Email Templates — POST /email/email-template/*

| Endpoint | Permission | Description | |----------|-----------|-------------| | POST /email/email-template/insert | email-template.create | Create a template | | POST /email/email-template/get-all | email-template.read | List all templates | | POST /email/email-template/get/:id | email-template.read | Get template by ID | | POST /email/email-template/update | email-template.update | Update template | | POST /email/email-template/delete | email-template.delete | Delete template |

Email Send — POST /email/send/*

| Endpoint | Permission | Description | |----------|-----------|-------------| | POST /email/send/template | email-config.create | Send using a stored template | | POST /email/send/raw | email-config.create | Send raw HTML email |


Entities

Core Entities (always registered)

| Entity | Table | Description | |--------|-------|-------------| | EmailConfig | email_config | Provider configuration (SMTP credentials, SendGrid API key, etc.) | | EmailTemplate | email_template | Email templates with {{variable}} placeholders |

Company Feature Entities (enableCompanyFeature: true)

| Entity | Table | Description | |--------|-------|-------------| | EmailConfigWithCompany | email_config | Same as EmailConfig + companyId and branchId columns | | EmailTemplateWithCompany | email_template | Same as EmailTemplate + companyId column |

Register Entities in TypeORM

import { EmailModule } from '@flusys/nestjs-email';

TypeOrmModule.forRoot({
  entities: [
    ...EmailModule.getEntities({ enableCompanyFeature: true }),
    // other entities
  ],
})

Email Providers

SMTP (Default)

Create an EmailConfig record with provider smtp:

POST /email/email-config/insert
{
  "name": "Company SMTP",
  "provider": "smtp",
  "config": {
    "host": "smtp.gmail.com",
    "port": 587,
    "secure": false,
    "user": "[email protected]",
    "password": "app-password"
  },
  "fromEmail": "[email protected]",
  "fromName": "My App",
  "isDefault": true
}

SendGrid

Install @sendgrid/mail first, then create a config:

POST /email/email-config/insert
{
  "name": "SendGrid Production",
  "provider": "sendgrid",
  "config": { "apiKey": "SG.xxxxxxxxxxxx" },
  "fromEmail": "[email protected]",
  "fromName": "My App",
  "isDefault": true
}

Mailgun

Install mailgun.js form-data first, then create a config:

POST /email/email-config/insert
{
  "name": "Mailgun",
  "provider": "mailgun",
  "config": {
    "apiKey": "key-xxxxxxxxxxxx",
    "domain": "mg.example.com",
    "region": "us"
  },
  "fromEmail": "[email protected]",
  "fromName": "My App",
  "isDefault": true
}

Custom Provider

Implement IEmailProvider and register it with StorageProviderRegistry:

import { IEmailProvider, EmailProviderRegistry } from '@flusys/nestjs-email';

class MyCustomProvider implements IEmailProvider {
  async send(options: IEmailSendOptions): Promise<void> {
    // custom sending logic
  }
  async testConnection(): Promise<boolean> {
    return true;
  }
}

// Register before module initialization
EmailProviderRegistry.register('custom', MyCustomProvider);

Template Engine

Templates use {{variableName}} syntax. All values are HTML-escaped automatically.

Create a template:

POST /email/email-template/insert
{
  "name": "Welcome Email",
  "slug": "welcome",
  "subject": "Welcome to {{appName}}, {{userName}}!",
  "html": "<h1>Hello {{userName}}</h1><p>Welcome to <strong>{{appName}}</strong>.</p><p><a href=\"{{loginUrl}}\">Login here</a></p>",
  "variables": ["appName", "userName", "loginUrl"]
}

Send using the template:

POST /email/send/template
{
  "templateSlug": "welcome",
  "to": "[email protected]",
  "variables": {
    "appName": "My App",
    "userName": "John Doe",
    "loginUrl": "https://app.example.com/login"
  }
}

Exported Services

These services are exported by EmailModule and injectable in your application:

| Service | Description | |---------|-------------| | EmailSendService | Send emails via template slug or raw HTML | | EmailTemplateService | CRUD for email templates | | EmailProviderConfigService | CRUD for provider configurations | | EmailConfigService | Exposes runtime config (provider defaults, rate limits) | | EmailDataSourceProvider | Dynamic TypeORM DataSource resolution per request |

Note: Always use @Inject(ServiceClass) explicitly — esbuild bundling loses TypeScript metadata.


Sending Emails Programmatically

Inject EmailSendService to send emails from other services:

import { EmailSendService } from '@flusys/nestjs-email';

@Injectable()
export class UserService {
  constructor(
    @Inject(EmailSendService) private readonly emailSendService: EmailSendService,
  ) {}

  async sendWelcomeEmail(user: { email: string; name: string }): Promise<void> {
    await this.emailSendService.sendTemplateEmail({
      templateSlug: 'welcome',
      to: user.email,
      variables: { userName: user.name, appName: 'My App' },
    });
  }

  async sendRawEmail(): Promise<void> {
    await this.emailSendService.sendRawEmail({
      to: '[email protected]',
      subject: 'Hello',
      html: '<p>Hello world</p>',
      attachments: [
        {
          filename: 'report.pdf',
          content: base64EncodedPdfString,
          contentType: 'application/pdf',
        },
      ],
    });
  }
}

Troubleshooting

No default email config found

Create at least one EmailConfig record and mark it as default:

POST /email/email-config/set-default
{ "id": "your-config-id" }

Template not found

Check the templateSlug matches exactly (case-sensitive). Use POST /email/email-template/get-all to list available templates.


SMTP connection refused

Use the test endpoint first:

POST /email/email-config/test
{ "id": "your-config-id", "to": "[email protected]" }

For Gmail, enable "App Passwords" and use the app password, not your account password.


No metadata for entity

Call EmailModule.getEntities() with the correct flags when registering TypeOrmModule:

entities: [...EmailModule.getEntities({ enableCompanyFeature: true })]

License

MIT © FLUSYS


Part of the FLUSYS framework — a full-stack monorepo powering Angular 21 + NestJS 11 applications.