Python 标准库提供了用于 SMTP 连接的 smtplib 和用于构建邮件的 email.message.EmailMessage,因此基本的 SMTP 发送无需任何第三方包。对于生产环境投递,HTTP 邮件 API 会处理 IP 预热、重试和退信事件,你无需自行运行邮件服务器。
如何使用标准库发送邮件?
EmailMessage 构建邮件并为你设置邮件头。smtplib.SMTP_SSL 在端口 465 上打开加密连接:
import smtplib
from email.message import EmailMessage
msg = EmailMessage()
msg["From"] = "you@yourdomain.com"
msg["To"] = "recipient@example.org"
msg["Subject"] = "Your receipt"
msg.set_content("Thanks for your order. This is the plain-text version.")
msg.add_alternative("<p>Thanks for your order.</p>", subtype="html")
with smtplib.SMTP_SSL("smtp.example.com", 465) as server:
server.login("smtp-user", "smtp-password")
server.send_message(msg)
set_content 写入纯文本正文,add_alternative 附加 HTML 版本,客户端会选择它能渲染的部分。同时发送两种格式是良好实践,也有助于提升送达能力。
SSL 还是 STARTTLS?
有两种加密路径,它们使用不同的端口。SMTP_SSL 在 465 端口从第一个字节开始协商 TLS。另一种方式是在 587 端口使用明文 SMTP,然后通过 starttls() 将明文连接升级为加密连接:
with smtplib.SMTP("smtp.example.com", 587) as server:
server.starttls()
server.login("smtp-user", "smtp-password")
server.send_message(msg)
根据你的邮件服务器支持的方式选择其一。不要通过未加密的连接发送凭据。将用户名和密码保存在环境变量中并使用 os.environ 读取,不要写在源代码里。
如何添加附件?
add_attachment 接收字节数据和 MIME 类型。以二进制模式读取文件:
with open("invoice.pdf", "rb") as f:
msg.add_attachment(
f.read(),
maintype="application",
subtype="pdf",
filename="invoice-1042.pdf",
)
为什么生产环境不应使用原始 SMTP?
生产环境发送会带来标准库无法处理的需求。你需要一个 IP 信誉良好的邮件服务器、SPF、DKIM 和 DMARC 记录、针对瞬时故障的重试逻辑,以及追踪退信和投诉的途径。HTTP API 负责处理这一层:你使用 API 密钥进行身份验证,发送 JSON,并读取结构化响应,而无需解析 SMTP 状态码。
使用 Bird 发送
安装 Bird Python SDK(pip install messagebird-sdk),即可通过 HTTPS 发送邮件,无需自行管理 SMTP 连接:
from bird import APIError, Bird
client = Bird()
try:
message = client.email.send(
from_="onboarding@messagebird.dev",
to=["delivered@messagebird.dev"],
subject="Hello from Python",
text="It works.",
html="<p>It works.</p>",
)
print(message.id, message.status)
except APIError as err:
print("send failed:", err)
Bird() 会自动从环境变量中读取 BIRD_API_KEY。从 onboarding@messagebird.dev 发送到 delivered@messagebird.dev 沙箱地址,可以在配置自定义域名之前验证你的密钥和载荷。如果请求未通过校验,APIError 会返回 HTTP 状态码和错误码。