Python3 SMTP发送邮件实战:从基础构造到QQ邮箱SSL配置
本文详细讲解如何利用 Python3 内置的 smtplib 与 email 模块,通过 SMTP 协议完成各类邮件自动发送。涵盖纯文本、HTML 富文本、附件打包及内嵌图片构造方法,并演示如何配置 QQ 邮箱授权码进行安全 SSL 连接,附带高频报错排查指南。
SMTP 协议与核心库基础
实现邮件自动投递需理解底层通信规则与 Python 标准库分工。SMTP(Simple Mail Transfer Protocol)负责定义邮件源端与接收端之间的传输规范。Python 无需安装第三方依赖即可调用两个核心模块:
smtplib:封装 SMTP 客户端逻辑,负责建立网络连接、身份认证与数据投递。email:负责按 RFC 规范组装邮件报文头(From/To/Subject)与正文载荷(文本/HTML/附件/多部分组合),确保邮件结构符合服务端校验标准。
标准连接与发送流程
所有邮件发送均遵循相同生命周期:实例化对象 → 建立 TCP 连接 → 登录认证 → 组装报文 → 执行投递 → 关闭会话。
第1步:初始化 SMTP 客户端对象
创建连接对象时需明确服务器地址与端口策略。非加密默认端口为 25,现代邮箱普遍强制要求 TLS/SSL 加密,推荐直接使用 SSL 专用类与端口 465。
import smtplib
# 语法结构:smtplib.SMTP(host, port, local_hostname)
# 常规明文连接示例(仅适用内部自建服务)
smtp_obj = smtplib.SMTP('localhost', 25)
第2步:调用 sendmail 执行投递
连接成功后,使用 sendmail() 提交报文。该方法严格校验收发件人列表格式,即便单收件人也必须包裹于列表中。
smtp_obj.sendmail(
from_addr='user@example.com',
to_addrs=['target@example.com'],
msg=raw_message_string
)
实战:构建不同类型邮件
第3步:发送纯文本通知邮件
适用于系统告警或简短状态同步。核心是使用 MIMEText 声明主体类型为 'plain',并通过头部字段设置发件人昵称与主题。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
sender = 'sender@example.com'
receivers = ['receiver@example.com']
msg = MIMEText('Python 邮件发送测试:这是一段纯文本内容', 'plain', 'utf-8')
msg['From'] = Header('发件人昵称', 'utf-8')
msg['To'] = Header('收件人昵称', 'utf-8')
msg['Subject'] = Header('Python SMTP 纯文本测试', 'utf-8')
try:
smtp_obj = smtplib.SMTP('localhost')
smtp_obj.sendmail(sender, receivers, msg.as_string())
print("纯文本邮件投递成功")
except smtplib.SMTPException as e:
print(f"投递失败: {e}")
第4步:发送含排版与表格的 HTML 邮件
适合推送数据报表或活动公告。只需将 MIMEText 的 _subtype 参数改为 'html',正文可包含标准 CSS 样式与 DOM 元素。
import smtplib
from email.mime.text import MIMEText
from email.header import Header
sender = 'sender@example.com'
receivers = ['receiver@example.com']
html_content = """
<p>Python 邮件发送测试...</p>
<p>这是 <b>HTML 格式</b> 的邮件,支持富文本:</p>
<p>1. 点击访问 <a href="http://www.example.com">示例链接</a></p>
<table border="1">
<tr><th>姓名</th><th>年龄</th></tr>
<tr><td>张三</td><td>25</td></tr>
<tr><td>李四</td><td>30</td></tr>
</table>
"""
msg = MIMEText(html_content, 'html', 'utf-8')
msg['From'] = Header('发件人昵称', 'utf-8')
msg['To'] = Header('收件人昵称', 'utf-8')
msg['Subject'] = Header('Python SMTP HTML 邮件测试', 'utf-8')
try:
smtp_obj = smtplib.SMTP('localhost')
smtp_obj.sendmail(sender, receivers, msg.as_string())
print("HTML 邮件投递成功")
except smtplib.SMTPException as e:
print(f"投递失败: {e}")
第5步:附加文件实现带附件发送
当需要分发日志、表格或压缩包时,需使用 MIMEMultipart 构建混合容器。附件读取时必须以二进制模式 'rb' 打开,并正确声明 Content-Disposition 为 attachment。
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
sender = 'sender@example.com'
receivers = ['receiver@example.com']
msg = MIMEMultipart()
msg['From'] = Header('发件人昵称', 'utf-8')
msg['To'] = Header('收件人昵称', 'utf-8')
msg['Subject'] = Header('Python SMTP 带附件测试', 'utf-8')
msg.attach(MIMEText('这是带附件的邮件正文...', 'plain', 'utf-8'))
# 添加第一个附件
with open('test.txt', 'rb') as f:
att1 = MIMEText(f.read(), 'base64', 'utf-8')
att1['Content-Type'] = 'application/octet-stream'
att1['Content-Disposition'] = 'attachment; filename="report.txt"'
msg.attach(att1)
try:
smtp_obj = smtplib.SMTP('localhost')
smtp_obj.sendmail(sender, receivers, msg.as_string())
print("带附件邮件投递成功")
except smtplib.SMTPException as e:
print(f"投递失败: {e}")
第6步:通过 Content-ID 在正文中嵌入图片
若希望图片直接渲染在邮件视图中而非作为独立附件下载,需采用 MIMEMultipart('related') 配合 cid: 引用机制。HTML 中的 src 属性值必须与图片主体的 Content-ID 头严格一致。
import smtplib
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
sender = 'sender@example.com'
receivers = ['receiver@example.com']
msgRoot = MIMEMultipart('related')
msgRoot['From'] = Header('发件人昵称', 'utf-8')
msgRoot['To'] = Header('收件人昵称', 'utf-8')
msgRoot['Subject'] = Header('Python SMTP 内嵌图片测试', 'utf-8')
# 备选方案容器:兼容不支持 HTML 的客户端
msgAlternative = MIMEMultipart('alternative')
msgRoot.attach(msgAlternative)
html_body = """<p>图片已嵌入正文:</p><p><img src="cid:logo_img"></p>"""
msgAlternative.attach(MIMEText(html_body, 'html', 'utf-8'))
with open('logo.png', 'rb') as img_f:
img_msg = MIMEImage(img_f.read())
img_msg.add_header('Content-ID', '<logo_img>')
msgRoot.attach(img_msg)
try:
smtp_obj = smtplib.SMTP('localhost')
smtp_obj.sendmail(sender, receivers, msgRoot.as_string())
print("内嵌图片邮件投递成功")
except smtplib.SMTPException as e:
print(f"投递失败: {e}")
对接第三方 SMTP 服务(QQ 邮箱配置)
生产环境通常放弃本地 sendmail 代理,转而调用运营商提供的标准化 SMTP 网关。该方式跨平台兼容,但必须开启服务权限并使用授权码替代原始密码。
第7步:启用 SSL 通道完成安全登录与投递
准备工作:登录目标邮箱进入设置 → 账户,找到 POP3/SMTP/IMAP 服务区域,开启 IMAP/SMTP 开关并完成短信验证,获取 16 位授权码。
参数配置:QQ 邮箱 SMTP 主机为 smtp.qq.com,SSL 专属端口为 465。连接时必须使用 smtplib.SMTP_SSL 类。
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
my_sender = '123456@qq.com' # 发件人账号
my_pass = 'abcdefghijklmnop' # 授权码(非登录密码)
my_user = '654321@qq.com' # 收件人账号
def send_ssl_mail():
ret = True
try:
msg = MIMEText('这是使用 QQ 邮箱 SMTP 发送的测试邮件', 'plain', 'utf-8')
msg['From'] = formataddr(["发件人", my_sender])
msg['To'] = formataddr(["收件人", my_user])
msg['Subject'] = "Python SMTP QQ 邮箱安全测试"
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
server.login(my_sender, my_pass)
server.sendmail(my_sender, [my_user], msg.as_string())
server.quit()
except Exception as e:
print(f"发送失败原因:{e}")
ret = False
return ret
if send_ssl_mail():
print("QQ 邮箱安全投递成功")
else:
print("QQ 邮箱安全投递失败")
其他服务商(如网易 163、企业微信等)接入逻辑一致:替换 host、port 并获取对应授权凭证即可复用上述代码结构。
高频异常排查
| 报错现象 | 排查方向 | 解决动作 |
|---|---|---|
SMTPAuthenticationError | 凭证不匹配或服务未激活 | 重新生成授权码;登录网页端确认 IMAP/SMTP 开关处于开启状态 |
SMTPConnectError | 网络拦截或参数错误 | 核对 smtp.qq.com 等标准域名;检查本地防火墙/代理是否阻断 465 端口 |
| 正文乱码或图片缺失 | 编码声明缺失或 CID 错位 | MIMEText 强制指定 'utf-8';检查 HTML src="cid:xxx" 与 add_header('Content-ID', '<xxx>') 标识完全闭环 |
| 投递成功但收不到信 | 反垃圾策略拦截 | 移入垃圾箱白名单;避免群发高频敏感词;首次发送可先抄送自身域名验证链路 |
总结
掌握 smtplib 的连接控制与 email 模块的结构化拼装,即可灵活应对日常运维监控、定时报表推送、用户验证信等自动化场景。配合 schedule 调度器与 CSV 循环读取,可进一步升级为批量个性化触达系统。以上就是Python3 SMTP发送邮件实战操作的详细内容,更多关于Python电子邮件自动化与smtplib库调用的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













