Nodemailer X Gmail OAuth 2.0

정적의 마도사·2021년 1월 20일
6

web-backend

목록 보기
1/1
post-thumbnail

사진 출처:
https://www.woolha.com/tutorials/node-js-send-email-using-gmail-with-nodemailer-oauth-2


Index

  1. Objective

  2. Google Gmail API

  3. Google OAuth 2.0 Playground

  4. Nodemailer


0. Objective

  • Nodemailer에서 Gmail을 "보안 수준이 낮은 앱" 설정을 하지 않고 사용할 수 있다.
  • Google 프로젝트를 사용하여 OAuth2 인증을 설정할 수 있다.
  • Nodemailer와 OAuth2를 연결한 Google 프로젝트를 연동할 수 있다.

1. Google Gmail API

Google 개발자 콘솔에서 프로젝트 만들기

이 섹션은 Google 개발자 콘솔을 처음 사용하는 사람들을 위한 섹션이다.
따라서 Google 개발자 콘솔을 사용해서 프로젝트를 생성해본 사람은 이 섹션을 건너뛰어도 좋다.

먼저 Google 개발자 콘솔에 로그인한다.

그러면 API 콘솔에 들어오게 되는데, 여기서 "프로젝트 선택" 이라는 버튼이 보일 것이다.

이 버튼을 클릭하면 프로젝트를 선택하는 창이 보인다. 여기서 Gmail API를 적용시킬 기존 프로젝트를 선택하거나 새 프로젝트를 생성한다.

새 프로젝트를 생성할 때에는 기존 프로젝트와 겹치는 이름을 설정할 수 없고, 프로젝트 ID의 경우는 추후에 변경할 수 없다. 프로젝트 ID를 수정하고 싶으면 "수정" 버튼을 눌러 수정할 수 있다.

조직의 경우 기본으로 설정된 "조직 없음" 그대로 해놔도 좋다. 설정을 마쳤으면 "만들기"를 클릭한다. 그러면 프로젝트가 생성되는 것을 볼 수 있다.

프로젝트가 생성되었다고 알림이 오면 프로젝트를 선택한다.

프로젝트를 선택하면 처음에 클릭했던 "프로젝트 선택"이 프로젝트 이름으로 바뀐 것을 확인할 수 있다.

Gmail API 적용하기

프로젝트를 생성했다면 해당 프로젝트의 "API 및 서비스 사용 설정"에 들어간다.

그러면 API 라이브러리를 볼 수 있다. 여기서 검색창에 "gmail api"를 검색하면 나오는 "Gmail API"를 클릭하여 들어간 후 "사용"을 클릭한다.

조금 기다린 뒤에 해당 API의 대쉬보드로 이동한 것을 볼 수 있다.

OAuth 동의 화면 설정

API 콘솔에서 맨 왼쪽 위의 탐색 아이콘을 누른 뒤 "API 및 서비스"의 "OAuth 동의 화면"을 클릭한다.

OAuth 동의 화면에 들어오면 User Type을 선택해야 하는데, "내부" 타입은 G Suite 사용자만 해당되기 때문에 여기서는 "외부" 타입을 선택해주면 된다. 선택한 후에 "만들기"를 클릭한다.

OAuth 타입 등록을 마치면 앱 등록 화면으로 넘어오는데, 여기서 앱 이름과 지원 이메일, 그리고 개발자 연락처 이메일을 작성해야 한다. 지원 이메일은 사용자의 질의를 받기 위한 메일이고, 개발자 연락처 이메일은 Google에서 프로젝트 변경사항 알림을 받기위한 메일이다. 즉, 둘 다 동일하게 설정해도 문제없다. 작성 후에 "저장 후 계속"을 클릭한다.

범위 설정은 이 글에서 다루지 않도록 하겠다. 따라서 "저장 후 계속"을 한번 더 클릭한다.

다음은 테스트 사용자를 등록하는 화면이다. 물론 정식 배포 시에는 등록한 앱을 인증하여 정식 사용자를 등록하는 것이 맞지만, 여기서는 테스트 사용자 이메일을 등록하도록 하겠다. 테스트 사용자는 최대 100명까지 추가할 수 있으며, 사용자 이메일 주소는 Gmail만 사용할 수 있다.

"ADD USERS"를 클릭하여 들어간 후 OAuth 테스트 사용자 Gmail 주소를 등록한 후 "추가"를 클릭하면 사용자 수가 변경된 것을 확인할 수 있다. 테스트 사용자를 추가했으면 "저장 후 계속"을 클릭한다.

"요약" 화면으로 넘어오면 이제까지 OAuth 동의 화면에서 설정했던 내용들을 살펴볼 수 있다.

OAuth 2.0 클라이언트 ID 만들기

"API 및 서비스" 밑에 "사용자 인증 정보"를 클릭한다. 그 후 "사용자 인증 정보 만들기"를 클릭하여 뜨는 메뉴 중 "OAuth 클라이언트 ID"를 선택한다.

그러면 OAuth 클라이언트 설정 화면으로 넘어오는데, 처음에 "애플리케이션 유형"에서는 node.js를 사용할 것이기 때문에 "웹 애플리케이션"을 선택한다. 웹 클라이언트의 적당한 이름도 지어준다.

"승인된 자바스크립트 원본" 설정은 건너뛰고, "승인된 리디렉션 URI"에서 "URI 추가"를 클릭하고 https://developers.google.com/oauthplayground정확하게 한 글자도 안 틀리게 기재한다. 만약 끝에 "/"를 붙여서 등록하게 되면 나중에 설정할 OAuth Playground에서 URI 에러가 생긴다. 작성을 마쳤으면 "만들기"를 클릭한다. (솔직히 다른데도 아니고 Google에서 이런다는 건 좀 이해가 많이 안 된다.)

그러면 OAuth 클라이언트가 생성되었다는 화면이 뜨고 클라이언트 ID와 클라이언트 보안 비밀번호를 보여준다. 이것을 복사해서 나중에 OAuth Playground 설정에서 사용할 것이다. "사용자 인증 정보"에서 해당 OAuth 클라이언트 이름을 클릭하여 다시 확인할 수 있으니 미리 복사할 필요는 없다.


2. Google OAuth 2.0 Playground

OAuth 2.0 Configuration

먼저 Google OAuth 2.0 Playground로 이동한다.

그 뒤에 설정 아이콘을 클릭해서 "OAuth 2.0 Configuration" 창에 들어간 후, "Use your own OAuth credentials" 체크박스를 선택한다. 그리고 나타나는 "OAuth Client ID"칸에는 직전에 만들었던 OAuth 클라이언트의 ID를, "OAuth Client secret"칸에는 해당 클라이언트 보안 비밀을 입력해준 후 "Close"를 클릭하여 창을 닫는다.

이제 이 설정을 가지고 OAuth Client를 OAuth Playground와 연동할 것이다.

Select & authorize APIs

이제 Gmail API를 OAuth Playground와 연결할 것이다.

왼쪽의 "Step 1 Select & authorize APIs" 밑에 "Input your own scopes"에 https://mail.google.com을 입력한 후 "Autorize APIs"를 클릭한다.

계정을 선택하는 창으로 넘어오면 OAuth Client 테스트 사용자로 등록했던 Gmail 계정을 선택한다. (테스트 사용자로 등록했던 Gmail로 로그인이 안 되어 있다면 로그인해서 해당 계정을 선택해야 한다. 안 그러면 access 거부 에러가 생긴다.)

계정을 선택하면 다음과 같은 창이 뜨는데, 처음부터 앱을 확인받지 않고 쓰려했기 때문에 고민하지 않고 "계속"을 클릭한다. 그 뒤로 앱 권한을 허용하면 API 인증이 완료된다.

Exchange authorization code for tokens

API 인증을 완료하면 "Step 2 Exchange authorization code for tokens" 밑에 요상한 것들이 뜨는데, 하나씩 설명하자면 다음과 같다.

  • Authorization code: 이전 단계에서 API 인증 후에 받은 코드이다.
  • Refresh token: OAuth2 인증을 위해서 받는 Access token가 만료되거나 없을 때 재발급을 받기 위한 토큰이다. Access token 발급에 필수적인 요소이다.
  • Access token: OAuth2 인증을 위한 토큰으로 일정 시간이 지나면 만료된다. Google OAuth에서 발급하는 토큰의 경우 생성하고 3600초(1시간) 후에 만료된다. Refresh token만 있으면 해당 토큰을 발급받을 수 있기 때문에 이 글에서는 따로 복사하여 사용하지는 않는다.

"Authorization code" 밑의 "Exchange autorization code for tokens"를 클릭한다.

클릭하면 Step 3로 자동으로 넘어가는데, 다시 Step 2로 돌아오면 Refresh token과 Access token을 발급받은 것을 볼 수 있다. 여기서 Refresh token만 따로 복사해놓는다.


3. Nodemailer

테스트 프로젝트 만들기

이제는 Node.js 테스트 프로젝트를 만들어 볼 것이다.

테스트 프로젝트는 nodemailer 패키지 이외에도 .env 파일의 프로젝트 환경변수들을 불러오는 dotenv 패키지를 추가로 설치할 것이다. OAuth 인증을 위해서 사용하는 OAuth Client ID, Client Secret과 Refresh Token은 모두 민감한 정보이기 때문에 아무리 테스트 프로젝트여도 코드에 직접 기재하는 만행을 저지르지는 않을 것이다.

먼저 테스트 디렉터리를 만들고 그 안에서 다음 명령어로 테스트 프로젝트를 생성한다.

// npm
npm init --yes

// yarn
yarn init --yes

프로젝트 생성 후에 nodemailer와 dotenv 패키지를 설치한다.

// npm
npm install --save nodemailer dotenv

// yarn
yarn add nodemailer dotenv

설치를 완료했으면 먼저 .env 파일을 만들고 다음과 같이 작성한다. {{ }} 안의 내용은 각자에 맞게 기재한다.

# Gmail OAuth 2.0
OAUTH_USER={{ OAuth Client에서 테스트 사용자로 등록된 Gmail 주소 }}
OAUTH_CLIENT_ID={{ OAuth Client ID }}
OAUTH_CLIENT_SECRET={{ OAuth Client 보안 비밀 }}
OAUTH_REFRESH_TOKEN={{ 발급받은 Refresh token }}

.env 파일 저장 후 index.js 파일을 만들고 다음과 같이 작성한다.

const nodemailer = require('nodemailer');
const dotenv = require('dotenv');

dotenv.config();

const {
  OAUTH_USER,
  OAUTH_CLIENT_ID,
  OAUTH_CLIENT_SECRET,
  OAUTH_REFRESH_TOKEN,
} = process.env;

if (
  !OAUTH_USER || 
  !OAUTH_CLIENT_ID || 
  !OAUTH_CLIENT_SECRET || 
  !OAUTH_REFRESH_TOKEN
) {
  throw Error('OAuth 인증에 필요한 환경변수가 없습니다.');
}

async function main(receiverEmail) {

  const transporter = nodemailer.createTransport({
    service: 'gmail',
    host: 'smtp.google.com',
    port: 587,
    secure: true,
    auth: {
      type: 'OAuth2',
      user: OAUTH_USER,
      clientId: OAUTH_CLIENT_ID,
      clientSecret: OAUTH_CLIENT_SECRET,
      refreshToken: OAUTH_REFRESH_TOKEN,
    },
  });
  
  const message = {
    from: OAUTH_USER,
    to: receiverEmail,
    subject: 'Nodemailer X Gmail OAuth 2.0 테스트',
    html: `
      <h1>
        Nodemailer X Gmail OAuth 2.0 테스트 메일
      </h1>
      <hr />
      <br />
      <p>축하하네, 구도자여!<p/>
      <p>자네는 모든 시련과 역경을 이겨냈네. 하산하시게나!</p>
      <br />
      <hr />
      <p>이 메일은 Gmail API를 써보고 싶은 정신나간 개발자에 의해서 발송되었습니다.</p>
      <p>이 메일을 요청한 적이 없으시다면 무시하시기 바랍니다.</p>
    `,
  };
  
  try {
    await transporter.sendMail(message);
    console.log('메일을 성공적으로 발송했습니다.');
  } catch (e) {
    console.log(e);
  }

}

main({{ 수신자 이메일 주소 }});

{{ }} 안에는 자신이 메일을 확인할 수 있는 이메일 주소를 기재한다.

테스트 메일 전송

다 작성했으면 index.js를 실행하고 결과를 확인한다.

node index.js

"메일을 성공적으로 발송했습니다."라는 콘솔 문구와 함께 메일을 잘 받았다면 성공이다.


References

4개의 댓글

comment-user-thumbnail
2021년 11월 28일

그대로 따라하니까 바로 되네요!
덕분에 시간 많이 벌었습니다. 감사해요

답글 달기
comment-user-thumbnail
2022년 5월 24일

와 진짜 너무감사합니다 ㅠㅠ!!!!!

답글 달기
comment-user-thumbnail
2022년 6월 13일

안녕하세요 혹시 위에대로 사용하다보면
refreshToken 만료되고 나면 메일전송이 에러나는데
이문제는 어떻게 해결 하셨나요

1개의 답글