+1

Nestjs 9 Forgot password with nodemailer

Chức năng quên mật khẩu với NestJS sử dụng Nodemailer

#nestjs #nodejs #mailer

Trong bài viết này, chúng ta sẽ triển khai chức năng quên mật khẩu trong một ứng dụng NestJS. Chức năng này sẽ sử dụng thư viện Nodemailer để gửi email và Handlebars để tạo template cho email.

Mục tiêu

  • Cài đặt và cấu hình Nodemailer và Handlebars.
  • Tạo dịch vụ gửi email.
  • Tạo module và service để quản lý các loại email.
  • Tạo chức năng quên mật khẩu trong Auth Controller.
  • Tạo template email với Handlebars.

1. Cài đặt các thư viện cần thiết

Trước tiên, chúng ta cần cài đặt Nodemailer và Handlebars. Mở terminal và chạy các lệnh sau:

npm install nodemailer
npm install handlebars

Cấu hình Nodemailer

Tiếp theo, chúng ta sẽ cấu hình Nodemailer để gửi emai Tạo một file mailer.service.ts với nội dung như sau:

import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import nodemailer from 'nodemailer';
import Handlebars from 'handlebars';
import fs from 'node:fs/promises';

@Injectable()
export class MailerService {
  private readonly transporter: nodemailer.Transporter;

  constructor(private readonly configService: ConfigService) {
    this.transporter = nodemailer.createTransport({
      host: configService.get<string>('mailer.host', { infer: true }),
      port: configService.get<number>('mailer.port', { infer: true }),
      secure: configService.get<boolean>('mailer.secure', { infer: true }),
      auth: {
        user: configService.get<string>('mailer.user', { infer: true }),
        pass: configService.get<string>('mailer.password', { infer: true }),
      },
      debug: true,
    });
  }

  async sendMail({
    templatePath,
    context,
    ...mailOptions
  }: nodemailer.SendMailOptions & {
    templatePath: string;
    context: Record<string, unknown>;
  }): Promise<void> {
    let html: string | undefined;
    if (templatePath) {
      const template = await fs.readFile(templatePath, 'utf-8');
      html = Handlebars.compile(template, {
        strict: true,
      })(context);
    }

    await this.transporter.sendMail({
      ...mailOptions,
      from: mailOptions.from
        ? mailOptions.from
        : `"${this.configService.get<string>('mailer.defaultName', {
            infer: true,
          })}" <${this.configService.get<string>('mailer.defaultEmail', {
            infer: true,
          })}>`,
      html: mailOptions.html ? mailOptions.html : html,
    });
  }
}

Giải thích

  • nodemailer.createTransport: Tạo một transporter để gửi email.
  • sendMail: Hàm này sử dụng Handlebars để biên dịch template email và gửi email.

.env

Thêm các cấu hình sau vào file .env của bạn:

MAILER_HOST=smtp.gmail.com
MAILER_PORT=587
MAILER_USER=your-email@gmail.com
MAILER_PASSWORD=your-email-password
MAILER_SECURE=false
MAILER_DEFAULT_NAME=Your Name
MAILER_DEFAULT_EMAIL=your-email@gmail.com

3. Tạo module Mailer

Tạo một module để chứa MailerService. Tạo một file mailer.module.ts với nội dung như sau:

4. Import MailerModule vào AppModule

Import MailerModule vào AppModule để có thể sử dụng trong toàn bộ ứng dụng:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MailerModule } from './mailer/mailer.module';
import { AuthModule } from './auth/auth.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    MailerModule,
    AuthModule,
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}

5. Tạo chức năng quên mật khẩu trong Auth Controller

Tạo một file auth.controller.ts với nội dung như sau:

import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
import { ForgotPasswordDto } from './dto/forgot-password.dto';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('forgot-password')
  async forgotPassword(@Body() forgotPasswordDto: ForgotPasswordDto) {
    return this.authService.forgotPassword(forgotPasswordDto);
  }
}

Tiếp theo, tạo service để xử lý chức năng quên mật khẩu. Tạo một file auth.service.ts với nội dung như sau:

import { Injectable } from '@nestjs/common';
import { MailsService } from 'src/mails/mails.service';
import { ForgotPasswordDto } from './dto/forgot-password.dto';

@Injectable()
export class AuthService {
  constructor(private readonly mailsService: MailsService) {}

  async forgotPassword(forgotPasswordDto: ForgotPasswordDto) {
    const { email, userName, token } = forgotPasswordDto;

    await this.mailsService.forgotPassword({
      to: email,
      data: {
        token,
        user_name: userName,
      },
    });

    return { message: 'Password reset email sent.' };
  }
}

6.Tạo module MailsService

Tạo một module để lưu trữ các loại email gửi như quên mật khẩu, xác thực, v.v. Tạo file mails.service.ts với nội dung như sau:

import { Injectable } from '@nestjs/common';
import path from 'path';
import { ConfigService } from '@nestjs/config';
import { MailerService } from 'src/mailer/mailer.service';

@Injectable()
export class MailsService {
  constructor(
    private readonly mailerService: MailerService,
    private readonly configService: ConfigService,
  ) {}

  async forgotPassword(mailData: {
    to: string;
    data: {
      token: string;
      user_name: string;
    };
  }): Promise<void> {
    await this.mailerService.sendMail({
      to: mailData.to,
      subject: 'Reset Password',
      templatePath: path.join(
        this.configService.get<string>('mailer.workingDirectory', {
          infer: true,
        }),
        'src',
        'mails',
        'templates',
        'reset-password.hbs',
      ),
      context: {
        username: mailData.data.user_name,
        resetLink: `${this.configService.get<string>('app.clientURL')}/reset-password?token=${mailData.data.token}`,
      },
    });
  }
}

9. Kết luận

Với các bước trên, bạn đã hoàn thành việc triển khai chức năng quên mật khẩu trong ứng dụng NestJS sử dụng Nodemailer và Handlebars. Chức năng này sẽ gửi một email quên mật khẩu với liên kết để người dùng có thể đặt lại mật khẩu của mình. Bạn có thể tùy chỉnh thêm các chi tiết như giao diện của email, các thông tin trong email, và cách xử lý các token để phù hợp với nhu cầu của dự án của bạn.

Chúc các bạn thành công trong việc triển khai chức năng này vào dự án của mình!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí