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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@haorama/nestjs-mailer

v0.2.0

Published

Nestjs mailer module

Downloads

12

Readme

Nestjs Mailer

Nestjs mailing service based on nodemailer with additional feature like

  • Multi mailer/ driver, you can used multiple driver like mailtrap, SES together
  • use your own view adapter like handlebars, nunjucks etc

Installation

npm install --save @haorama/nestjs-mailer nodemailer
npm install --save-dev @types/nodemailer
#or
yarn add @haorama/nestjs-mailer nodemailer
yarn add -D @types/nodemailer

Usage

Import the MailerModule into your Root Module e.g AppModule.

import { Module } from "@nestjs/common";
import { MailerModule } from "@haorama/nestjs-mailer";

@Module({
  imports: [
    MailerModule.forRoot({
      mailers: {
        mailtrap: {
          host: process.env.MAIL_HOST,
          port: +process.env.MAIL_PORT,
          auth: {
            user: process.env.MAIL_USER,
            pass: process.env.MAIL_PASSWORD,
          },
        },
      },
      default_mailer: "mailtrap"
    })
  ]
})
export class AppModule {}

and somewhere in your service or controller you can use MailerService and send the email

import { MailerService } from "@haorama/nestjs-mailer";

@Injectable()
export class AuthService {
  constructor(private mailerService: MailerService) {}

  sendOtp() {
    const otp = 123456;

    await this.mailerService.send({
      to: "[email protected]",
      subject: "OTP",
      text: `Your Otp is ${otp}`,
      html: `<p>Your Otp is ${otp}</p>`,
      data: {
        otp
      },
    });
  }
}

Async Configuration

you can also use forRootAsync e.g if you prefer to put all configuration inside your config module file

@Module({
  imports: [
    MailerModule.forRootAsync({
      useFactory: (configService: ConfigService) => {
        return configService.get("mail");
      },
      imports: [ConfigModule],
      inject: [ConfigService],
    }),
  ]
})
export class AppModule {}

Amazon SES

you can pass a function and return the Transport instance from nodemailer

// this import depend on your allowSyntheticDefaultImports on your tsconfig.json
import * as nodemailer from "nodemailer";
import * as aws from "@aws-sdk/client-ses";

const ses = new aws.SES({
  region: process.env.AWS_REGION,
  credentialDefaultProvider: defaultProvider,
});

@Module({
  imports: [
    MailerModule.forRoot({
      mailers: {
        ses: () => nodemailer.createTransport({ SES: { ses, aws } }),
        mailtrap: {
          host: process.env.MAIL_HOST,
          port: +process.env.MAIL_PORT,
          auth: {
            user: process.env.MAIL_USER,
            pass: process.env.MAIL_PASSWORD,
          },
        },
      },
      default_mailer: "ses",
    }),
  ]
})
export class AppModule {}

Template / View Engine

We dont provide default template engine inside MailerModule but you can create and choose your own template / view engine. For example we can create a Nunjuck engine by passing template inside module options.

First create a NunjuckAdapter class and extends our MailEngineAdapter to it

import { resolve, join } from "path";
import nunjucks from "nunjucks";
import { MailEngineAdapter } from "@hikingness/nestjs-mailer";

export class NunjucksAdapter extends MailEngineAdapter {
  root: string;

  constructor() {
    super();
    this.root = resolve("./src/views/html");
  }

  render(path: string, data?: any) {
    const env = new nunjucks.Environment();

    const name = process.env.APP_NAME;
    nunjucks.configure(this.root, { autoescape: true });

    return nunjucks.render(join(this.root, path), {
      appName: name,
      ...data,
    });
  }
}

the render method can be anything as long as it return an html, then in the MailerModule

@Module({
  imports: [
    MailerModule.forRoot({
      mailers: {
        mailtrap: {
          host: process.env.MAIL_HOST,
          port: +process.env.MAIL_PORT,
          auth: {
            user: process.env.MAIL_USER,
            pass: process.env.MAIL_PASSWORD,
          },
        },
      },
      default_mailer: "mailtrap",
      template: {
        engine: new NunjucksAdapter()
      }
    })
  ]
})
export class AppModule {}

After that you can use template options inside send method

await this.mailerService.send({
  to: "[email protected]",
  subject: "OTP",
  // this path depend on your view configuration on the template / view adapter
  template: "/emails/otp.html",
  data: {
    otp,
  },
});

Queueing

By default we dont provide queueing inside MailerService, but you can create your own mailing Module.

import { MailerModule } from "@hikingness/nestjs-mailer";
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
// we used bull for queueing the email
import { BullModule } from "@nestjs/bull";
import { MailService } from "./mail.service";
import { MailConsumer } from "./mail.consumer";

@Module({
  imports: [
    MailerModule.forRootAsync({
      mailers: {
        anyMailerOfYours: "defined your config here",
      }
    }),
    BullModule.registerQueue({
      name: "mail",
    }),
  ],
  providers: [MailService, MailConsumer],
  exports: [MailService],
})
export class MailModule {}

as you can see above we use BullModule from @nestjs/bull to make the mailing service queueable, we still need to define MailService and MailConsumer

mail.service.ts

import { Injectable } from "@nestjs/common";
import { InjectQueue } from "@nestjs/bull";
import { Queue } from "bull";
import { SendMailOptions } from "@haorama/nestjs-mailer";

/**
 * This mail service by default send an email in the background using Bull queue
 */
@Injectable()
export class MailService {
  constructor(@InjectQueue("mail") private mailQueue: Queue) {}

  send(options: SendMailOptions) {
    return this.mailQueue.add("send", options);
  }
}

mail.consumer.ts

import { MailerService, SendMailOptions } from "@haorama/nestjs-mailer";
import { OnQueueFailed, Process, Processor } from "@nestjs/bull";
import { Job } from "bull";

@Processor("mail")
export class MailConsumer {
  constructor(private mailerService: MailerService) {}

  @Process("send")
  send(job: Job<SendMailOptions>) {
    return this.mailerService.send(job.data);
  }

  @OnQueueFailed({ name: "send" })
  onSendFailed(job: string, error: any) {
    console.log("Job failed", job, error);
    // or send failed report to Sentry etc
  }
}

and you can replace the MailerService with your own service (in this example is MailService)

import { MailService } from "/your-mail-service-path";

@Injectable()
export class AuthService {
  constructor(private mailService: MailService) {}

  sendOtp() {
    const otp = 123456;

    await this.mailService.send({
      to: "[email protected]",
      subject: "OTP",
      template: "/views/otp.html",
      data: {
        otp
      },
    });
  }
}