군붕이의 메모장

Nodemailer + Gmail OAuth2.0으로 이메일 발송기능 구현하기 본문

웹 개발/기타 지식

Nodemailer + Gmail OAuth2.0으로 이메일 발송기능 구현하기

초보군붕이 2023. 2. 18. 21:00
반응형

 

회원가입시 이메일 인증을 위해 Nodemailer 라이브러리를 통해 제작하려고 했다.

 

하지만 어째서인지 공식문서에 있는 로그인방식대로 하면 에러가 발생해서 관련해서 정리해둘려고 한다.

 

우선 2022.05.30부터 기존 존재하던 구글 이메일, 비밀번호 기반 인증으로는 더이상 이메일 발송이 불가능해졌다.

 

Google 약관

 

nodemailer에서 Gmail을 통해 이메일발송을 구현하기 위해선 OAuth2.0 인증이 필요하게 되었다.

 

● 절차

  1. 구글 개발자 콘솔에서 프로젝트 생성 후 Gmail API 사용하기
  2. OAuth 사용 동의하기
  3. OAuth2.0 클라이언트 아이디 생성하기
  4. 리프레쉬 토큰과 엑세스 토큰 발급받기
  5. 발급받은 코드로 Nodemailer를 사용해서 이메일 발송하기

 

 

● 구글 개발자 콘솔에서 프로젝트 생성 후 Gmail API 사용하기

구글 개발자 콘솔 URL : https://console.cloud.google.com/projectselector2/apis/dashboard?supportedpurview=project 

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

 

 

프로젝트 선택을 눌러준다

 

새 프로젝트를 눌러준다.

 

 

API 및 서비스 사용설정을 눌러준다.

 

 

 

gmail을 검색해준다.

 

Gmail API 를 클릭해서 사용 버튼을 눌러준다.

 

● OAuth 사용 동의하기

좌측상단 메뉴에서 API 및 서비스OAuth 동의 화면을 들어가준다.

 

 

내부의 경우 G Suite, Google Workspace 등 조직 내부 사용자들을 위한 사용자 유형으로 외부를 체크해준다.

 

 

앱의 이름과 사용자 지원 이메일을 입력해준다. 이 때 동일하게 해도 상관없다.

 

 

개발자의 연락처 정보를 입력해준다. 나는 내가 주로 사용하는 이메일을 입력했다.

 

 

테스트 사용자에 사용자의 이메일을 입력해준다. 

 

 

● OAuth2.0 클라이언트 아이디 생성하기

 

좌측 메뉴에서 사용자 인증 정보에 접속한 뒤 사용자 인증 정보 만들기에서 OAuth 클라이언트 ID를 눌러준다.

 

나는 nodejs 환경의 웹앱에서 사용할 예정이므로 유형을 웹 애플리케이션을 지정했고 이름은 자유롭게 해주면 된다.

또한 승인된 리디렉션 URI는 "https://developers.google.com/oauthplayground" 입력해준다.

 

클라이언트 아이디가 생성되면 아래처럼 확인이 가능하다. 외부에 노출되면 안되니 주의하자.

 

 

● 리프레쉬 토큰과 엑세스 토큰 발급받기

우선 클라이언트 아이디를 생성할 때 리다이렉트 URI에 입력한 oauthplayground에 접속해준다

 

Google OAuthplayground : https://developers.google.com/oauthplayground

 

OAuth 2.0 Playground

Request Body Manual entry Enter the data that will be added to the body of the request: File You may choose to send a file as part of the request. When both a file and manual content are provided both will be sent using a multipart request. You may send fi

developers.google.com

 

홈페이지 접속 후 좌측에 설정버튼을 눌러서 Use your own OAuth credentials을 체크해준다.

 

그러면 아래 클라이언트 아이디와 시크릿키 입력칸이 나오는데 생성했던 값을 넣어준다.

 

 

검색기능이 왜 없는지 모르겠지만 스크롤을 내려서 Gmail API v1 을 찾고 바로 아래 mail.google.com을 눌러준다.

 

그 후 Authorize APIs을 눌러준다.

 

계정을 선택하고 나면 이런 창이 뜰텐데 계속 버튼을 눌러준다.

 

그 후 창이 리다이렉션 되면서 Steop2에 있는 Exchange auth... 버튼을 눌러주면 토큰이 발급된다.

 

Authorization code : 위 과정을 거치면서 발급받은 코드

Refresh Token : Access Token이 만료되거나 없을때 재발급을 위한 코드

Access Token : 인증을 위한 토큰으로 구글의 경우 3600초 즉 1시간이 지나면 만료된다.

 

 

 

● Nodemailer를 사용해서 이메일 발송하기

여기까지 왔다면 거의 다했다. 이제 발급받은 토큰을 이용해서 메일만 발송하면 된다.

 

1. nodemailer 설치하기

우선 npm을 통해서 nodemailer를 설치해준다. (타입스크립트 환경의 경우 types 패키지도 다운로드 해야된다)

# NPM
npm i nodemailer

# NPM with Typescript
npm i nodemailer
npm i -D @types/nodemailer

 

 

2. 토큰 안전하게 관리하기

위 과정에서 발급받은 토큰은 외부에 공개되면 안된다.보안을 위해 .env 파일에서 관리해준다.

// .env

# GMAIL OAUTH
GMAIL_OAUTH_USER= # Oauth Client에서 테스트 사용자로 등록된 이메일 주소
GMAIL_OAUTH_CLIENT_ID= # OAuth Client의 아이디
GAMIL_OAUTH_CLIENT_SECRET= # OAuth Client의 보안 비밀번호
GAMIL_OAUTH_REFRESH_TOKEN= # playground에서 발급받은 리프레쉬 토큰
// config.ts
import dotenv from "dotenv";
dotenv.config();

export default {
  // ...other configures
  mailer: {
    gmailUser: process.env.GMAIL_OAUTH_USER,
    gmailClientId: process.env.GMAIL_OAUTH_CLIENT_ID,
    gmailClientSecret: process.env.GAMIL_OAUTH_CLIENT_SECRET,
    gmailRefreshToken: process.env.GAMIL_OAUTH_REFRESH_TOKEN,
  },
};

 

3. nodemailer 설정하기

import { createTransport } from "nodemailer";

static register = async (userDTO: RegisterUserDTO) => {
  try {
    // ... 회원가입 관련 로직들
    const transporter = createTransport({
      service: "gmail",
      host: "smtp.gmail.com",
      port: 587,
      secure: true,
      auth: {
        type: "OAuth2",
        user: config.mailer.gmailUser,
        clientId: config.mailer.gmailClientId,
        clientSecret: config.mailer.gmailClientSecret,
        refreshToken: config.mailer.gmailRefreshToken,
      },
    });

    const mailOptions = {
      to: userDTO.email,
      subject: "[헬로디벨로퍼] 회원가입 이메일 인증 메일입니다.",
      html: `인증링크 : <a href="http://www.naver.com?token=${emailVerifyToken}">여기를 눌러주세요</a>`,
    };

    await transporter.sendMail(mailOptions);
  } catch (err: any) {
    console.error(err)
  }
};

 

 

결과

 

메일이 잘 발송되었음을 볼 수 있다.

 

참고자료 : https://devdotcode.com/how-to-send-email-from-node-js-api-using-gmail/

반응형