작성자: Okure U. Edet
NestJS를 학습하던 중 Nodemailer로 테스트 이메일을 전송해야 하는 상황이 있었는데, NestJS 애플리케이션 환경에서 이를 구현하는 데 꽤 애를 먹었습니다. 인터넷을 뒤져가며 여러 자료를 찾아본 끝에 해결책을 발견했고, 생각보다 아주 간단한 방법이었습니다.
이 글에서는 제가 찾은 해결 방법을 공유하여 여러분의 NestJS 프로젝트에서도 바로 활용할 수 있도록 안내해 드리겠습니다.
목차
- NestJS 프로젝트 설정 방법
- 앱에서 Nodemailer 구성하기
- Nodemailer로 이메일 전송하기
- 마무리
NestJS 프로젝트 설정 방법
실제 서비스에서는 사용자가 비밀번호 찾기 경로를 클릭하면 해당 사용자의 이메일로 링크가 발송되고, 사용자는 그 링크를 통해 비밀번호를 재설정할 수 있어야 합니다. 이 글에서는 Nodemailer를 사용하여 이러한 시나리오를 테스트 케이스 형태로 구현하는 방법을 보여드립니다.
먼저 선호하는 IDE를 열거나 터미널로 이동하여 다음 명령어를 입력하세요.
$ npm i -g @nestjs/cli
$ nest new nodemailer-app
위 명령어를 실행하면 nodemailer-app이라는 이름의 새 프로젝트가 생성됩니다.
프로젝트 폴더로 이동한 후, Nodemailer 관련 패키지와 타입 정의를 설치합니다.
$ npm i --save @nestjs-modules/mailer nodemailer
$ npm i --save-dev @types/nodemailer
앱에서 Nodemailer 구성하기
진행하기 전에 mailtrap.io 계정이 있는지 확인하세요. 계정이 있다면 로그인 후 Email Testing 메뉴로 이동합니다. 받은 편지함(Inbox)이 없다면 새로 하나 생성하고, 해당 편지함으로 들어가면 애플리케이션에서 Nodemailer를 설정할 때 사용할 자격 증명(인증 정보)을 확인할 수 있습니다.
프로젝트 디렉터리에서 app 모듈 파일을 열고 패키지를 다음과 같이 구성합니다.
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { MailerModule } from '@nestjs-modules/mailer';
@Module({
imports: [
AuthModule,
MailerModule.forRoot({
transport: {
host: process.env.EMAIL_HOST,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD,
},
},
}),
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
위 코드에서는 @nestjs-modules/mailer에서 MailerModule을 가져온 후, forRoot() 메서드를 호출했습니다. forRoot() 메서드 내부에는 transport 속성을 지정했으며, 이 속성에는 host와 auth 정보가 포함됩니다.
mailtrap.io의 받은 편지함에 있는 자격 증명에서 호스트(host), 포트(port), 사용자 이름(username), 비밀번호(password) 값을 반드시 확인해서 사용하세요.
이러한 자격 증명 정보는 .env 파일에 따로 보관하는 것이 좋습니다. NestJS에서 .env 파일을 불러오려면 다음 패키지를 설치해야 합니다.
$ npm i --save @nestjs/config
그런 다음 app.module.ts 파일에 ConfigModule을 임포트합니다.
import { ConfigModule } from '@nestjs/config';
같은 app.module.ts 파일의 imports 배열에 Config 모듈을 추가합니다.
// imports 배열에 config 모듈을 포함시킵니다
@Module({
imports: [
ConfigModule.forRoot({ envFilePath: '.env', isGlobal: true }),
],
controllers: [AppController],
providers: [AppService],
})
Nodemailer로 이메일 전송하기
Nodemailer 구성이 끝났다면, 이제 실제로 이메일을 전송해 볼 차례입니다.
app.service.ts 파일에 다음 코드를 붙여 넣으세요.
import { MailerService } from '@nestjs-modules/mailer';
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
constructor(private readonly mailService: MailerService) {}
sendMail() {
const message = `Forgot your password? If you didn't forget your password, please ignore this email!`;
this.mailService.sendMail({
from: 'Kingsley Okure <kingsleyokgeorge@gmail.com>',
to: 'joanna@gmail.com',
subject: `How to Send Emails with Nodemailer`,
text: message,
});
}
}
app.service.ts 파일에서는 MailerService가 의존성 주입(DI) 방식으로 클래스에 주입되어 이메일 전송에 사용됩니다. 클래스 내부에서 MailerService의 sendMail 함수를 호출하며, 이 함수는 객체를 매개변수로 받습니다. 객체에는 from(발신자), to(수신자), subject(제목), text(본문) 속성이 담겨 있습니다.
서비스 코드 작성이 완료되면, app.controller.ts 파일에 다음 코드를 붙여 넣습니다.
import { Controller, Get, Res } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
sendMailer(@Res() response: any) {
const mail = this.appService.sendMail();
return response.status(200).json({
message: 'success',
mail,
});
}
}
컨트롤러에서 하는 일은 간단합니다. GET 요청 엔드포인트를 만들어 서비스에 정의한 sendMail 함수를 호출하는 것입니다.
실제 운영 환경의 애플리케이션에서는 이 모든 과정이 비밀번호 찾기 기능 안에서 처리될 것입니다. 즉, 사용자가 비밀번호 찾기 경로를 클릭하는 순간 이메일이 발송되는 방식입니다.
이 간단한 설정을 테스트하려면 Postman을 열고 localhost:3000으로 요청을 전송해 보세요.
그런 다음 mailtrap.io의 받은 편지함으로 이동하면 전송된 메시지를 확인할 수 있습니다.
마무리
이번 글에서는 개발자가 여러 사람에게 한 번에 이메일을 보낼 수 있도록 설계된 소프트웨어인 Nodemailer를 사용해 이메일을 전송하는 방법을 배웠습니다.
또한 NestJS 애플리케이션 환경에서 Nodemailer를 설정하고 구성하는 방법도 함께 익혔습니다.
저와 연결하고 싶으시다면 Twitter나 LinkedIn에서 팔로우해 주세요.