0%

Express.js - Gmail 發送信件實作 + OAuth 2.0

前言

原本在 nodemailer 中輸入 Gmail 的帳號密碼就能夠發送信件,但 Google 基於安全性考量,在近幾年推出 OAuth 2.0 驗證機制。也就是必須跟 Google 取得 token 才能使用該帳號進行寄信功能

建立 OAuth

首先到 Google Cloud Platform 創建一個新專案
Google Cloud Platform
新增專案
創建完專案後,到左邊選單找到 API 服務,並點選啟用 API 服務
API 服務
搜尋 Gmail API,然後點選 啟用
Gmail API
Gmail API 啟用
啟用之後會來到 Gmail API 頁面,接下來要建立憑證。
點擊左方 憑證 然後 建立憑證 選擇 OAuth 用戶端ID
接著會要求同意設定
同意設定
User Type 選擇 外部
User Type
接下來只需填寫名稱並儲存即可
OAuth 同意畫面
到左邊選 憑證 建立憑證 選擇 OAuth 用戶端ID
選擇憑證
選擇 網路應用程式,並且在下方 已授權的重新導向URL 中填入 https://developers.google.com/oauthplayground
網路應用程式
完成後會得到兩筆資料 用戶端ID用戶端密鑰 ,之後會用到。
OAuth

取得 Refrsh Token

開啟 https://developers.google.com/oauthplayground ,點選右上角齒輪,將 Use your own OAuth credentials打勾,並填入剛剛取得的 Client ID 以及 Client Secret
Client ID 以及 Client Secret
左邊的部分輸入 https://mail.google.com/後按下 Authorize APIs
Authorize APIs
選擇要使用的 Google 帳戶
Google 帳戶
這邊因為 Google 的安全機制會先擋一下,只需在 進階 裡面點選前往連結即可。
未經驗證
進入之後 Google 會再詢問一次是否允許。
權限授予
再驗證一次是否允許應用程式
應用程式權限
接著畫面會回到原本的頁面,這時點選 Exchange authorization code for tokens 就可取得 Refresh Token
Imgur

模版建立

開啟專案資料夾輸入

1
express --view=ejs

views 建立 contact.ejs 以及 contactReview.ejs,可以參考下範例:

  • contact.ejs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <!DOCTYPE html>
    <html>
    <head>
    <title>傳送表單內容</title>
    </head>
    <body>
    <form action="/contact/post" method="post">
    <h1>聯絡我們</h1>
    <div>
    <label for="username">姓  名:</label>
    <input type="text" name="username" id="username"/>
    </div>
    <div>
    <label for="email">電子郵件:</label>
    <input type="text" name="email" id="email"/>
    </div>
    <div>
    <label for="title">標  題:</label>
    <input type="text" name="title" id="title"/>
    </div>
    <div>
    <label for="description">訊息內容:</label>
    <textarea name="description" id="description" cols="30" rows="10"></textarea>
    </div>
    <div>
    <input type="submit" value="送出訊息" />
    </div>
    </form>
    </body>
    </html>
  • contactReview.ejs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title>傳送成功</title>
    </head>
    <body>
    <h1>傳送成功</h1>
    <a href="/contact">回到 聯絡我們</a>
    </body>
    </html>

Express 修正

App.js 中加入以下程式碼:

1
2
const contactRouter = require('./routes/contact');
app.use('/contact', contactRouter);

nodemailer 設定

來到 routes 建立 contact.js 並加入範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const express = require('express');
const router = express.Router();
const nodemailer = require('nodemailer');

router.get('/', function(req, res) {
res.render('contact');
});
router.get('/review', function(req, res) {
res.render('contactReview');
});
router.post('/post', function(req, res) {
const data = req.body;
// 前端傳進資料,用傳統表單形式,也能用 AJAX 呦!
console.log(data);
const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
type: 'OAuth2',
user: '要使用的 Gmail',
clientId: '填入用戶端ID',
clientSecret: '填入用戶端金鑰',
refreshToken: '填入 Refresh Token',
},
});
const mailOptions = {
from: '"來自XXX"<xxx@gmail.com>',
to: '收件人信箱',
subject: `${req.body.username}寄了一封測試信`,
text: req.body.description,
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
return console.log(err);
}
res.redirect('/contact/review');
});
});
module.exports = router;

測試

接著開啟服務,在 http://localhost:3000/contact 輸入一些內容並送出,並查看收件人信箱,如果有收到信件代表已經成功囉!!