用 Node.js 和 Python 发送邮件:从 SMTP 到 API

在 Node.js 和 Python 里发送邮件的几种方式:nodemailer / smtplib 直连 SMTP,以及调用邮件 API。附完整代码、错误处理和重试建议。

在代码里发邮件,大致有两条路:自己连 SMTP 服务器,或者调用邮件服务商的 HTTP API。这篇两种都写一遍,最后说说什么时候该选哪种。

方式一:直连 SMTP

Node.js(nodemailer)

import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.example.com",
  port: 587,
  auth: { user: "you@example.com", pass: process.env.SMTP_PASSWORD },
});

await transporter.sendMail({
  from: '"Acme" <you@example.com>',
  to: "user@example.com",
  subject: "你的验证码",
  text: "验证码是 382915,10 分钟内有效。",
});

Python(smtplib)

import os, smtplib
from email.message import EmailMessage

msg = EmailMessage()
msg["From"] = "Acme <you@example.com>"
msg["To"] = "user@example.com"
msg["Subject"] = "你的验证码"
msg.set_content("验证码是 382915,10 分钟内有效。")

with smtplib.SMTP("smtp.example.com", 587) as s:
    s.starttls()
    s.login("you@example.com", os.environ["SMTP_PASSWORD"])
    s.send_message(msg)

SMTP 的好处是通用,几乎所有邮箱都支持。缺点是连接慢、出错信息不直观;而且很多云服务器默认封了 25 端口,部署到线上经常发不出去。

方式二:调用邮件 API

API 走的是普通 HTTPS 请求,不受端口限制,返回的是结构化的结果,也更容易拿到投递状态。

Node.js

const res = await fetch("https://bulkmail.dev/emails", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BULKMAIL_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    from: "Acme <hello@acme.com>",
    to: "user@example.com",
    subject: "你的验证码",
    text: "验证码是 382915,10 分钟内有效。",
  }),
});
if (!res.ok) throw new Error((await res.json()).error);
const { id } = await res.json();

Python

import os, requests

r = requests.post(
    "https://bulkmail.dev/emails",
    headers={"Authorization": f"Bearer {os.environ['BULKMAIL_API_KEY']}"},
    json={
        "from": "Acme <hello@acme.com>",
        "to": "user@example.com",
        "subject": "你的验证码",
        "text": "验证码是 382915,10 分钟内有效。",
    },
    timeout=10,
)
r.raise_for_status()
print(r.json()["id"])

错误处理和重试

  • 4xx(参数错误、域名没验证):重试没用,记日志、修代码。
  • 429(超出额度):别立刻重试,等额度恢复或者升级套餐。
  • 5xx 或网络超时:可以重试,用指数退避,比如 1 秒、2 秒、4 秒。

验证码这类邮件,建议把“发信”放到后台任务里,不要卡住用户的请求。拿到邮件 ID 后,用 Webhook 接收送达结果,比轮询省事得多。

该选哪种

个人脚本、发给自己的提醒,用 SMTP 连自己的邮箱就够了。正式产品里给用户发信,建议用 API:不受端口限制、有投递记录、退信会自动处理,出了问题也好查。

用 BulkMail 发你的第一封信

注册不用绑卡,每天 100 封免费额度。加个域名、调一个接口就能发。