跳转到内容
简体中文

通过 SMTP 发送邮件

连接前的准备

使用邮箱地址和邮箱密码,通过 SMTP 从应用发送邮件。API 密钥和账户令牌不能用于 SMTP。

在已接入的域名下创建有效邮箱,并完成 DNS 记录验证。用户名是完整邮箱地址,例如 [email protected]。请使用该邮箱的密码,而不是邮件账户密码。将示例地址替换为自己的地址;程序运行时输入密码,输入内容不会显示。

服务器、端口和加密

所有已接入的域名均使用 mail.adapt-mail.com。端口 465 在连接时立即启用 TLS;端口 587 先执行 STARTTLS,再进行身份验证。选择一种方式即可。请保持证书验证开启。

示例中的 From 地址和 SMTP 信封发件人均与邮箱用户名一致。发件人显示名称可以修改。端口 25 用于邮件服务器之间的通信;应用请使用 465 或 587。

SMTP_HOST = "mail.adapt-mail.com"
SMTP_PORT = 465
SMTP_USER = "[email protected]"
SMTP_PASSWORD = "<mailbox-password>"
SMTP_FROM = "[email protected]"
SMTP_FROM_NAME = "Example"
465: implicit TLS
587: STARTTLS

Python:通过端口 465 发送

示例仅使用 Python 3 标准库。保存为 send_mail.py,然后运行 python3 send_mail.py。自动发送时,请从应用的安全配置中获取密码,不要将密码保存到 Git 或日志中。

import smtplib
import ssl
from getpass import getpass
from email.message import EmailMessage
from email.utils import formataddr, make_msgid, formatdate
username = "[email protected]"
password = getpass("SMTP password: ")
recipient = "[email protected]"
message = EmailMessage()
message["From"] = formataddr(("Example", username))
message["To"] = recipient
message["Subject"] = "SMTP test"
message["Date"] = formatdate(localtime=False, usegmt=True)
message["Message-ID"] = make_msgid(domain=username.split("@")[1])
message.set_content("Hello! This message was sent through Adapt Mail SMTP.")
with smtplib.SMTP_SSL(
"mail.adapt-mail.com", 465, timeout=30,
context=ssl.create_default_context(),
) as smtp:
smtp.login(username, password)
refused = smtp.send_message(
message, from_addr=username, to_addrs=[recipient],
)
print("Rejected recipients:", refused)

Python:通过端口 587 连接

使用 STARTTLS 时,保留上一个示例中准备邮件的代码,将 with smtplib.SMTP_SSL 代码块替换为以下代码。使用 smtplib.SMTP 时,只有 STARTTLS 成功后才会发送密码。

with smtplib.SMTP("mail.adapt-mail.com", 587, timeout=30) as smtp:
smtp.ehlo()
smtp.starttls(context=ssl.create_default_context())
smtp.ehlo()
smtp.login(username, password)
refused = smtp.send_message(
message, from_addr=username, to_addrs=[recipient],
)
print("Rejected recipients:", refused)

HTML 和附件

在 set_content 之后添加 HTML 版本,在发送之前添加附件。保留纯文本版本,以兼容不支持 HTML 的客户端。仅使用可信 HTML,或对插入的数据进行转义。

message.add_alternative(
"<p>Hello! This message was sent through <strong>Adapt Mail</strong>.</p>",
subtype="html",
)
with open("document.pdf", "rb") as attachment:
message.add_attachment(
attachment.read(), maintype="application", subtype="pdf",
filename="document.pdf",
)

发送结果、限制和已发送邮件

send_message 成功表示 SMTP 服务器接受了邮件,并不代表邮件已进入收件人的收件箱。refused 字典包含被拒绝的收件人;若所有收件人都被拒绝,Python 会抛出 SMTPRecipientsRefused。

SMTP 和 API 共用每个邮箱的发送限制:滚动 60 秒内最多 30 封邮件,每封最多 50 位收件人,滚动 24 小时内最多 1000 位收件人;启用提高限额后为 5000 位。To、Cc 和 Bcc 中的所有收件人均计入。

直接通过 SMTP 发送不会自动在“已发送”文件夹中保存副本。邮件客户端通过 IMAP 保存副本;Adapt Mail API 发送时会单独保存副本。

SMTP 错误

535
身份验证失败:请检查完整邮箱地址、邮箱密码以及邮箱是否可用。
451
临时失败,也可能是超过发送限制。请等待一段时间后重试。
550 / 5xx
永久拒绝:请检查地址、发件人权限和响应内容。超过 50 位收件人的邮件会在 DATA 之后被拒绝。请先解决原因再重试。
TLS / timeout
请检查 mail.adapt-mail.com、端口、TLS 模式及应用服务器的出站网络访问。465 使用 SMTP_SSL,587 使用 SMTP 加 STARTTLS。

请阅读 SMTP 服务器的完整响应。遇到临时失败时,等待一段时间后重试。如果邮件传输后连接断开且结果未知,请勿盲目重发:SMTP 没有 Idempotency-Key,重试可能产生重复邮件。