Level Up Your NestJS Apps: Email Functionality with Mailgun & EJS

Sidali Assoul - May 14 - - Dev Community

Effective email communication is a fundamental requirement for virtually any application. In this course, we’ll delve into the art of implementing essential email sending functionality within NestJS, a robust Node.js framework. We’ll harness the power of Mailgun, a reliable third-party email service, while taking advantage of the versatile EJS templating language for crafting visually appealing emails enriched with compelling content.

read the original blog post: read on spithacode

Prerequisites

Before we dive into the implementation, you need to set up a NestJS project and configure the Mailgun API credentials. Make sure you have the following dependencies installed:

1. NestJS project setup

let’s start by installing the nest cli then creating our project

 npm install -g @nestjs/cli
Enter fullscreen mode Exit fullscreen mode

installing @nestjs/cli

nest new <your project name goes here>
Enter fullscreen mode Exit fullscreen mode

create a new project using @nestjs/cli

2. Installing our required dependencies

we need the config module which will help us store our mailgun api crendentials in a secure place (the process environnement variables) , nest config will basically load the envs into our app

npm install @nestjs/config
Enter fullscreen mode Exit fullscreen mode

this is the mailgun sdk aka a bunch of modules to help us to communicate with the mailgun api.

npm install  mailgun.js
Enter fullscreen mode Exit fullscreen mode

Let’s start coding

1. Email Module components

We’ll begin by wrapping our email interaction logic in a separate module to better separate concerns. Run the following commands to generate an email module and an email service:

nest g module email
nest g service email
Enter fullscreen mode Exit fullscreen mode

Make sure to provide and export the EmailService within the module to allow injection into other parts of the application:

import { Module } from '@nestjs/common';
import { EmailService } from './email.service';

@Module({
  providers: [EmailService],
  exports:[EmailService],
  controllers: []
})
export class EmailModule {}

Enter fullscreen mode Exit fullscreen mode

Next, import the email module into your app module to enable injection of its exported services in the app module context:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { EmailModule } from './email/email.module';

@Module({
  imports: [EmailModule],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

Enter fullscreen mode Exit fullscreen mode

2. Setup mailgun account and and load our credentials safly

To get started with Mailgun website, sign up for a free account on the Mailgun website. After that, create a .env file and store your Mailgun credentials securely: then create a .env file and put your mailgun credentials there:

# mailgun credentials
MAILGUN_API_KEY="your super secret api key"
DOMAIN="your mailgun domain"
MAILGUN_HOST="mailgun host"
FROM_EMAIL="you@gmail.com"
Enter fullscreen mode Exit fullscreen mode

To read the .env file and inject its content as environment variables in NestJS, use the config module. Set the isGlobal attribute to true to make the module available globally for injection:

// app.module.ts
@Module({
  imports: [
    EmailModule,
     ConfigModule.forRoot({
      isGlobal: true,
    }),
    ],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

Enter fullscreen mode Exit fullscreen mode

3. Injecting our mailgun client

Now, let’s write the main logic for sending emails. In the following code, we initialize the Mailgun package with our credentials. To access these credentials, we inject the configService from the ConfigModule:

@Injectable()
import { ConfigService } from '@nestjs/config';
import FormData from 'form-data';
import Mailgun, { MailgunMessageData } from 'mailgun.js';

export class EmailService {

  private readonly mailgun: Mailgun;
  private readonly mailGunClient: IMailgunClient;

  constructor(private readonly configService: ConfigService) {

    this.mailgun = new Mailgun(FormData);
    this.mailGunClient = this.mailgun.client({
      key: this.configService.get('MAILGUN_API_KEY'),
      username: 'api',
      url:this.configService.get('MAILGUN_HOST'),
    });
  }
}

Enter fullscreen mode Exit fullscreen mode

initializing our mailgun sdk , formData is needed by the mailgun client to wrap the payload which it will be sending under the ground as its just a wrapper around an http clients doing api calls to the mailgun rest api

4. creating our email template

Now, let’s create our HTML email template . If you’re not familiar with the EJS templating engine, <%=var1%> means to render the content of the JavaScript variable named var as a string in that specific place.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><%=title%></title>
</head>
<body>
    <h1><%=title%></h1>
    <p><%=content%></p>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

save the file in your project route directory at ./templates/email-template.ejs Let’s start implement our email service

5. Email sending logic

Let’s start implementing our email sending method

export class EmailService {
  //.......
   async send({ email, subject, templatePath, data , attachment = undefined,inline=undefined}: SendEmailParams) {
    //.....................
      // get our html file content as a utf8 encoded string 
      const file = await fs.readFile(templatePath, 'utf8');
      // inject all the attributes inside the data object to the template file 
       const html = ejs.render(file, {
        email,
        ...data,
      });

  }
}

Enter fullscreen mode Exit fullscreen mode
  1. First we are reading our template file as a bare utf8 encoded string
  2. Next we are using ejs to render our html from our ejs template file and it’s

ejs will automatically substitute all the referenced variables passed which are passed to the render function in the template file to get the final html

nest we will use the mailgunClient to send our email after filling all of these options:

  • from : sender
  • to : receiver
  • subject : email subject
  • html : email html body , we will use the ejs rendered html which we got in the previous step
  • inline : inline attachments like images …
  • attachment : some documents which we want to attach with the email
  async send({ email, subject, templatePath, data , attachment = undefined,inline=undefined}: SendEmailParams) {
    //.....................

      try {
        const options: MailgunMessageData = {
          from: this.configService.get('FROM_EMAIL'),
          to: email,
          subject,
          inline,
          html,
          attachment
        };
      return await this.mailGunClient.messages.create(
        this.configService.get('DOMAIN'),
        options,
      );
    } catch (err) {
      throw err;
    }
  }
Enter fullscreen mode Exit fullscreen mode

6. Using our email service

Now let’s try to make use our email service in app.controller.ts

@Controller()
export class AppController {
  constructor(
    private readonly emailService:EmailService
  ) {}

 @Post()
 async sendEmail(){
  return this.emailService.send({
    data:{
      title:"Sidali Assoul",
      content:"content"
    },
    email:"assoulsidali@gmail.com",
    subject:"test",
    templatePath:join("./email-template.ejs")
  })
 }
}

Enter fullscreen mode Exit fullscreen mode

Conclusion

In this tutorial, we’ve walked through the process of sending emails in a NestJS application using the Mailgun API. Here are the key steps we covered:

  1. Setting up a NestJS project and installing the necessary dependencies.
  2. Creating an EmailModule and EmailService to encapsulate email-related logic.
  3. Storing Mailgun credentials securely in a .env file and using the @nestjs/config module to load them.
  4. Initializing the Mailgun client and sending emails with HTML templates using the EJS templating engine.
  5. With this setup, you can easily integrate email functionality into your NestJS application, allowing you to send dynamic and visually appealing emails to your users. This is just the beginning, and you can further enhance this functionality by handling email responses, error handling, and more, depending on your application’s requirements.
. . . .
Terabox Video Player