最后更新:2026-09-04 00:01
实验20 Python邮件
难度:★★☆ | 预估时长:90 分钟
20.1 实验目的
- 知识目标:理解 SMTP 邮件发送原理与 QQ 邮箱授权码的安全作用,能区分纯文本邮件与附件邮件所用的模块差异(MIMEText 与 MIMEMultipart)。
- 技能目标:能用 Python 内置模块完成极简固定发信、发送带附件的邮件、定时自动发信三个由浅入深的工程案例,打通邮件自动化闭环。
- 素养目标:树立「授权码代替真实密码」的安全意识,建立用代码解决批量、定时办公痛点的自动化思维。
20.1.1 课堂提问
平时手动发邮件流程:打开邮箱 → 登录 → 新建邮件 → 写标题正文 → 添加附件 → 选择收件人 → 点击发送。
思考以下实际工作场景:
- 批量与附件痛点:你需要给 100 个客户发送当月的账单(每个人的附件都不同),手动发送极易发错。
- 定时通知痛点:公司的自动化测试脚本在凌晨 3 点运行完毕生成了报告,你想让代码自动把结果和报告文件发给主管,不可能定个闹钟半夜爬起来手动发。
20.1.2 本节课学习目标
使用 Python 内置模块打通邮件自动化闭环,分为三个由浅入深的工程案例:
- 方法 1:极简固定发信法(打通底层协议通道)
- 方法 2:发送带附件的邮件(解决真实办公需求)
- 方法 3:定时自动发信(实现真正的无人值守)
20.2 实验环境
- 软件工具:Python(使用内置的 smtplib、email 模块,无需额外安装第三方库)
- 前置准备:参照《QQ 邮箱授权码获取指南》,拿到16 位 SMTP 授权码,代码中密码位置统一填写该授权码,严禁使用QQ真实登录密码!
20.3 实验重难点
- 重点:三种发信方法(极简发信、带附件发信、定时自动发信)的代码编写与运行;SMTP 授权码的正确使用。
- 难点:附件邮件必须用 MIMEMultipart「大信封」装信并做 Base64 编码防损坏;定时发送用 while True 循环监控时间并防止重复发送。
20.4 实验内容
20.4.1 方法1:极简固定发信法【纯文本】
20.4.1.1 适用场景
第一次体验代码发邮件,所有信息直接写在代码中,优先保证程序一次运行成功,建立自信。
20.4.1.2 核心模块说明
本次仅使用两个 Python 内置模块,无需额外安装:
MIMEText:负责编写纯文本形式的邮件正文、标题、收发件人信息;
smtplib:负责"当邮递员",连接邮箱服务器、登录账号、完成信件投递。
为什么发邮件要用授权码,不能用 QQ 密码?
授权码就像给程序专门办的「门禁卡」:它只能开门(发邮件),就算写在代码里不小心泄露了,也不影响你的 QQ 本体安全;QQ 真实密码则绝对不能写进代码。
20.4.1.3 完整可运行代码
使用说明:将代码中 你的QQ号、收件人邮箱、你的16位英文授权码 替换为自己的真实信息。
| # 导入所需内置模块
import smtplib
from email.mime.text import MIMEText
# ========== 第一步:编写邮件内容 ==========
# 1. 设置邮件正文,plain=纯文本格式,utf-8=防止中文乱码
msg = MIMEText("你好,这是一封完全由 Python 代码发出的极简测试邮件!", "plain", "utf-8")
# 2. 设置邮件标题
msg["Subject"] = "来自 Python 的第一封信"
# 3. 设置发件人邮箱
msg["From"] = "你的QQ号@qq.com"
# 4. 设置收件人邮箱
msg["To"] = "收件人邮箱"
# ========== 第二步:连接服务器并发送邮件 ==========
try:
print("🚀 正在连接QQ邮箱服务器...")
# 连接QQ邮箱加密服务器,固定地址和端口:smtp.qq.com 465
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
# 登录邮箱:账号 + 16位授权码(重点!不是QQ密码)
server.login("你的QQ号@qq.com", "你的16位英文授权码")
# 执行发送操作
server.sendmail("你的QQ号@qq.com", ["收件人邮箱"], msg.as_string())
print("✅ 邮件发送成功!快去邮箱查看吧!")
except Exception as e:
# 捕获并打印错误信息
print(f"❌ 发送失败,原因:{e}")
finally:
# 无论成功/失败,最后都关闭服务器连接
server.quit()
|
运行结果如下:

图 20-1:极简发信法运行结果
常见错误与排错
- 若提示
(535, b'Error: authentication failed'):说明授权码填错或还没开启 SMTP 服务,重新按《QQ 邮箱授权码获取指南》生成新的授权码;
- 若提示连接超时:检查电脑网络,确认服务器地址写的是
smtp.qq.com、端口 465;
- 若收件人没收到:先查看垃圾邮件箱,再确认收件人邮箱地址拼写无误。
20.4.2 方法2:发送带附件的邮件
20.4.2.1 适用场景
当需要把 Python 处理好的 Excel 表格、系统生成的日志文件或者 PDF 报告连同邮件一起发送时使用。
20.4.2.2 原理说明
如果带有附件,邮件的性质就变了,它不再是一张"明信片",而是一个"包裹"。所以我们必须引入 MIMEMultipart (用来装信件和附件的大信封)和 MIMEApplication(用来读取文件对象)。
附件为什么要 Base64 编码?
图片是二进制数据,直接塞进邮件像「裸寄玻璃杯」,路上容易碎(乱码损坏);Base64 编码就像给它套上缓冲泡沫箱,保证在网络上安全传输、收到不损坏。
20.4.2.3 完整可运行代码
| import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage # 专门针对图片的模块
from email import encoders # 专门负责网络编码的模块
file_name = r"C:\Users\saberQueen\Desktop\问题.png"
# 1. 准备大信封
msg = MIMEMultipart()
msg["Subject"] = "测试:修复图片损坏问题"
msg["From"] = "你的邮箱"
msg["To"] = "接收方的邮箱"
# 2. 塞入正文
msg.attach(MIMEText("请查看附件,这次图片绝对不会损坏了!", "plain", "utf-8"))
# 3. 读取并处理图片附件(核心修复区)
try:
# 必须是 "rb" 二进制读取
with open(file_name, "rb") as f:
img_data = f.read()
# 使用专门的 MIMEImage 模块,并告诉它这是 png 格式
img_attachment = MIMEImage(img_data, _subtype="png")
# 【最关键一步】使用 Base64 重新编码,确保能在网络安全传输!
encoders.encode_base64(img_attachment)
# 设置附件在邮件里的显示名称
img_attachment.add_header('Content-Disposition', 'attachment', filename=file_name)
# 放入大信封
msg.attach(img_attachment)
print("✅ 图片装载成功,已进行 Base64 编码防损处理。")
except FileNotFoundError:
print(f"❌ 找不到图片:请确认代码旁边真的有一张叫 {file_name} 的图片!")
# 4. 发送操作(原样保留)
try:
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
server.login("你的邮箱", "jqsxacyzalwvjeag")
server.sendmail("你的邮箱", ["接收方的邮箱"], msg.as_string())
print("✅ 邮件发送成功!")
except Exception as e:
print(f"❌ 发送出错:{e}")
finally:
server.quit()
|
结果如下:

图 20-2:带附件邮件发送结果
常见错误与排错
- 若提示
FileNotFoundError 找不到图片:检查 file_name 路径是否与图片实际位置一致(文件名、后缀都要完全对上);
- 若收到的图片打不开或损坏:确认代码用的是
"rb" 二进制模式读取,并且执行了 encoders.encode_base64()。
20.4.3 方法3:定时自动发送邮件
20.4.3.1 适用场景
设定每天的固定时间(如下班前 18:00),代码自动触发发送流程,结合前面的附件功能,实现真正的办公自动化。
20.4.3.2 原理说明
利用 Python 内置的 time 和 datetime 模块,写一个 while True 的死循环。程序每隔一小段时间看一眼电脑时间,一旦时间匹配就执行发信函数。
20.4.3.3 完整可运行代码
| import smtplib
import time
import datetime
from email.mime.text import MIMEText
# 将发邮件的核心逻辑封装成一个函数(Function)
def send_auto_mail():
msg = MIMEText("这是一封系统定时自动触发的邮件,恭喜你测试成功!", "plain", "utf-8")
msg["Subject"] = "【定时任务】下班提醒"
msg["From"] = "你的QQ号@qq.com"
msg["To"] = "收件人邮箱@163.com"
try:
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
server.login("你的QQ号@qq.com", "你的16位英文授权码")
server.sendmail("你的QQ号@qq.com", ["收件人邮箱@163.com"], msg.as_string())
print(f"✅ [{datetime.datetime.now()}] 邮件准点发送成功!")
except Exception as e:
print(f"❌ 发送失败:{e}")
finally:
server.quit()
# ========== 定时监控中枢 ==========
# 假设你想在今天下午 17点30分 发送
target_time = "17:30"
print(f"⏳ 定时任务已启动,系统将默默等待,直到 {target_time} 准点发送...")
# 开启死循环不断监控时间
while True:
# 获取当前电脑的 时:分 格式
current_time = datetime.datetime.now().strftime("%H:%M")
if current_time == target_time:
print("🎯 时间到!开始执行发信任务...")
send_auto_mail()
# 核心细节:发完之后立刻让程序睡 60 秒!
# 防止程序在这个一分钟内疯狂重发几百封邮件
print("💤 任务完成,进入休眠以防重复发送...")
time.sleep(60)
# 为了不占用电脑过多CPU,没到时间的话,每隔10秒再睁眼看一次时间
time.sleep(10)
|
结果:

图 20-3:定时自动发送邮件运行结果
发完邮件后为什么要立刻 time.sleep(60)?
因为时间精确到「分」:在这一分钟内循环还会转好几圈,如果不睡 60 秒,程序会在这 1 分钟里疯狂重发几百封一样的邮件。
常见错误与排错
- 若程序一直等待没反应:检查
target_time 是否已改成当前时间的后 1~2 分钟(格式为 24 小时制「时:分」,如 14:05);
- 若想中途停止死循环:在黑窗口按 Ctrl + C 终止程序;
- 运行期间不要关闭黑窗口,窗口一关定时任务就停了。
| import os
import time
import datetime
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email import encoders
# ========== 将发信逻辑封装为独立函数 ==========
def send_attachment_mail():
file_name = "C盘\X\X\X\问题.png"
# 【质量闸门】严格检查附件是否存在,找不到直接报错终止
if not os.path.exists(file_name):
raise FileNotFoundError(f"❌ 严重错误:在同级目录下找不到名为【{file_name}】的图片!")
# 1. 准备大信封
msg = MIMEMultipart()
msg["Subject"] = "【系统通知】定时触发的图片报告"
msg["From"] = "你的QQ号@qq.com"
msg["To"] = "收件人邮箱@163.com"
# 2. 塞入正文
msg.attach(MIMEText("主管您好,时间已到,这是系统自动定时的进度汇报,详情请看附件图片。", "plain", "utf-8"))
# 3. 读取并处理图片附件
with open(file_name, "rb") as f:
img_data = f.read()
img_attachment = MIMEImage(img_data, _subtype="png")
encoders.encode_base64(img_attachment) # Base64编码防损坏
img_attachment.add_header('Content-Disposition', 'attachment', filename=file_name)
msg.attach(img_attachment)
# 4. 执行网络发送
try:
print("🚀 正在连接服务器投递附件...")
server = smtplib.SMTP_SSL("smtp.qq.com", 465)
server.login("你的QQ号@qq.com", "你的16位英文授权码")
server.sendmail("你的QQ号@qq.com", ["收件人邮箱@163.com"], msg.as_string())
print(f"✅ [{datetime.datetime.now()}] 邮件及附件准点发送成功!")
except Exception as e:
print(f"❌ 发送失败,网络异常:{e}")
finally:
server.quit()
# ========== 定时监控中枢 ==========
# 建议测试时,将时间改为当前电脑时间的后 1~2 分钟
target_time = "17:30"
print(f"⏳ 定时附件任务已启动,系统将默默等待至 {target_time}...")
while True:
current_time = datetime.datetime.now().strftime("%H:%M")
if current_time == target_time:
print("🎯 时间匹配!开始读取附件并执行发信任务...")
# 调用发信函数
send_attachment_mail()
# 【质量闸门】作为单次任务,发完立刻退出死循环,避免后台常驻
print("🏁 今日发送任务已圆满完成,程序安全退出。")
break
# 没到时间则休眠 10 秒,降低 CPU 占用
time.sleep(10)
|
20.4.4 综合实战大演练(随堂练习)
任务要求
- 完成前置操作:获取 QQ 邮箱的 16 位授权码。
- 具体场景:在你的代码同级目录下随便准备一张图片或一个文本文档作为附件。修改代码,将定时发送的时间设定为当前时间的后 2 分钟。
- 运行代码,不要关掉黑窗口,静静等待 2 分钟。
- 看到控制台提示发送成功后,前往你的目标收件箱,截取一张带有附件收信成功的网页截图作为作业提交。
常见错误与排错
- 若一直收不到邮件:确认
target_time 已改为当前时间的后 2 分钟,且程序窗口没有被关闭;
- 若附件发送报错:检查附件文件名、路径与代码中
file_name 是否完全一致。
20.5 实验总结
本次实验掌握了以下要点:
- 一是安全第一:凡是用代码发信,必须使用 16 位 SMTP 授权码,严禁使用 QQ 真实登录密码(对应素养目标);
- 二是理解了模块分工:纯文本邮件用
MIMEText 搞定;只要带附件,必须升级为 MIMEMultipart 当"大包裹",并用 msg.attach() 装东西(对应知识目标);
- 三是完成了极简固定发信、发送带附件的邮件、定时自动发信三个由浅入深的工程案例,能打通邮件自动化闭环(对应技能目标)。
20.6 作业提交
-
提交地点:吾爱作业网
-
提交资料:
- 作业1:Python 代码发送邮件成功的控制台截图【至少1张】;
- 作业2:收件箱收到带附件邮件的网页截图【至少1张】。
20.7 知识检测
- [ ] (填空)QQ 邮箱代码发信必须使用______位 SMTP 授权码,严禁使用 QQ 真实登录密码。(16)
- [ ] (填空)QQ 邮箱加密服务器地址是__,端口是____。(smtp.qq.com、465)
- [ ] (选择)发送带附件的邮件,必须用哪个模块当"大信封"?A. MIMEText B. MIMEMultipart C. smtplib D. time
查看解析
正确答案:B。纯文本邮件用 MIMEText 即可;只要带附件,必须升级为 MIMEMultipart,并用 msg.attach() 装入正文和附件。
- [ ] (填空)定时发送成功一次后,代码立刻执行 time.sleep(______),防止在这一分钟内重复发送大量邮件。(60)
本课相关资源
| 序号 |
资源名称 |
类型 |
说明 |
| 1 |
实验0527:Python邮件自动化三合一.html |
HTML |
实验原始文档 |
| 2 |
QQ 邮箱授权码获取与管理指南指南.docx |
Word |
文档素材 |
实验素材下载
点击下方链接获取本节课全部资源(含课件、任务清单、安装包等):
🔗 夸克网盘