全端勇士之路 Node.js 基礎學習-實作發送電子郵件並且部屬 HeroKu(2)

前言

前面基本 UI 及 Rotue 已經建立完畢,所以現在就要來準備將剛剛安裝的套件給加入至 app.js 中

回憶階段

首先先回頭想一下我們安裝了那些插件,這樣子才知道要設定那些

  • express-session - session 套件
  • nodemailer - 發送電子郵件套件
  • connect-flash - 快取套件
  • csurf - CSRF 防禦
  • express-validator - 欄位驗證,前面沒有講到,所以順便這章節實作來講
  • body-parser - 解析表單欄位
  • dotenv - 環境變數

dotenv

先在可能會需要使用環境變數的 users.js 引入環境變數語法

1
require('dotenv').config();

並且在根目錄建立 .env 檔案內容如下

1
2
ACCOUNT= 
PASSWORD=

express-session

首先先將 express-session 的相關設定寫入至 app.js 中

1
2
3
4
5
6
var session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
}))

connect-flash

我先跳過了 nodemailer 的設置,因為這裡面有一些東西要先做調整

也是一樣將 connect-flash 寫入至 app.js 中

1
2
var flash = require('connect-flash');
app.use(flash());

csurf

絕對少不了 csurf 的套件,也是相同都是在 app.js 引入

1
2
var csurf = require('csurf')
var csrfProtection = csrf({ cookie: true })

那由於是 middleware 的關係,所以我先調整一下 router 加入 middlew加入

1
2
app.use('/',csrfProtection ,indexRouter);
app.use('/users',csrfProtection ,usersRouter);

也要記得隱藏欄位並帶上 name="_csrf" value="{{csrfToken}}",要注意不能用 {{csrfToken}} 在 EJS 下要這樣使用 <%= csrfToken %>

另外還要修改 get route,否則會出現 no defined

1
2
3
4
5
6
router.get('/mailsend',function(req, res, next) {
res.render('users', {
title: '信件發送頁面',
csrfToken: req.csrfToken()
});
});

body-parser

這是一個超級重要的套件,要是沒有這個套件就不能解析表單元素,一樣 app.js 引入

1
2
3
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

nodemailer

接下到了設置發送電子郵件的套件,但是這一個套件只會在特定的 route 使用,所以只會在 users.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
var nodemailer = require("nodemailer");

router.post('/mailsend',function(req, res, next) {
var transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: process.env.ACCOUNT,
pass: process.env.PASSWORD,
}
});
var mailOption = {
form: '"測試電子郵件"<[email protected]>',
to: req.body.email,
subject: req.body.username + '你好!測試一封測試信',
text: req.body.content
}
transporter.sendMail(mailOption ,function(error, info) {
if (error) {
console.log('錯誤訊息:' + error);
res.redirect('/users/mailsend');
}
console.log('發送成功');
res.redirect('/users/mailsend');
})
res.send('Hello!');
});

express-validator

express-validator 只會有幾個地方使用,所以直接在 route 中引入即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var validat = [
check('email').isEmail().withMessage('Email 錯誤'),
check('username').isLength({ min: 2 }).withMessage('姓名不可低於 3 個字元'),
check('content').isLength({ min: 10 }).withMessage('字數不可少於 10 字元')
]
router.post('/mailsend' ,validat ,function(req, res, next) {
var errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).render('users', {
title: '信件發送頁面',
csrfToken: req.csrfToken(),
errorMessages: errors.array(),
})
}
...(以下略)

可透過 withMessage 自訂提示訊息

這邊其實可以優化一下改用 flash 來做提示訊息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
router.get('/mailsend',function(req, res, next) {
res.render('users', {
title: '信件發送頁面',
csrfToken: req.csrfToken(),
errorMessages: req.flash('errorMessages')
});
});

var validat = [
check('email').isEmail().withMessage('Email 錯誤'),
check('username').isLength({ min: 2 }).withMessage('姓名不可低於 3 個字元'),
check('content').isLength({ min: 10 }).withMessage('字數不可少於 10 字元')
]
router.post('/mailsend' ,validat ,function(req, res, next) {
var errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('errorMessages',errors.array())
res.redirect('/users/mailsend')
}
...以下略過

補充雷點

基本上發送郵件這邊有可能發生一個錯誤,就是被 Google 阻擋。

所以當出現錯誤的時候可以將紅框處複製下來組成一個網址,然後再登入發送郵件的帳號,在 URL 貼上你組好的字串即可,如果出現被出現重大訊息之類,就點進去信件內標註是我本人登入即可。

這是一個組字串前奏

若沒問題的話基本上是可以發信哩~

發信成功