大多数Web应用程序都需要发送电子邮件。它可能用于注册、密码重置、状态报告,甚至是完整的市场营销活动,如新闻和促销。本教程解释了如何在Node.js中发送电子邮件,但其概念和挑战适用于您正在使用的任何系统。
你会在 npm 上找到大量与电子邮件相关的模块,其中最流行的是 NodeMailer,每周的下载量超过 300 万次。
要使用它,您需要一个可以发送电子邮件的 SMTP 服务器。您可以使用自己的电子邮件提供程序,但是出于演示的目的,我使用免费的 WPOven Test SMTP 服务器。
创建一个新的项目文件夹:
mkdir emailtest
cd emailtest
然后创建一个新的 package.json
文件,内容如下:
{
"name": "emailtest",
"type": "module",
"main": "index.js",
"dependencies": {
"nodemailer": "^6.0.0"
}
}
安装模块(NodeMailer):
npm install
并创建以下 index.js
代码:
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: 'smtp.freesmtpservers.com',
port: 25
});
try {
const send = await transporter.sendMail({
from: '"Test Email" <test@email.com>', // sender address
to: 'someone@example.com', // list of receivers
subject: 'Hello!', // subject line
text: 'Hello world!', // plain text body
html: '<p>Hello world!</p>', // HTML body
});
console.dir(send, { depth: null, color: true });
}
catch(e) {
console.dir(e, { depth: null, color: true });
}
运行代码。您应该看到包含 250 OK
响应和 messageId
的结果:
$ node index.js
{
accepted: [ 'someone@example.com' ],
rejected: [],
ehlo: [ 'SIZE 33554432', '8BITMIME', 'SMTPUTF8', 'HELP' ],
envelopeTime: 486,
messageTime: 289,
messageSize: 595,
response: '250 OK',
envelope: {
from: 'test@email.com',
to: [ 'someone@example.com' ]
},
messageId: '<4673597e-a9e4-e422-85f7-4422edf31774@email.com>'
}
检查 to:
地址的收件箱,在 WPOven Test SMTP Server 页面输入该地址并单击 Access Inbox。单击“Hello!” 消息检查内容。
NodeMailer 基础知识
要发送电子邮件,你必须创建一个NodeMailer传输器(transporter)对象来定义服务类型。SMTP是最常见的,但其他服务也可以使用。通常需要一个身份验证用户ID和密码:
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: 'smtp.yourserver.com',
port: 587,
auth: {
user: 'myid@yourserver.com',
pass: 'my-password'
},
});
你可以使用传输器的 sendMail()
方法发送电子邮件给一个或多个收件人:
const send = await transporter.sendMail({
from: '"Test Email" <test@email.com>', // sender address
to: 'someone@example.com, sometwo@example.com', // list of receivers
cc: 'somethree@example.com',
bcc: 'somefour@example.com',
subject: 'Hello!', // subject line
text: 'Plain text version of the message', // plain text body
html: '<p>HTML version of the message</p>', // HTML body
});
所有的邮件客户端都支持纯文本消息,当邮件客户端支持HTML时,你也可以发送相同消息的富格式版本(更多内容见下文)。
NodeMailer 提供了许多其他的消息选项,但最常见的是附件。
const send = await transporter.sendMail({
// ...
attachments: [
{ // get file content from disk
filename: 'text1.txt',
path: '/path/to/file1.txt'
},
{ // get file content from a URL
filename: 'text2.txt',
path: 'https://myserver.com/text2.txt'
},
{ // create file from UTF-8 string
filename: 'text3.txt',
content: 'This is the file content!'
},
{ // create file from data URI
filename: 'text4.txt',
path: 'data:text/plain;base64,SGVsbG8gd29ybGQh'
}
]
});
发送服务
发送简单的一次性电子邮件很容易,但请不要低估随着需求变化的挑战。
- 你可能没有SMTP服务器。不是所有的电子邮件服务提供SMTP(谷歌正在收回Gmail的基本SMTP支持)。
- 大多数服务都会限制外发电子邮件。如果您发送大量电子邮件,则可能会达到提供商的限制。那时,通过同一服务的所有电子邮件都将失败。
- 你可能成为垃圾邮件发送者。收件人很容易把你的邮件标记为“垃圾邮件”——即使它不是垃圾邮件。当足够多的人这样做时,你会发现来自你域名的所有电子邮件都被拦截了。
最好使用专用的电子邮件服务,而不是自己的邮件服务器。以下服务可以减少潜在的问题,有些服务还为那些使用要求较低的用户提供免费计划:
- https://aws.amazon.com/ses/
- https://www.brevo.com/
- clicksend.com
- https://mailchimp.com/
- https://www.mailersend.com/
- https://www.mailgun.com/
- https://www.mailjet.com/
- https://mailtrap.io/
- https://postmarkapp.com/
- https://www.sender.net/
- https://sendgrid.com/
异步应用程序架构
发送单个电子邮件通常很快,但是:
- SMTP服务器可能已经关闭,所以重试是必要的,或者
- 消息可能会在大量新闻邮件中被截获。
通常,最好将数据发送到任务队列,而不是直接在 Node.js 应用程序中发送电子邮件。最终用户无需等待响应,可以继续使用该应用程序。
另一个进程可以监视电子邮件队列,发送下一条消息,并在发生故障时重新排队。
制作HTML邮件
HTML5和CSS3在现代浏览器中一直运行良好。电子邮件客户端则是另一回事,它把我们带回了令人沮丧的20世纪90年代末的表格和内联样式。
这些是你将面临的一些问题:
- 有几十种本地和基于Web的电子邮件客户端,包括Gmail、雅虎邮件、苹果邮件、iOS邮件、Android邮件、Windows邮件、Outlook、Outlook.com、(新)Outlook、雷鸟、AOL、Claws、RoundCube等。
- 所有这些浏览器都使用各自奇怪又奇妙的渲染引擎,这些引擎都有各自的问题和漏洞。 有些奇怪的是,Outlook从2007年起就使用微软Word来渲染HTML(尽管新的预览版是基于浏览器的)。
- 大多数客户端会阻止或限制字体、图像、追踪器、媒体查询、iframe、视频、音频、表单和脚本。
- 即使是基于浏览器的电子邮件客户端也必须删除HTML、CSS和JavaScript,这些代码是危险的,或者会影响UI布局。 例如,电子邮件不应该自动点击自己的链接,或者绝对将一个元素定位在删除按钮上。
- 电子邮件客户端可以重新格式化你的HTML,以确保它是单一的列或遵循用户的明/暗模式偏好。
手工编写HTML邮件是可能的,但除非你的布局很简单,否则这会是一个困难、令人沮丧且容易出错的过程。下面几节建议一些工具和资源,可能会让你的生活变得更容易。
预先构建的电子邮件模板
以下站点提供免费且强大的商业电子邮件模板,您可以轻松预览、下载和使用:
- codedmails.com
- 活动监控模板
- Litmus邮件模板
- Stripo模板
邮件模板设计工具
以下无代码设计工具允许您使用更简单的 WYSWYG 编辑器创建自己的 HTML 电子邮件模板:
- Beefree
- Blocks Edit
- Campaign Monitor
- chamaileon
- fly-brid
- GrapesJS
- knak
- Mail Developer
- Maily
- Postcards
- Psd2Newsletters
- Stensul
- Stripo
- Topol
- Unlayer
其中一些服务还提供代码验证和测试工具。
电子邮件模板转换
Premailer 是一个web工具,它可以将页面URL或粘贴的源代码转换为兼容电子邮件的HTML和纯文本模板。
类似的工具包括:
- alter.email
- email-comb
- Postdrop
邮件模板标记工具
Cerberus、Email Framework、Email Skeleton,和 Good Email Code 提供HTML组件片段,你可以复制并调整到你自己的模板中。
HEML 和 MJML 是电子邮件标记语言。它们类似于HTML,但避免了典型的兼容性问题。Maizzle 使用了类似的方法,使用了Tailwind CSS。
Parcel 是一个代码编辑器,它可以理解邮件格式并显示预览。你也可以找到大量的VS Code的邮件扩展。
caniemail.com 是相当于网页版 caniuse.com 的电子邮件,报告特定 HTML 或 CSS 功能是否可在多个客户端上使用。最后,Accessible Email 提供了相关的资源和链接。
邮件测试工具
虽然HTML邮件可能在你自己的邮件应用程序中工作,但你能确定它在其他应用程序中工作吗?下面的工具将有所帮助,但没有什么可以替代测试一系列真实的设备、操作系统和电子邮件客户端。
HTML Email Check 和 MailTrap 验证您的源代码,并报告您在特定客户机中可能遇到的问题。
emailpreview, Mailosaur 和 Email Preview Services 提供布局预览工具,这样你就可以检查你的设计在各种客户机上的效果。
最后,Litmus和 Email on Acid 有一系列工具来验证代码、检查可访问性、跨客户端预览、记录分析和运行完整的营销活动。
读取收到的电子邮件
大多数应用只需要发送邮件,但有时你可能需要检查接收到的邮件 - 比如服务注册、退订处理、自动化支持等等。虽然这超出了本教程的范围,但 Node.js 模块,如 ImapFlow,允许应用连接到 IMAP 收件箱,获取消息并处理响应:
import ImapFlow from 'imapflow';
const client = new ImapFlow({
host: 'imap.email',
port: 993,
secure: true,
auth: {
user: 'account@imap.email',
pass: 'mypassword'
}
});
try {
// connect
await client.connect();
// select and lock inbox
const lock = await client.getMailboxLock('INBOX');
// get latest message
const msg = await client.fetchOne(client.mailbox.exists, { source: true });
console.log( msg.source.toString() );
// release lock
lock.release();
// log out
await client.logout();
}
catch (e) {
console.log(e);
}
使用 Node.js 发送电子邮件的常见问题
我如何使用 Node.js 将文件附加到我的电子邮件中?
使用 Node.js 在邮件中附加文件非常简单,你可以在邮件选项中使用 attachments
属性,这个属性接受一个附件选项数组,每个附件选项是一个对象,包含文件名和路径属性,文件名属性是文件名,它将出现在邮件中,路径属性是文件在系统中的位置。
这里有一个例子:
let mailOptions = {
from: 'sender@example.com',
to: 'receiver@example.com',
subject: 'Hello',
text: 'Hello world',
attachments: [
{
filename: 'file.txt',
path: '/path/to/file.txt'
}
]
};
我可以使用 Node.js 发送 HTML 电子邮件吗?
是的,你可以使用 Node.js 发送 HTML 邮件。在邮件选项中,你使用的是 html
属性,而不是 text
属性。这个属性的值是邮件的 HTML 内容。
这里有一个例子:
let mailOptions = {
from: 'sender@example.com',
to: 'receiver@example.com',
subject: 'Hello',
html: '<h1>Hello world</h1>'
};
我怎么能把电子邮件发送给多个收件人?
要向多个收件人发送电子邮件,您可以在邮件选项的 to
属性中提供一个以逗号分隔的电子邮件地址列表。
let mailOptions = {
from: 'sender@example.com',
to: 'receiver1@example.com, receiver2@example.com',
subject: 'Hello',
text: 'Hello world'
};
我如何处理发送电子邮件时出现的错误?
你可以使用回调函数来处理发送电子邮件时的错误。该函数作为 sendMail
方法的第二个参数传递。回调函数接受两个参数:一个 error
对象和一个info
对象。如果发送电子邮件时发生错误,error
对象将包含有关错误的信息。
transporter.sendMail(mailOptions, function(error, info){
if (error) {
console.log(error);
} else {
console.log('Email sent: ' + info.response);
}
});
我可以用Gmail账户发邮件吗?
是的,你可以使用Gmail账户发送电子邮件。但是,你需要在Gmail账户设置中启用“(Less secure apps)不安全的应用程序”。此外,你需要在传输选项中使用 smtp.gmail.com
作为主机和587作为端口。
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
auth: {
user: 'your-email@gmail.com',
pass: 'your-password'
}
});
我怎么异步发送电子邮件?
你可以使用 Promise异步发送邮件。 sendMail
方法返回一个 Promise,当邮件发送时,它会解析为一个info对象。
transporter.sendMail(mailOptions)
.then(info => console.log('Email sent: ' + info.response))
.catch(error => console.log(error));
我可以使用自定义的SMTP服务器发送电子邮件吗?
是的,您可以使用自定义的 SMTP 服务器发送电子邮件。您需要在传输器选项中提供 SMTP 服务器的主机、端口和身份验证详细信息。
let transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
auth: {
user: 'username',
pass: 'password'
}
});
我如何发送带有特定字符集的电子邮件?
您可以使用邮件选项中的 charset
属性发送具有特定字符集的电子邮件。该属性设置了电子邮件的字符集。
let mailOptions = {
from: 'sender@example.com',
to: 'receiver@example.com',
subject: 'Hello',
text: 'Hello world',
charset: 'UTF-8'
};
我可以发送带有特定内容类型的电子邮件吗?
是的,你可以发送带有特定内容类型的邮件。你可以在邮件选项中使用contentType
属性。这个属性设置了邮件的内容类型。
let mailOptions = {
from: 'sender@example.com',
to: 'receiver@example.com',
subject: 'Hello',
text: 'Hello world'
contentType: 'text/plain'
};
我如何发送带有特定编码的电子邮件?
你可以使用邮件选项中的 encoding
属性来发送带有特定编码的邮件。这个属性设置了邮件的编码。
let mailOptions = {
from: 'sender@example.com',
to: 'receiver@example.com',
subject: 'Hello',
text: 'Hello world',
encoding: 'base64'
};
结论
通过 Node.js Web 应用程序发送电子邮件很简单。但要发送外观漂亮、在所有电子邮件客户端都能可靠运行、不会让用户停机、不会引起垃圾邮件问题的电子邮件,则要困难得多。
我建议你保持邮件的简洁,也许可以选择不常用的纯文本信息。当然,您的客户和营销部门很快就会想要精美的颜色和动画,但您明天就可以交付!