跳转至

最后更新:2026-09-04 00:01

实验20 Python邮件

难度:★★☆ | 预估时长:90 分钟

20.1 实验目的

  • 知识目标:理解 SMTP 邮件发送原理与 QQ 邮箱授权码的安全作用,能区分纯文本邮件与附件邮件所用的模块差异(MIMEText 与 MIMEMultipart)。
  • 技能目标:能用 Python 内置模块完成极简固定发信、发送带附件的邮件、定时自动发信三个由浅入深的工程案例,打通邮件自动化闭环。
  • 素养目标:树立「授权码代替真实密码」的安全意识,建立用代码解决批量、定时办公痛点的自动化思维。

20.1.1 课堂提问

平时手动发邮件流程:打开邮箱 → 登录 → 新建邮件 → 写标题正文 → 添加附件 → 选择收件人 → 点击发送。

思考以下实际工作场景:

  1. 批量与附件痛点:你需要给 100 个客户发送当月的账单(每个人的附件都不同),手动发送极易发错。
  2. 定时通知痛点:公司的自动化测试脚本在凌晨 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 内置模块,无需额外安装:

  1. MIMEText:负责编写纯文本形式的邮件正文、标题、收发件人信息;
  2. 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 内置的 timedatetime 模块,写一个 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 综合实战大演练(随堂练习)

任务要求

  1. 完成前置操作:获取 QQ 邮箱的 16 位授权码。
  2. 具体场景:在你的代码同级目录下随便准备一张图片或一个文本文档作为附件。修改代码,将定时发送的时间设定为当前时间的后 2 分钟
  3. 运行代码,不要关掉黑窗口,静静等待 2 分钟。
  4. 看到控制台提示发送成功后,前往你的目标收件箱,截取一张带有附件收信成功的网页截图作为作业提交。

常见错误与排错

  • 若一直收不到邮件:确认 target_time 已改为当前时间的后 2 分钟,且程序窗口没有被关闭;
  • 若附件发送报错:检查附件文件名、路径与代码中 file_name 是否完全一致。

20.5 实验总结

本次实验掌握了以下要点:

  1. 一是安全第一:凡是用代码发信,必须使用 16 位 SMTP 授权码,严禁使用 QQ 真实登录密码(对应素养目标);
  2. 二是理解了模块分工:纯文本邮件用 MIMEText 搞定;只要带附件,必须升级为 MIMEMultipart 当"大包裹",并用 msg.attach() 装东西(对应知识目标);
  3. 三是完成了极简固定发信、发送带附件的邮件、定时自动发信三个由浅入深的工程案例,能打通邮件自动化闭环(对应技能目标)。

20.6 作业提交

  1. 提交地点:吾爱作业网

  2. 提交资料:

  3. 作业1:Python 代码发送邮件成功的控制台截图【至少1张】;
  4. 作业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 文档素材

实验素材下载

点击下方链接获取本节课全部资源(含课件、任务清单、安装包等): 🔗 夸克网盘

本站总访问 次 | 访客 人 | 本页阅读