備忘録

備忘録

Node.jsでnodemailerを利用してGmailを送信する方法

Ⅰ. はじめに

Gmailは2022年5月30日に「安全性の低いアプリ」からのアクセスを終了します。
例えばSMTPでパスワード認証を利用している場合が該当します。
この記事ではOAuth認証をする事によって2022年5月30日以降もメールを送信する方法を紹介します。

Ⅱ. 手順

1. OAuth用の認証情報を作成する

https://console.cloud.google.com/apis/credentials

※「アプリケーションの種類」は「デスクトップアプリ」を選択する
※プロジェクトの新規作成を求められた場合は新規作成する。
 スコープを指定する必要はない。
※OAuth同意画面の新規作成を求められた場合は新規作成する。
 公開ステータスがテストの場合はテストユーザーを追加する。

2. 「クライアントID」「クライアントシークレット」をメモする


3. 以下スクリプトを実行して「リフレッシュトークン」を取得する

※2022/03/31 追記
「urn:ietf:wg:oauth:2.0:oob」が非推奨になったようです
以下スクリプトはテスト環境のみで動作します
https://takuya-1st.hatenablog.jp/entry/2022/03/14/171939

index.mjs

// Node v18.9.1で動作確認
// npm install open node-fetch
import readline from 'node:readline/promises'
import open from 'open'
import fetch from 'node-fetch'

function generateQueryString (parameters) {
  return parameters.map(x => `${x.key}=${encodeURI(x.value)}`).join('&')
}

(async () => {
  const clientId = 'ENTER_YOUR_CLIENT_ID'
  const clientSecret = 'ENTER_YOUR_CLIENT_SECRET'

  const redirectUri = 'urn:ietf:wg:oauth:2.0:oob'
  const parameters = [
    { 'key': 'client_id', value: clientId },
    { 'key': 'redirect_uri', value: redirectUri },
    { 'key': 'response_type', value: 'code' },
    { 'key': 'scope', value: 'https://mail.google.com/' }
  ]
  const url = `https://accounts.google.com/o/oauth2/auth?${generateQueryString(parameters)}`
  open(url)
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
  const code = await rl.question('Enter code:');
  console.log(code)

  const response = await fetch('https://www.googleapis.com/oauth2/v4/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: generateQueryString([
      { 'key': 'client_id', 'value': clientId },
      { 'key': 'client_secret', 'value': clientSecret },
      { 'key': 'redirect_uri', 'value': redirectUri },
      { 'key': 'grant_type', 'value': 'authorization_code' },
      { 'key': 'code', 'value': code }
    ])
  })
  const json = await response.json()
  console.log(json)
})()
4. 以下スクリプトを実行してメールを送信する

index.mjs

// npm install nodemailer
import nodemailer from 'nodemailer'

(async () => {
  const clientId = 'ENTER_YOUR_CLIENT_ID'
  const clientSecret = 'ENTER_YOUR_CLIENT_SECRET'
  const to = 'user001@example.com'
  const myGmailAddress = 'user002@gmail.com'
  const refreshToken = 'ENTER_YOUR_REFRESH_TOKEN'

  const transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 465,
    secure: true,
    auth: {
      type: 'OAuth2',
      clientId: clientId,
      clientSecret: clientSecret,
    }
  })

  transporter.on('token', token => {
    console.log(`AccessToken: ${token.accessToken}`)
    console.log(`Expires: ${new Date(token.expires)}`)
  })

  const response = await transporter.sendMail({
    to: to,
    subject: 'Subject',
    text: 'Hello world!',
    auth: {
      user: myGmailAddress,
      // accessToken: 'ya29....',
      refreshToken: refreshToken
    }
  })

  console.log(response)
})()

実行結果

省略