Sending Emails in NestJS with Sendgrid
This guide provides a comprehensive walkthrough on seamlessly integrating the SendGrid mail service into your NestJS application.
Step 1: NestJS CLI Installation
If you don't have an existing NestJS application, proceed to generate a new NestJS app. Install the NestJS CLI globally by utilizing npm:
npm install -g @nestjs/cli
Step 2: Create a New NestJS Project
Use the NestJS CLI to create a new project. Name it whatever you like; for this article, we’ll use “sendgrid-email-nestjs.”
nest new sendgrid-email-nestjs
cd sendgrid-email-nestjs
Step 3: Install SendGrid Package
Install the @sendgrid/mail
package:
npm install @sendgrid/mail
Step 4: Set up SendGrid API Key
Retrieve your SendGrid API key from the SendGrid dashboard, and securely store it either in your environment variables or utilize a configuration service for enhanced security and flexibility.
SENDGRID_API_KEY=your-sendgrid-api-key
Step 5: Create Email Module
Create an email module that will contain our implementations.
nest generate module email
Step 6: Create SendGrid Client class
Establish the SendGridClient class within the sendgrid-client.ts file located in the email folder. This class is designed to utilize the API key retrieved from the configuration, enabling seamless interaction with the SendGrid API through the @sendgrid/mail package.
nest generate class email/sendgrid-client --flat --no-spec
Step 7: Update SendGrid Client
Update sendgrid-client.ts
to use the API key from the configuration:
// src/email/sendgrid-client.ts
import { Injectable } from '@nestjs/common';
import { MailDataRequired, setApiKey, send } from '@sendgrid/mail';
@Injectable()
export class SendGridClient {
constructor() {
// Set the API key from the config service or environment variable
setApiKey(process.env.SENDGRID_API_KEY);
}
/**
* Send an email using SendGrid.
* @param mail - The email data, including recipient, sender, subject, and content.
* @returns Promise<void>
*/
async send(mail: MailDataRequired): Promise<void> {
try {
// Send the email using the SendGrid API
await send(mail);
console.log(`Email successfully sent to ${mail.to as string}`);
} catch (error) {
// Handle errors during the email sending process
console.error('Error while sending email', error);
throw error;
}
}
}
Note:
Ensure "esModuleInterop" is set to true in your tsconfig.json file to enable the use of default imports.
// Example tsconfig.json snippet:
/*
{
"compilerOptions": {
"esModuleInterop": true,
// ... other options
},
// ... other configurations
}
*/
Step 8: Create Email Service
Generate the email.service.ts file to serve as an abstraction layer for the SendGridClient. This facilitates the implementation of distinct methods tailored for specific email use cases, promoting a modular and organized approach to handling email functionality within your NestJS application.
nest generate service email/email --flat --no-spec
Step 9: Update Email Service
Our email service class will consist of 2 methods: “sendTestEmail” and “sendTestEmailWithTemplate”. The former will be a method to send a test email and the latter will be a method to send an email with a preconfigured sendgrid email template. The template ID will be retrieved from the Sendgrid dashboard: dynamic template.
// src/email/email.service.ts
import { Injectable } from '@nestjs/common';
import { MailDataRequired } from '@sendgrid/mail';
import { SendGridClient } from './sendgrid-client';
@Injectable()
export class EmailService {
constructor(private readonly sendGridClient: SendGridClient) {}
/**
* Sends a test email with a simple body content.
* @param recipient - Email address of the recipient.
* @param body - Body content of the email (default is 'This is a test mail').
*/
async sendTestEmail(recipient: string, body = 'This is a test mail'): Promise<void> {
const mail: MailDataRequired = {
to: recipient,
from: 'noreply@domain.com', // Approved sender ID in Sendgrid
subject: 'Test email',
content: [{ type: 'text/plain', value: body }],
};
await this.sendGridClient.send(mail);
}
/**
* Sends a test email using a SendGrid template.
* @param recipient - Email address of the recipient.
* @param body - Dynamic content for the template.
*/
async sendTestEmailWithTemplate(recipient: string, body: string): Promise<void> {
const mail: MailDataRequired = {
to: recipient,
cc: 'example@mail.com', // Assuming you want to send a copy to this email
from: 'noreply@domain.com', // Approved sender ID in Sendgrid
templateId: 'Sendgrid_template_ID', // Retrieve from config service or environment variable
dynamicTemplateData: { body, subject: 'Send Email with template' }, // Data to be used in the template
};
await this.sendGridClient.send(mail);
}
}
Step 10: Update Email Module
Update the email module by adding the SendGridClient class as a provider and exporting the email service so that it is accessible to any module that imports the Email module.
// src/email/email.module.ts
import { Module } from '@nestjs/common';
import { EmailService } from './email.service';
import { SendGridClient } from './sendgrid-client';
@Module({
providers: [EmailService, SendGridClient],
exports: [EmailService],
})
export class EmailModule {}
Step 11: Use Email Service in Controller
Import the email service and make it available in the appropriate controller. We will be using the app controller. Update the app.controller.ts
file to provide an endpoint to test the email service.
// src/app.controller.ts
import { Body, Controller, Get, Post } from '@nestjs/common';
import { AppService } from './app.service';
import { EmailService } from './email/email.service';
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
private readonly emailService: EmailService,
) {}
/**
* Handles GET requests to the root endpoint.
* @returns Hello message from AppService.
*/
@Get()
getHello(): string {
return this.appService.getHello();
}
/**
* Handles POST requests to send a test email.
* @param sendEmailDTO - Data for sending a test email.
*/
@Post('send-test-email')
async sendEmail(
@Body() sendEmailDTO: { recipient: string; body: string },
): Promise<void> {
try {
// Delegate the task of sending the test email to the EmailService.
await this.emailService.sendTestEmail(
sendEmailDTO.recipient,
sendEmailDTO.body,
);
} catch (error) {
// Handle and log any errors that may occur during email sending.
console.error('Error sending test email:', error);
throw error;
}
}
}
Step 12: Run Your NestJS Application
Run your NestJS application:
npm run start:dev
To test the email functionality, initiate a POST request to http://localhost:3000/send-test-email using an API testing tool like Postman. Provide the recipient email and, if desired, the optional body parameters in the request body as a JSON payload.
Ensure to replace placeholders such as 'Sendgrid_template_ID', 'SENDGRID_API_KEY', etc., with your specific and valid values before making the request.
Conclusion
In conclusion, this guide has walked you through the seamless integration of the SendGrid mail service into your NestJS application. By following the outlined steps, you've successfully established the project, configured the SendGrid API key, and crafted essential modules and classes. With a well-organized modular structure and detailed instructions, you now possess a robust framework for seamlessly incorporating efficient email functionality into your NestJS projects. Should you have any questions or encounter issues, feel free to seek assistance. Happy coding!
Subscribe to my newsletter
Read articles from iyiola osuagwu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
iyiola osuagwu
iyiola osuagwu
Highly qualified technical lead and developer, with experience in multiple programming languages and technologies. Passionate about high-performance, scalable, reliable, and maintainable software, working in agile development environments and leading efficient, dynamic development teams. Having 7+ more years of technical development experience spent most of my time developing solutions. Solid experience in Front End / Back End Engineering and strong problem-solving skills and passion for technology. Skills and expertise: Javascript, typescript, React, React Native, Node.js, Git, Rest API Design & Development, Linux, Team leading, Code quality control, JSON, XML, Automated Test, TDD, Continuous integrations, Agile, Scrum, MVC, Design Principles, and Patterns