Node.js 使用 Nodemailer 模块发送邮件
在网站开发中,发送邮件是一个经常会遇到的需求。比如注册账号的时候,可以通过邮件来验证邮箱地址,服务变更或账号异常的时候,也可以通过邮件来通知。我的博客在回复评论的时候,也会有邮件通知。
我用来发送邮件的模块是 Nodemailer,这是一个第三方的邮件模块,也是目前使用最多的 Node.js 邮件模块。
使用 npm 安装 nodemailer:
npm install nodemailer --save我使用的邮箱是 QQ 邮箱,使用的是 SMTP 协议。
SMTP(Simple Mail Transfer Protocol)也叫简单邮件传输协议,这是互联网上常用的一种邮件传输协议。SMTP 主要是发送邮件,不包括邮件接收。
常见邮箱的 SMTP 地址和端口
下面是一些常见邮箱的 SMTP 地址和端口:
| 服务商 | SMTP 地址 | SMTP 端口 | 
|---|---|---|
| QQ邮箱 | smtp.qq.com | 25 | 
| 网易126邮箱 | smtp.126.com | 25 | 
| 网易163邮箱 | smtp.163.com | 25 | 
| 新浪邮箱 | smtp.sina.cn | 25 | 
| Gmail | smtp.gmail.com | 465 | 
| 雅虎邮箱 | smtp.mail.yahoo.com | 465 | 
Foxmail 和 QQ邮箱的 SMTP 地址都是 smtp.qq.com。
一般邮箱的 SMTP 服务默认都是关闭状态,你可能需要到邮箱设置中开启 SMTP。
发送文本
下面使用 Nodemailer 发送普通文本:
const nodemailer = require('nodemailer');
// 创建  SMTP 连接
const transporter = nodemailer.createTransport({
  // SMTP 服务器地址
  host: 'smtp.qq.com',
  // 端口
  port: 25,
  // 使用 TLS
  secure: false,
  auth: {
    // 你的邮箱账号或地址
    user: '[email protected]',
    // 密码
    pass: 'sjifjhierhjiji'
  }
});
// 发送邮件
transporter.sendMail({
  // 发信地址
  from: '[email protected]',
  // 收信地址
  to: '[email protected]',
  // 邮件标题
  subject: 'Hello',
  // 邮件内容(普通文本)
  text: `这是来自 Mr. Ma's Blog www.misterma.com 的邮件`,
}).then(result => {
  console.log(`发送成功,id:${result.messageId}`);
}).catch(error => {
  console.log(error);
});注意!在调用 createTransport 的时候,有一个选项 secure,这是使用 TLS 连接到 SMTP 服务器。如果 SMTP 服务器的端口是 465,secure 需要设置为 true,端口 25 和 587 secure 需要设置为 false。
sendMail 的 to 收信地址可以设置多个,多个地址之间用英文逗号 , 分隔。
sendMail 的发送结果会通过 Promise 的方式返回,成功的 Promise 内容如下:
{
  "accepted": [
    "[email protected]"
  ],
  "rejected": [],
  "ehlo": [
    "PIPELINING",
    "SIZE 73400320",
    "AUTH LOGIN PLAIN XOAUTH XOAUTH2",
    "AUTH=LOGIN",
    "MAILCOMPRESS",
    "8BITMIME"
  ],
  "envelopeTime": 233,
  "messageTime": 348,
  "messageSize": 379,
  "response": "250 OK: queued as.",
  "envelope": {
    "from": "[email protected]",
    "to": [
      "[email protected]"
    ]
  },
  "messageId": "<[email protected]>"
}发送 HTML
这里使用的 transporter 选项和上面是一样的,下面直接使用 sendMail 发送邮件:
// 要发送的 HTML
const htmlText = `
<h2>Mr. Ma's Blog评论回复邮件通知</h2>
<p>呵呵呵呵😀😁😂🤣</p>
`;
// 发送邮件
transporter.sendMail({
  // 发信地址
  from: '[email protected]',
  // 收信地址
  to: '[email protected]',
  // 邮件标题
  subject: 'Hello',
  // 邮件内容(HTML)
  html: htmlText
}).then(result => {
  console.log(`发送成功,id:${result.messageId}`);
}).catch(error => {
  console.log(error);
});如果你要发送比较复杂的 HTML 内容,你可能需要使用 Web 模板引擎生成,关于模板引擎的使用可以看 Node.js Web 模板引擎 Eta 的简单使用 。
在发送 HTML 时,CSS 样式需要写在元素的 style 属性里,不能直接使用 link 调用 CSS 文件,也不能使用 style 标签来写 CSS。
发送附件
下面把项目目录下的 package.json 作为附件发送:
const path = require('path');
// 发送邮件
transporter.sendMail({
  // 发信地址
  from: '[email protected]',
  // 收信地址
  to: '[email protected]',
  // 邮件标题
  subject: 'Hello',
  // 邮件内容
  text: '给你发了一个 JSON 文件',
  // 附件
  attachments: [
    {
      filename: 'package.json',
      path: path.join(__dirname, 'package.json')
    }
  ]
}).then(result => {
  console.log(`发送成功,id:${result.messageId}`);
});附件 attachments 需要接收一个对象数组,下面是属性说明:
- filename:用于显示的文件名,可以和真实的文件名不一样
- path:真实的文件路径
- content:文件内容,可以直接使用字符串,也可以使用- fs.readFile之类的读取文件发送
- href:文件的 URL
- httpHeaders:与- href一起使用的 HTTP 请求头
- contentType:附件类型,省略会根据- filename自动生成
- cid:附件的 Content-ID(CID),用于内联显示图片等嵌入式资源
- encoding:附件内容的编码方式。默认为 base64
- headers:附件的自定义标题。可以设置任何有效的 MIME 头字段和值的键值对
在发送附件的时候,path、content、href 一般只会选择一个。如果要发送大文件可以使用 path,path 是流式传输的,发送动态生成的内容可以使用 content,发送公开的网络文件可以使用 href。
在 HTML 中插入附件图片
附件有一个 cid 属性,通过 cid 可以直接在 HTML 中显示附件图片:
const path = require('path');
// 发送邮件
transporter.sendMail({
  // 发信地址
  from: '[email protected]',
  // 收信地址
  to: '[email protected]',
  // 邮件标题
  subject: 'Hello',
  // 邮件内容(HTML)
  html: `看看这张图片 <img src="cid:www.misterma.com" alt="图片" />`,
  // 附件
  attachments: [
    {
      filename: 'test.gif',
      path: path.join(__dirname, 'test.gif'),
      cid: 'www.misterma.com'
    }
  ]
}).then(result => {
  console.log(`发送成功,id:${result.messageId}`);
});附件的 cid 可以设置一个字符串,在 HTML 的 img src 可以直接使用附件 cid,src 需要以 cid: 开头。
版权声明:本文为原创文章,版权归 Changbin's Blog 所有,转载请联系博主获得授权。
本文地址:https://www.misterma.com/archives/937/
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。