Python学习超简单第十一弹:邮件发送

Python快乐学习、快乐成长

1、邮件发送

Python3 中应用的SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。

2、发送纯文本邮件

smtplib提供了一种很方便的途径发送电子邮件。它对 smtp 协议进行了简单的封装。

Python创建 SMTP 对象语法如下:

import smtplib

smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )

示列代码:

python 复制代码
import smtplib
from email.mime.text import MIMEText

# 1. 配置邮件发送信息(替换成自己的信息)
sender = "你的邮箱地址@qq.com"  # 发件人邮箱
password = "你的邮箱授权码"      # 不是登录密码,是授权码
receiver = "接收人邮箱地址@163.com"  # 收件人邮箱(可多个,用列表:["a@163.com", "b@qq.com"])
smtp_server = "smtp.qq.com"    # 对应邮箱的SMTP服务器地址
smtp_port = 465                # SSL加密端口,固定465

# 2. 构建邮件内容(纯文本)
mail_subject = "Python SMTP 测试邮件"  # 邮件主题
mail_content = "这是用 Python3 smtplib 发送的纯文本测试邮件,新手入门必看!"  # 邮件正文

# 创建邮件对象,指定编码(防止中文乱码)
msg = MIMEText(mail_content, "plain", "utf-8")
msg["From"] = sender  # 发件人
msg["To"] = receiver  # 收件人(多个收件人用逗号分隔)
msg["Subject"] = mail_subject  # 邮件主题

# 3. 连接SMTP服务器并发送邮件
try:
    # 连接SMTP服务器(SSL加密方式)
    server = smtplib.SMTP_SSL(smtp_server, smtp_port)
    # 登录邮箱
    server.login(sender, password)
    # 发送邮件(sender:发件人,receiver:收件人,msg.as_string():邮件内容转字符串)
    server.sendmail(sender, receiver, msg.as_string())
    print("邮件发送成功!")
except Exception as e:
    print(f"邮件发送失败,错误信息:{e}")
finally:
    # 关闭连接
    server.quit()

解析:

  • smtplib.SMTP_SSL():使用 SSL 加密连接 SMTP 服务器,避免邮件内容被窃取,端口固定为 465(推荐使用,更安全);
  • MIMEText():创建纯文本邮件对象,参数分别是「邮件正文」「邮件格式(plain 为纯文本)」「编码(utf-8 防止中文乱码)」;
  • msg["From"]/["To"]/["Subject"]:设置邮件的发件人、收件人、主题,必须填写,否则邮件会被判定为垃圾邮件;
  • server.login():用发件人邮箱和授权码登录 SMTP 服务器;
  • server.sendmail():发送邮件,第三个参数必须是邮件对象转字符串(msg.as_string());
  • try-except-finally:捕获发送过程中的异常,确保无论成功与否,都关闭服务器连接。

3、发送带附件的邮件

实际应用中,我们经常需要发送带附件的邮件(如报表、文档、图片等),这时候需要用到 email.mime.multipart.MIMEMultipart 模块,实现「正文+附件」的组合发送。

示例代码如下:

python 复制代码
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header  # 用于设置邮件主题中文格式

# 1. 配置邮件发送信息(替换成自己的信息)
sender = "你的邮箱地址@163.com"
password = "你的邮箱授权码"
receiver = ["接收人1@qq.com", "接收人2@163.com"]  # 多个收件人,用列表
smtp_server = "smtp.163.com"
smtp_port = 465

# 2. 构建邮件对象(支持附件)
msg = MIMEMultipart()
msg["From"] = sender
msg["To"] = ",".join(receiver)  # 多个收件人用逗号分隔,转字符串
msg["Subject"] = Header("Python SMTP 带附件测试邮件", "utf-8")  # 中文主题,避免乱码

# 3. 邮件正文(可写HTML格式,也可写纯文本)
mail_content = """
这是用 Python 发送的带附件测试邮件附件包含:测试文档和测试图片新手可直接复制代码,替换自己的信息即可使用!
"""
# 正文内容(HTML格式,更美观)
text_part = MIMEText(mail_content, "html", "utf-8")
msg.attach(text_part)  # 将正文添加到邮件对象中

# 4. 添加附件(支持多个附件,重复以下代码即可)
# 附件1:测试文档(txt格式)
attachment1 = MIMEText(open("test.txt", "rb").read(), "base64", "utf-8")
attachment1["Content-Type"] = "application/octet-stream"  # 附件类型
# 设置附件显示名称(中文需用Header处理,避免乱码)
attachment1["Content-Disposition"] = 'attachment; filename="测试文档.txt"'
msg.attach(attachment1)  # 将附件添加到邮件对象

# 附件2:测试图片(jpg格式)
attachment2 = MIMEText(open("test.jpg", "rb").read(), "base64", "utf-8")
attachment2["Content-Type"] = "application/octet-stream"
attachment2["Content-Disposition"] = 'attachment; filename="测试图片.jpg"'
msg.attach(attachment2)

# 5. 发送邮件
try:
    server = smtplib.SMTP_SSL(smtp_server, smtp_port)
    server.login(sender, password)
    server.sendmail(sender, receiver, msg.as_string())
    print("带附件邮件发送成功!")
except Exception as e:
    print(f"带附件邮件发送失败,错误信息:{e}")
finally:
    server.quit()

解析:

  • MIMEMultipart():创建支持多部分内容(正文+附件)的邮件对象,是发送附件的核心;
  • Header():处理中文主题,避免中文乱码(纯文本主题可不用,但推荐使用);
  • 邮件正文支持 HTML 格式:将 MIMEText 的第二个参数改为 "html",即可在正文中使用 HTML 标签让正文更美观;
  • 添加附件:
    1. 用 open() 以二进制模式(rb)读取附件文件;
    2. 用 MIMEText 对附件内容进行 base64 编码(避免附件损坏);
    3. 设置 Content-Type 为 application/octet-stream(通用附件类型);
    4. 设置 Content-Disposition,指定附件显示名称(filename 可自定义);
    5. 用 msg.attach() 将附件添加到邮件对象中,多个附件重复此步骤即可。

4、定时发送邮件

安装依赖库,语法如下:

pip install schedule # 用于定时任务

定时发送代码示例:

python 复制代码
import smtplib
import schedule
import time
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart

# 1. 定义邮件发送函数(复用之前的带附件逻辑)
def send_email():
    sender = "你的邮箱地址@qq.com"
    password = "你的邮箱授权码"
    receiver = "接收人邮箱@163.com"
    smtp_server = "smtp.qq.com"
    smtp_port = 465

    msg = MIMEMultipart()
    msg["From"] = sender
    msg["To"] = receiver
    msg["Subject"] = "每日定时测试邮件"

    # 正文
    content = f"当前时间:{time.strftime('%Y-%m-%d %H:%M:%S')}\n这是每日定时发送的邮件,自动化测试成功!"
    text_part = MIMEText(content, "plain", "utf-8")
    msg.attach(text_part)

    # 发送邮件
    try:
        server = smtplib.SMTP_SSL(smtp_server, smtp_port)
        server.login(sender, password)
        server.sendmail(sender, receiver, msg.as_string())
        print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} 定时邮件发送成功!")
    except Exception as e:
        print(f"定时邮件发送失败,错误信息:{e}")
    finally:
        server.quit()

# 2. 设置定时任务(每天8:00发送)
schedule.every().day.at("08:00").do(send_email)

# 3. 循环执行定时任务
print("定时任务已启动,等待发送邮件...")
while True:
    schedule.run_pending()  # 检查是否有定时任务需要执行
    time.sleep(60)  # 每隔60秒检查一次

解析:

  • schedule.every().day.at("08:00").do(send_email):设置每天8:00执行 send_email 函数;
  • while True + schedule.run_pending():循环检查定时任务,确保任务能按时执行;
  • time.sleep(60):每隔60秒检查一次,避免占用过多CPU资源;
  • 如果需要修改定时规则,可参考:
    • 每小时发送:schedule.every().hour.do(send_email)
    • 每周一8:00发送:schedule.every().monday.at("08:00").do(send_email)
    • 每隔30分钟发送:schedule.every(30).minutes.do(send_email)

5、常见问题排查

1. 错误:smtplib.SMTPAuthenticationError: (535, b'Login fail. Please enter your authorization code to login.')

原因:授权码错误,或未开启 SMTP 服务。

解决方案:重新检查授权码,确认邮箱的 SMTP 服务已开启,重新生成授权码重试。
2. 错误:smtplib.SMTPConnectError: Connection refused

原因:SMTP 服务器地址或端口错误。

解决方案:核对邮箱的 SMTP 服务器地址和端口,确保使用 465 端口(SSL 加密)。
3. 邮件发送成功,但收件人收不到

原因:邮件被判定为垃圾邮件,或收件人地址错误。

解决方案:检查收件人地址;在收件人邮箱的垃圾邮件箱中查找,标记为正常邮件;优化邮件主题和正文,避免使用敏感词汇(如"广告""推广""测试"可适当修改)。
4. 中文乱码

原因:未设置正确的编码,或中文主题/附件名未用Header 处理。

解决方案:确保 MIMEText 的编码为 utf-8,中文主题用 Header() 处理,中文附件名也用 Header() 处理。
5. 附件无法打开或损坏

原因:读取附件时未用二进制模式(rb),或编码错误。

解决方案:确保读取附件时使用 open("文件路径", "rb"),附件编码设置为 base64。


结尾

记录自己的快乐学习日志,也祝贺观看到这的小伙伴早日学有所成,财富自由💰💰。

记得点赞👍、收藏👋呀!!!

相关推荐
qq_372154232 小时前
如何配置表中某列的排序权重_全文索引配置与权重分配
jvm·数据库·python
CoderCodingNo2 小时前
【信奥业余科普】C++ 的奇妙之旅 | 14:程序的分叉路口——逻辑判断与 if-else 语句
开发语言·c++
还是阿落呀2 小时前
如何判断一个年份是否为闰年?
python
The Chosen One9852 小时前
a进制转b进制的转换总结
开发语言·c++
2501_914245932 小时前
CSS如何使用-nth-of-type精确选择列表项_通过元素类型限制提升样式健壮性
jvm·数据库·python
ECT-OS-JiuHuaShan2 小时前
哲学的本质,是递归因果
java·开发语言·人工智能·科技·算法·机器学习·数学建模
overmind2 小时前
oeasy Python 124 序列_字符串_string_str
开发语言·python
一个假的前端男2 小时前
Flutter 实现 BLE 设备 WiFi 配网流程实践
开发语言·flutter
吕源林2 小时前
Golang如何做本地缓存加速_Golang本地缓存教程【核心】
jvm·数据库·python