저번 포스트에 이어서 이메일이 가입자 본인의 이메일이 맞는지 확인 하는 로직을 구현 해보겠다.
우선, 이메일 서비스를 직접 만드는 것도 좋지만 비지니스에 더 집중하기 위하여 이미 구현되어 있는 라이브러리를 사용하는 경우가 많다. 외부 이메일 서비스를 고를 때 고려할 점은 다음과 같다.
- 이메일 전송 안정성
- 전송기록 확인
- 이메일 보안 및 스팸 처리
- 바운스 (이메일이 반송되는 경우) 처리
- 등등
여기에서는 간단하게 무료로 사용가능한 nodemailer라는 라이브러리를 사용할 것이다.
$ npm i nodemailer
$ npm i @types/nodemailer --save-dev
UserService는 유저에 대한 정보를 다루는 로직을 담고 있는 역할을 하므로, EmailService라는 새로운 Email 관련 로직을 다루는 프로바이더를 생성하자.
$ nest g s Email
우선 이전의 포스트에서 이런식으로 메서드를 구현했는데,
import { EmailService } from 'src/email/email.service'; export class UsersService { constructor(private emailService: EmailService) { } ... private async sendMemberJoinEmail(email: string, signupVerifyToken: string) { await this.emailService.sendMemberJoinVerification(email, signupVerifyToken); } }
이제 이 EmailService에 대해서 구현을 하면 되겠다.
import Mail = require('nodemailer/lib/mailer');
import * as nodemailer from 'nodemailer';
import { Injectable } from '@nestjs/common';
//sendMail()의 인수로 전달 될 이메일의 옵션 타입
interface EmailOptions {
to: string;
subject: string;
html: string;
}
@Injectable()
export class EmailService {
private transporter: Mail;
constructor() {
//nodemailer가 제공하는 트랜스포터의 객체를 생성한다.
this.transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: 'YOUR_EMAIL',
pass: 'YOUR_PASSWORD',
},
});
}
async sendMemeberJoinVerification(emailAddress: string, singupVerifyToken: string) {
const baseUrl = 'http://localhost:3000';
const url = `${baseUrl}/users/email-verify?signupVerifyToken=${signupVerifyToken}`;
const mailOptions: EmailOptions = {
to: emailAddress,
subject: '가입 인증 메일',
// 이 부분에서는 사용자가 받을 이메일 부분의 html코드를 작성하면 된다.
html: `
<form action="${url}" method="POST">
<button>가입 확인</button>
</form>
`
}
// transporter 객체를 사용하여 메일을 전송한다.
return await this.transporter.sendMail(mailOptions);
}
}
이 부분에서 유리가 유의해야할 부분은 이메일이라던지 비밀번호 같은 것들의 부분들이 모두 하드 코딩으로 구성되어 있다는 것이다. 우리는 이를 dotenv
라는 라이브러리를 활용하여 환경변수를 사용하여 한꺼번에 관리 할 수 있다.
추가적으로 비밀번호 부분의 그냥 사용자의 비밀번호를 입력하면 Gmail에서는 이 nodemailer로 발송한 메일을 보안이 낮은 앱이 보낸 것으로 판단하여 에러를 발생시키는데, 이와 같은 경우에는 2단계인증을 활성화하여 앱 비밀번호를 생성하여 사용하면 해결된다.
이 포스트는 위 책을 기반으로 작성하고 있습니다...