포시코딩

[Nest.js] 이메일 인증 시스템 (1). nodemailer 본문

Node.js

[Nest.js] 이메일 인증 시스템 (1). nodemailer

포시 2023. 2. 23. 16:24
728x90

개요

위와 같은 회원가입 폼에서 이메일 입력 후 인증번호 전송을 누르면

해당 이메일로 랜덤한 6자리 숫자의 인증번호가 보내지고

 

사용자는 이메일에서 인증번호를 확인 후 인증번호 란에 입력한다음 인증번호 확인 버튼을 눌러 

인증을 거치는 과정을 구현해보고자 한다.

 

회원가입 후 이메일을 보내 사용자 인증을 거치는 과정도 괜찮지만

이메일을 잘못 입력 후 회원가입 할 경우를 고려해 위와 같은 방식으로 진행했다.

 

설치

$ npm i nodemailer
$ npm i @types/nodemailer --save-dev

 

코드

email.service.ts

interface EmailOptions {
  to: string;
  subject: string;
  html: string;
}

@Injectable()
export class EmailService {
  private transporter: Mail;

  // nodemailer에서 제공하는 Transporter 객체 생성
  constructor(
    private readonly configService: ConfigService
  ) {
    this.transporter = nodemailer.createTransport({
      service: 'Gmail',
      auth: {
        user: this.configService.get<string>('EMAIL_USER'),
        pass: this.configService.get<string>('EMAIL_PASS'),
      },
    });
  }

  async sendVerifyToken(email: string, verifyToken: number) {
    const mailOptions: EmailOptions = {
      to: email,
      subject: '[찰칵] 이메일 확인',
      html: `인증번호: ${verifyToken}`,
    }
    // transporter 객체를 이용해 메일 전송
    return await this.transporter.sendMail(mailOptions);
  }
}

nodeMailer를 통해 메일을 보낼 수 있게 세팅해준다.

auth의 user와 pass에는 발신을 보낼 이메일과 앱 비밀번호를 세팅해주면 되는데

코드에 하드코딩 하지 않고 .env를 활용하기 위해 ConfigService를 inject 해줬다.

 

html 항목에서 메일을 받았을 때 보기 좋게 꾸미는 것도 가능하다.

 

.env

EMAIL_USER='test@gmail.com'
EMAIL_PASS='abcdedfg'

참고로 로그인 할 때 쓰는 비밀번호가 아닌 앱 비밀번호를 사용해야 하는데

설정은 구글 -> 내 계정 -> 보안 탭에서 할 수 있다.

 

 

Controller

@Post('/verifyEmail')
async sendVerification(@Body() body) {
  return await this.usersService.sendVerification(body.email);
}

인증번호 전송을 누르면 왼쪽에 입력한 이메일을 body로 넣어 POST 요청을 보낸다. 

 

user.service.ts

@Injectable()
export class UsersService {
  constructor(private readonly emailService: EmailService) {}

  async sendVerification(email: string) {
    const verifyToken = this.generateRandomNumber();
    
    console.log('캐싱할 데이터: ', email, verifyToken);
    // TODO: verifyToken이랑 이메일 캐싱

    await this.sendVerifyToken(email, verifyToken);
  }
  
  async sendVerifyToken(email: string, verifyToken: number) {
    await this.emailService.sendVerifyToken(email, verifyToken);
  }

  async verifyEmail(email:string, verifyToken: number) {
    console.log('verifyEmail: ', email, verifyToken);
    // TODO: 캐싱된 데이터 찾기. 있으면 200, 없으면 Exception
    return;
  }

  private generateRandomNumber(): number {
    var minm = 100000;
    var maxm = 999999;
    return Math.floor(Math.random() * (maxm - minm + 1)) + minm;
  }
}

sendVerification() 메서드로 들어오게되며

generateRandomNumber() 메서드를 통해 랜덤한 6자리 숫자로 이루어진 verifyToken을 발급 받고 

아직 작성되진 않았지만 이메일과 토큰을 캐시 매니저를 통해 저장할 계획이다. 

 

이후 sendVerifyToken() 를 통해 맨 위에 나온 email.service의 sendVerify()로 가 메일을 전송하게 된다.

 

생성자에서 EmailService를 inject 한 모습을 볼 수 있다.

 

users.module.ts

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UsersController],
  providers: [UsersService, EmailService]
})
export class UsersModule {}

당연하지만 inject 하기 위해서는 module의 providers에 추가해줘야 한다.

 

정리

참고한 곳

https://velog.io/@mageboy/server-Nest.js-회원가입-및-이메일-인증-구현-연습

 

[server] Nest.js 회원가입 및 이메일 인증 구현 연습

참조: https://wikidocs.net/158501목표: 유저 이메일주소를 입력하면 유저 이메일보관함으로 회원가입인증메일이 날아옴메일에 포함된 인증버튼을 누르면 서버에서 uuid가 날아옴참조: https://wikidocs.net/

velog.io

이 글은 위 블로그를 통해 매우매우 많은 도움을 얻어 작성되었다.

위 블로그의 글이 회원가입 후 이메일을 보내 사용자 인증을 거치는 과정이니

해당 과정으로 구현하고 싶으면 들어가서 참고.

 

 

메일을 발송하는 서비스이기 때문에 비용도 그렇고 

무슨 AWS SES를 써야 한다느니 해서 AWS에 대한 두려움도 들어

구현하기에 앞서 겁을 좀 먹은 상태였는데

 

막상 구현해보니 정말 별거 아니었다.

nodemailer를 통해 아주 쉽게 구현할 수 있었고

무엇보다 평소에 메일 보낼 때 돈도 안드는데 왜 비용에 대해 겁을 먹었는지 모르겠다.

 

물론 특정 서비스를 하게 된다면 해당 서비스의 메일 계정을 만들어 계정 값이 들긴 하겠지만

이렇게 임의의 개인 메일을 만들어 사용한다면 문제 없을듯

 

다음 포스팅에선 캐시 매니저(Cache Manager)를 통해 이메일과 토큰을 저장하고

인증 확인 과정을 거치는 과정을 진행할 예정이다.

 

관련 코드는 아래 GitHub에서 확인 가능하다.

https://github.com/cchoseonghun/nestjs_sample

 

GitHub - cchoseonghun/nestjs_sample: Sample Back-End project using Nest.js. with Front-end using ejs or React.js

Sample Back-End project using Nest.js. with Front-end using ejs or React.js - GitHub - cchoseonghun/nestjs_sample: Sample Back-End project using Nest.js. with Front-end using ejs or React.js

github.com

728x90