浏览器会阻止与邮件服务器建立原始 TCP 连接。如果把 API 密钥或 SMTP 密码放在前端代码中,任何打开开发者工具的人都能看到你的凭据。
为什么浏览器不能发送邮件?
浏览器不向 JavaScript 暴露原始 TCP 套接字,因此客户端代码无法建立邮件服务器所需的 SMTP 连接。如果直接从浏览器调用 HTTP 邮件 API,你的 API 密钥也会暴露在页面源代码和网络面板中。浏览器收集表单输入并提交到后端,由后端发送邮件。
如何在 Node 后端使用 SMTP 发送邮件?
Nodemailer 是 Node 中用于 SMTP 的标准库。你只需配置一次传输,然后调用 sendMail:
import nodemailer from "nodemailer";
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
secure: false,
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
await transporter.sendMail({
from: "you@yourdomain.com",
to: "recipient@example.org",
subject: "Your receipt",
text: "Thanks for your order.",
html: "<p>Thanks for your order.</p>",
});
这在长期运行的服务器上效果很好。Nodemailer 还支持文件附件和本地 SMTP 测试。
如何通过 HTTP 邮件 API 发送?
你的后端也可以使用 fetch 向 HTTP 邮件 API 提交 JSON 来发送邮件。这种方式使用标准 HTTPS,而不是原始 TCP 套接字,因此在长期运行的服务器和 serverless 运行时上都能使用:
const res = await fetch("https://us1.platform.bird.com/v1/email/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BIRD_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "onboarding@messagebird.dev",
to: ["delivered@messagebird.dev"],
subject: "Hello from JavaScript",
html: "<p>It works.</p>",
}),
});
if (!res.ok) {
throw new Error(`Send failed: ${res.status}`);
}
根据工作区所在区域选择主机(bk_us1_ 密钥使用 us1.platform.bird.com,bk_eu1_ 密钥使用 eu1.platform.bird.com)。将 API 密钥保存在服务器端环境变量中,这样它永远不会被发送到客户端。
使用 Bird 发送
如需从 Node.js 或 TypeScript 发送邮件,并获得类型化响应和自动重试,请将 BIRD_API_KEY 传给 Bird TypeScript SDK:
import { BirdClient } from "@messagebird/sdk";
const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
const { data, error } = await bird.email
.send({
from: "onboarding@messagebird.dev",
to: ["delivered@messagebird.dev"],
subject: "Hello from Node",
html: "<p>It works.</p>",
})
.safe();
在配置自定义域名之前,你可以用 onboarding@messagebird.dev 发件人和 delivered@messagebird.dev 沙箱收件人验证配置。如果你用 React 组件构建邮件正文,React Email 会将组件渲染为传入 html 的 HTML 字符串。