How To Setup Nodemailer With Nest Js.
Sending email with Nest js

I work with nest js as a backend developer to use technology to address issues. I am a team player who produces efficient code.
What is Nodemailer
NodeMailer is a NodeJS module that makes it simple for users to send emails from the server. Emails such as "Confirmation email," "Forgot Password email," "Contact us email," and "Notification kinds email" can be sent through NestJS applications using Nodemailer.
Steps To Follow
Step 1: Install the required dependencies
Install the nest js mailer module by executing this command to get started.
npm i @nestjs-modules/mailer nodemailer --save

Step 2: Select a view template
To generate email templates in the NestJS application, select one of the three available template engines (handlebars, pug, or ejs).
Run the command below to install the Handlebars package
npm i handlebars --save

Step 3: Create a mail module in your application
You need to create a mail module and service in your application This can be done using the NEST CLI
To use the nest CLI, run the commands bellow
nest g module mail
nest g service mail
These commands will create a folder named mail in your src and the folder will contain three files (mail.module, mail.service, mail.service.spec)
Step 4: Update the mail module generated
Import the mailer module (the one we installed above) into the mail module we just created and configure your mail server transport via smtp.
Provide a default from email address to use the same mail throughout your application consistently.
You can always override the default whenever necessary.
The last step, configure the templates folder and the adapter in this case HandlebarsAdapter. Find out more about the other template adapters in the Mailer documentation.
import { MailerModule } from '@nestjs-modules/mailer';
import { Global, Module } from '@nestjs/common';
import { join } from 'path';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { MailService } from './mail.service';
@Global()
@Module({
imports: [
MailerModule.forRootAsync({
useFactory: async (config: ConfigService) => ({
transport: {
host: 'smtp.example.com',
port: 111,
auth: {
user: 'hello@example.com',
pass: 'topsecret',
},
},
defaults: {
from: `"Mr Example" <hello@example.com>`,
},
template: {
dir: join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(), // or new PugAdapter() or new EjsAdapter()
options: {
strict: true,
},
},
}),
],
providers: [MailService],
exports: [MailService],
})
export class MailModule {}
Export the MailService to provide it via Dependency Injection (DI) for your controllers, resolvers, and services.
Step 5: Create an email template
To create your email template (using handlebars ) you have to make a folder named
templates in your mail folder i.e src/mail/templates . All your email templates should be stored in this folder.
Let's create an example welcome email ...
Create a file named welcome.hbs inside the templates folder
<html lang="en">
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
.headDiv {
width: 100%;
height: 120px;
background: #F9FAFB;
text-align: center;
}
</style>
</head>
<body>
<p class="headDiv">Hi {{ name }},</p>
<p>Welcome to example web application</p>
<p>Click on the link below to view our website</p>
<p>
<a href="{{ url }}">View</a>
</p>
</body>
</html>
I find it easier to embed my CSS in the head with <style> tag.
NOTE
By default, Nest only distributes TypeScript-compiled files (.js and .d.ts) during the build step, your templates might be missing when you build your application for production.
To distribute your .hbs files, open your nest-cli.json and add your templates directory to the assets property in the global compilerOptions.
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["mail/templates/**/*"], // 👈 or "**/*.hbs" all files ending with .hbs
"watchAssets": true // 🤖 copy assets in watch mode
}
}
HOW TO SEND MAIL
Add MailerService to your MailService and implement your mailing logic here.
You need to provide {{ name }} and {{ url }} under the context key. Read the Handlebars documentation for more background.
import { MailerService } from '@nestjs-modules/mailer';
import { Injectable } from '@nestjs/common';
import { User } from './../user/user.entity';
@Injectable()
export class MailService {
constructor(private mailerService: MailerService) {}
async sendUserConfirmation(user: User, token: string) {
const url = `example.com/auth/confirm?token=${token}`;
await this.mailerService.sendMail({
to: user.email,
// from: '"Support Team" <support@example.com>', // override default from
subject: 'Welcome to Our App!',
template: './welcome', // `.hbs` extension is appended automatically
context: { // ✏️ filling curly brackets with content
name: user.name,
url,
},
});
}
}
Call this method in your service that is handling the user registration
How To Create a Generic Method To Send Mails
You don't want to write a function for every email you send to the user because it takes time and results in more code being written.
You can construct a single method to handle all the mail (welcome email, otp confirmation, forgot password) you want to send.
Step 1: Create a folder inside your Mail Folder
Create a folder inside your mail folder and name it interface.
Inside the interface folder, create a typescript file and name it index.ts
Step 2: Create Your Mail Data Interface
This interface needs to include any potential parameters you want to have in the email templates.
export interface MailData {
to: string;
subject:string;
firstName?: string;
lastName?: string;
link?: string;
}
The to and subject properties are not optional for some reasons I'll explain soon.
Step 2: Modify Your Mail Service
The mail service must be modified as shown below in order to make the function general.
import { MailerService } from '@nestjs-modules/mailer';
import { Injectable } from '@nestjs/common';
import { MailData } from './interface';
@Injectable()
export class MailService {
constructor(private mailerService: MailerService) {}
async sendMail(data: MailData, templatePath: string) {
await this.mailerService.sendMail({
to: data.to,
subject: data.subject,
template: `./${templatePath}`,
context: {
...data,
},
});
}
}
HOW TO USE THE GENERIC FUNCTION
The sample code provided below demonstrates how to apply this one method throughout your application.
import { Injectable } from '@nestjs/common';
import { MailService } from 'src/mail/mail.service';
import { CreateUserDto } from './dto/create-user.dto';
@Injectable()
export class UserService {
async create(createUserDto: CreateUserDto) {
const {firstName, lastName, email} = createUserDto
// check if email is unique
// hash the password
// create a token
// create a link and append the token to it
// use the mail method to send email as use below
this.mailService.sendMail(
{
firstName,
lastName,
to: email,
subject: `Welcome User`,
link: 'link created above',
},
'welcome',
);
return { message: 'success' };
}
Your mail module should look similar to the image below

UPDATE THE MAIL CONFIG WITH ENV VARIABLES
Currently, the MailModule has the mail server configurations hardcoded in. With the help of Nest's configuration module, you may import your settings and login information from.env files.
Install the @nestjs/config dependency.
npm i --save @nestjs/config
Add the ConfigModule to the imports list of your AppModule.
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true, // no need to import into other modules
}),
AuthModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
Create a .env file in your root directory (not in your src folder).
MAIL_HOST=smtp.example.com
MAIL_USER=user@example.com
MAIL_PASSWORD=topsecret
MAIL_FROM=noreply@example.com
MAIL_PORT=111
Modify Your Mail Module
import { MailerModule } from '@nestjs-modules/mailer';
import { Global, Module } from '@nestjs/common';
import { join } from 'path';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { MailService } from './mail.service';
import { ConfigService } from '@nestjs/config';
@Global()
@Module({
imports: [
MailerModule.forRootAsync({
useFactory: async (config: ConfigService) => ({
transport: {
host: config.get('MAIL_HOST'),
port: config.get('MAIL_PORT'),
auth: {
user: config.get('MAIL_USER'),
pass: config.get('MAIL_PASSWORD'),
},
},
defaults: {
from: `"No Reply" <${config.get('MAIL_FROM')}>`,
},
template: {
dir: join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
}),
inject: [ConfigService],
}),
],
providers: [MailService],
exports: [MailService],
})
export class MailModule {}
GitHub repository: https://github.com/ayodeji1167/Nest-Js-Email