Today's tutorial, you will learn how Create Email Templates and send them with nodemailer from your Nest application. In here, I am using Nodemailer to send emails and Handlebars to create email templates, alternatively you can use pug or ejs for templating.

Create new Nest application

First upon, we need to create a new Nest application. To create a new Nest application, we will use the following command:
1
nest new nestjs-mailer

Then, we need to navigate to the newly created Nest application folder. To navigate to the newly created Nest application folder, we will use the following command:

1
cd nestjs-mailer

Install Dependencies

Now, we need to install all required dependencies. To install all required dependencies, we will use the following command:
1
npm install --save @nestjs-modules/mailer nodemailer handlebars @types/nodemailer @nestjs/config

Now. we have already installed all required dependencies. Then we need to to create to seperate module for handle email templates and email service.

Create Mail module

Let's begin with creating a mail module and service via the Nest CLI. To create a mail module and service, we will use the following command:
1
2
3
nest g module mail

nest g service mail

Then import the MailerModule into your MailModule and configure your mail server transport via smtp. Final code of MailModule looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { MailerModule } from '@nestjs-modules/mailer'; 
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { Module } from '@nestjs/common';
import { MailService } from './mail.service';
import { join } from 'path';
import { ConfigService } from '@nestjs/config';

@Module({
imports: [
MailerModule.forRootAsync({
useFactory: async (config: ConfigService) => ({
transport: {
host: config.get('MAIL_HOST'),
secure: false,
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 {}

Create Mail template

Create your first email template confirmation.hbs in the src/mail/templates folder. Add the following simple template for a user confirmation:
1
2
3
4
5
6
<p>Hey {{name}},</p>
<p>Please click below to confirm your email</p>
<p>
<a href='{{url}}'>Confirm</a>
</p>
<p>If you did not request this email you can safely ignore it.</p>

By default, Nest only distributes TypeScript compiled files (.js and .d.ts) during the build step. To distribute your .hbs files, open your nest-cli.json and add your templates directory to the assets property in the global compilerOptions. In my case it looks like this:

1
2
3
4
5
6
7
8
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": ["mail/templates/**/*"],
"watchAssets": true
}
}

Configure mail.service.ts

Then Navigate to mail.service.ts and paste the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Injectable } from '@nestjs/common';
import { MailerService } from '@nestjs-modules/mailer';
import { User } from '../../src/auth/entities/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: "[email protected]",
subject: 'Welcome to Nice App! Confirm your Email',
template: '/confirmation',
context: {
name: user.name,
url,
},
});
}
}

Using Mail Service

In here, I wanna use this created Mail Service in Auth Service to send an email to the user. Create new module called auth and create a new service called auth.service.ts within it. Then paste below command in the auth.service.ts file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { Injectable } from '@nestjs/common';
import { MailService } from './../mail/mail.service';
import { User } from '../auth/entities/user.entity';

@Injectable()
export class AuthService {

constructor(private mailService: MailService) {}

async signUp(user: User) {
const token = Math.floor(1000 + Math.random() * 9000).toString();
// create user in db
// ...
// send confirmation mail
await this.mailService.sendUserConfirmation(user, token);
}

Then create file called user.entity.ts in /src/auth/entities directory and paste the following code:

1
2
3
4
export class User {
email: string;
name: string;
}

Navigate to you auth.module.ts in /src/auth directory and import MailModule in imports property. Final code of auth.module.ts looks like this:

1
2
3
4
5
6
7
8
9
10
11
import { Module } from '@nestjs/common';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { MailModule } from 'src/mail/mail.module';

@Module({
imports: [MailModule],
controllers: [AuthController],
providers: [AuthService]
})
export class AuthModule {}

Finally, navigate your auth.controller.ts file in /src/auth directory and paste the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';

@Controller('auth')
export class AuthController {

constructor(private readonly authService: AuthService) {}

@Post('/sign-up')
signUp(@Body() user: any) {
return this.authService.signUp(user);
}
}

Create .env file

Create .env file in your root and paste below code:
1
2
3
4
5
# mail
MAIL_HOST=
MAIL_USER=
MAIL_PASSWORD=
MAIL_FROM=

Global Mail Module

If you need to send mails throughout the entire Nest application. Make the MailModule a global module by adding the @Global() decorator to MailModule and only import it once in your AppModule. All modules can now inject the MailService without forgetting to import the MailModule.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { MailerModule } from '@nestjs-modules/mailer'; 
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
import { Module } from '@nestjs/common';
import { MailService } from './mail.service';
import { join } from 'path';
import { ConfigService } from '@nestjs/config';

@Global() //
@Module({
imports: [
MailerModule.forRootAsync({
useFactory: async (config: ConfigService) => ({
transport: {
host: config.get('MAIL_HOST'),
secure: false,
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 {}

Conclusion

In this tutorial, we learned how to send mail using Nest.JS application. If you have any issue regarding this tutorial, mention your issue in comment section or reach me through my E-mail. You can obtainf the complete source code from this GitHub repository.

Happy Coding