Try   HackMD

[Node.js] 用 Nodemailer 寄信 - 筆記

tags: Node.js Express.js npm

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
本站筆記已同步更新到我的個人網站囉! 歡迎參觀與閱讀,體驗不同的視覺感受!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Nodemailer安裝與設定

首先參閱Nodemailer的文件

安裝

npm install --save nodemailer
安裝完成後到package.json確認,沒問題就來進行接下來的設定,看一下文件的說明:

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

其實就是3個重點:

  1. 先做一個transporter,可以使用SMTP其他傳輸機制
  2. 設定寄信的內容,包含寄件人、收件人、信件內容、主旨、附件等
  3. 使用Nodemailer的sendMail()方法,透過先前產生的transporter將信件寄出

引入nodemailer

const nodemailer = require('nodemailer')

製作transporter

官方文件範例:
let transporter = nodemailer.createTransport(options[, defaults])
因為預設使用SMTP,所以如果使用SMTP機制的話,以下兩種寫法皆可:
let transporter = nodemailer.createTransport("SMTP", {smtpOptions});
let transporter = nodemailer.createTransport({smtpOptions});
完整範例如下,帳號密碼可以用環境變數的方式引入:

let transporter = nodemailer.createTransport({ host: "smtp.ethereal.email", // 寄信的host, port: 587, secure: false, // true for 465, false for other ports auth: { user: testAccount.user, // 代為寄信的帳號 pass: testAccount.pass, // 該帳戶的密碼 }, });

如果使用Gmail做為transporter

nodemailer已經知道知名的信件服務提供者的SMTP連線資訊,所以若使用這些信件服務做為transporter,不需提供host、port等資訊,以下以gmail為例:

let transporter = nodemailer.createTransport({ service: 'gmail', // no need to set host or port etc. auth: {...} })

但是由於gmail對安全性的限制,這裡無法直接使用gmail帳號密碼做為驗證,必須設定App password

  1. 首先進入Google account頁面,點選左側Security
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →
  2. 找到 How you sign in to Google的區塊,確認 2-Step Verification已經開啟
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →
  3. 進入 2-Step Verification頁面,拉到最下面,找到App passwords
    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →
  4. 點進App passwords,選擇app:Mail、device:(你的裝置),按Generate。
  5. 這時會產生一組password,這組密碼可以做為transporter中auth的密碼,記得複製下來貼到.env裡面,視窗關了就看不到了,必須重新產生一組。

如果不想使用密碼

如果不想使用App password,又想利用gmail做為transporter,可以使用Gmail API + OAuth2的方式驗證,詳細作法參考:

設定mail options

接著設定寄件內容,直接看範例:

let mailOptions = { from: "sender@server.com", //寄件人email to: "receiver@sender.com", //收件人email subject: "Message title", //主旨 text: "Plaintext version of the message", //信件內容,純文字 html: "<p>HTML version of the message</p>" //信件內容,html };

除了以上基本內容,還有更多進階內容可以設定,例如:

let mailOptions = { ..., cc: 'user1@example.com', //cc的對象 bcc: 'user2@example.com', //bcc的對象 attachments: [{ filename: 'image1.jpg', path: 'filepath/image1.jpg' }], //附件 headers: { 'My-Custom-Header': 'header value' }, // headers內容 date: new Date('2000-01-01 00:00:00') //日期 };

更多進階設定,參考文件Message Configuration

寄出信件

transporter和mail options都設定完之後,就可以用nodemailer提供的sendMail()方法寄出信件:
transporter.sendMail(mailOptions)
也可以加上callback回傳error和result,更多選項詳見文件

transport.sendMail(mailOptions, (error, info) => {
  if (error) {
       return console.log(error);
    }
   console.log("Message sent: %s", info.messageId); 
   // Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
})

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
實際操作 - 聯絡表單 Contact form

想法

製作一個聯絡表單,類似客服信箱的概念,使用者留言後按送出,表單內容會寄到客服信箱。

表單HTML

  <form class="form" method="POST" action="/contact" onsubmit="return validation();">
     <div class="row">
	<div class="form-group col-md-6 my-3">
	    <input type="text" name="name" class="form-control" placeholder="Name" required>
	</div>
	<div class="form-group col-md-6 my-3">
	    <input type="email" name="email" class="form-control" placeholder="Email" required>
	</div>
	<div class="form-group col-md-12 my-3">
	    <input type="text" name="subject" class="form-control" placeholder="Subject" required>
	</div>
	<div class="form-group col-md-12 my-3">
            <textarea rows="6" name="message" class="form-control" placeholder="Your Message" required></textarea>
	</div>
	<div class="col-md-12 text-center my-3">
	    <button type="submit" value="Send message" name="submit" class="btn btn-contact fs-5" title="Submit Your Message!">Send Your Message!</button>
	</div>
      </div>
  </form>

把寄信功能封裝成一個helper

# ./helpers/email-helpers.js const nodemailer = require('nodemailer') const contactFormSend = async (name, email, subject, message) => { const transporter = nodemailer.createTransport({ service: 'gmail', auth: { user: process.env.EMAIL, pass: process.env.APP_PASSWORD } }) const mailOptions = { from: process.env.EMAIL, to: process.env.EMAIL, subject, html: `<h3>Name: ${name}</h3><br/><h3>Email: ${email}</h3><br/><h3>Message:</h3><br/><p>${message}</p>` } const sendMail = await transporter.sendMail(mailOptions) return sendMail } module.exports = contactFormSend
# .env EMAIL=XXXX@gmail.com APP_PASSWORD=your_password

Route - POST /contact

  • 首先利用Express架一個伺服器,專案入口設定為app.js(詳細步驟點我),接著到app.js引入email-helpers
    const contactFormSend = require('./helpers/email-helpers')
  • 傳送表單資料的路由
# app.js if (process.env.NODE_ENV !== 'production') { require('dotenv').config() } const express = require('express') const app = express() const port = 3000 const contactFormSend = require('./helpers/email-helpers') app.use(express.urlencoded({ extended: true })) app.use(express.json()) // Send email from contact form app.post('/contact', (req, res) => { try { //從req.body取得表單資料 const { name, email, subject, message } = req.body // 傳入表單資料,利用email-helper寄信 contactFormSend(name, email, subject, message) return res.redirect('/contact') } catch (error) { console.log(error) res.redirect('/contact') } }) app.listen(port, () => { console.log(`App is listening at http://localhost:${port}`) })

寄信功能試用

都設定完畢後,來試用看看:

  1. 填寫表單並送出

  1. 到信箱收信

成功寄信啦!!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


參考資料

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
 本站內容僅為個人學習記錄,如有錯誤歡迎留言告知、交流討論!