news 2026/4/15 21:59:40

Day 43:【99天精通Python】发送邮件 (smtplib) - 你的自动化信使

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Day 43:【99天精通Python】发送邮件 (smtplib) - 你的自动化信使

Day 43:【99天精通Python】发送邮件 (smtplib) - 你的自动化信使

前言

欢迎来到第43天!

在前面的课程中,我们学会了写爬虫、做数据分析、处理 Excel 和图片。当这些自动化任务运行结束后,我们通常希望第一时间收到通知,比如:

  • 爬虫抓到了新的优惠信息,发邮件提醒我。
  • 每天凌晨 2 点自动备份数据库,并把日志文件发给运维。
  • 监控股票价格,跌破止损线时发警报。

虽然现在微信、钉钉通知很流行,但邮件依然是职场中最正式、最通用的通知方式。Python 内置的smtplibemail模块,可以让我们轻松实现邮件的自动发送。

本节内容:

  • 邮件发送原理 (SMTP)
  • 准备工作:获取授权码
  • 发送纯文本邮件
  • 发送 HTML 富文本邮件
  • 发送带附件的邮件
  • 封装成通用的邮件工具类

一、邮件发送原理

发送邮件就像寄信,需要两个核心要素:

  1. 信封和信纸:由email模块负责,构建邮件的标题、正文、附件等格式。
  2. 邮局:由smtplib模块负责,通过SMTP (Simple Mail Transfer Protocol)协议将邮件发给邮件服务器(如 QQ 邮箱服务器、网易邮箱服务器)。

注意:接收邮件通常使用 POP3 或 IMAP 协议,但今天我们只讲发送。


二、准备工作:开启 SMTP 服务

出于安全考虑,现代邮箱不允许直接使用登录密码在代码中发邮件,必须使用授权码 (Authorization Code)

QQ 邮箱为例(163/Gmail 类似):

  1. 登录网页版 QQ 邮箱。
  2. 点击设置->账户
  3. 找到POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务
  4. 开启POP3/SMTP服务
  5. 按照提示发送短信验证,获取一串字符(如abcdefghijklmn),这就是授权码

常用 SMTP 服务器配置

邮箱SMTP 服务器SSL 端口 (推荐)非 SSL 端口
QQsmtp.qq.com46525
163smtp.163.com46525
Gmailsmtp.gmail.com465587 (TLS)

三、发送第一封纯文本邮件

importsmtplibfromemail.mime.textimportMIMETextfromemail.headerimportHeader# --- 配置信息 ---mail_host="smtp.qq.com"# SMTP 服务器mail_port=465# SSL 端口mail_user="123456789@qq.com"# 你的邮箱账号mail_pass="xxxxxxxxxxxx"# 你的授权码 (不是密码!)sender="123456789@qq.com"# 发件人receivers=["friend@example.com"]# 收件人列表# --- 1. 构建邮件内容 ---# MIMEText(内容, 类型, 编码)message=MIMEText("你好!这是我用 Python 发送的第一封邮件。","plain","utf-8")message['From']=Header("Python助手",'utf-8')# 发件人昵称message['To']=Header("亲爱的朋友",'utf-8')# 收件人昵称message['Subject']=Header("Python 邮件测试",'utf-8')# 邮件标题# --- 2. 发送邮件 ---try:# 使用 SSL 加密连接 (推荐)smtp_obj=smtplib.SMTP_SSL(mail_host,mail_port)# 登录smtp_obj.login(mail_user,mail_pass)# 发送smtp_obj.sendmail(sender,receivers,message.as_string())print("邮件发送成功!")smtp_obj.quit()# 退出exceptsmtplib.SMTPExceptionase:print(f"邮件发送失败:{e}")

四、发送 HTML 格式邮件

纯文本太丑了,没法加粗、变色或插图。我们可以发送HTML格式的邮件。
只需要将MIMEText的第二个参数从"plain"改为"html"

html_content=""" <h1>每日数据报告</h1> <p>亲爱的用户:</p> <p>今天的任务 <span style="color:green; font-weight:bold;">执行成功</span>。</p> <table border="1"> <tr> <th>项目</th> <th>数值</th> </tr> <tr> <td>新增用户</td> <td>1024</td> </tr> </table> <p><a href="https://www.python.org">点击查看详情</a></p> """message=MIMEText(html_content,"html","utf-8")message['Subject']=Header("今日日报 (HTML版)",'utf-8')# ... 发送逻辑同上 ...

五、发送带附件的邮件

附件稍微复杂一点,需要创建一个MIMEMultipart对象(像一个大包裹),然后把正文(MIMEText)和附件(MIMEApplication)都塞进去。

importsmtplibfromemail.mime.textimportMIMETextfromemail.mime.multipartimportMIMEMultipartfromemail.mime.applicationimportMIMEApplication# 专门处理文件fromemail.headerimportHeaderdefsend_email_with_attachment():# ... 配置信息 (同上) ...# 1. 创建一个带附件的实例message=MIMEMultipart()message['From']=Header("Python助手",'utf-8')message['To']=Header("Boss",'utf-8')message['Subject']=Header("附带报表文件",'utf-8')# 2. 添加正文message.attach(MIMEText("附件是今天的销售报表,请查收。","plain","utf-8"))# 3. 添加附件file_path="report.xlsx"# 假设本地有这个文件try:withopen(file_path,"rb")asf:# 读取文件内容part=MIMEApplication(f.read())# 添加头信息,设置文件名part.add_header('Content-Disposition','attachment',filename="report.xlsx")# 将附件添加到邮件中message.attach(part)exceptFileNotFoundError:print("附件文件未找到!")return# 4. 发送try:server=smtplib.SMTP_SSL(mail_host,mail_port)server.login(mail_user,mail_pass)server.sendmail(sender,receivers,message.as_string())server.quit()print("带附件邮件发送成功!")exceptExceptionase:print(f"发送失败:{e}")

六、封装:EmailSender 类

为了在以后的项目中方便复用,我们把这些逻辑封装成一个类。

classEmailSender:def__init__(self,host,user,password,port=465):self.host=host self.user=user self.password=password self.port=portdefsend(self,to_list,subject,content,files=None):""" :param to_list: 收件人列表 ["a@qq.com", "b@163.com"] :param subject: 标题 :param content: 正文 (支持HTML) :param files: 附件路径列表 ["a.jpg", "b.xlsx"] """message=MIMEMultipart()message['From']=Header(self.user)message['To']=Header(",".join(to_list))message['Subject']=Header(subject,'utf-8')# 添加正文message.attach(MIMEText(content,'html','utf-8'))# 添加附件iffiles:forfile_pathinfiles:try:withopen(file_path,"rb")asf:part=MIMEApplication(f.read())filename=file_path.split("/")[-1]# 获取文件名part.add_header('Content-Disposition','attachment',filename=filename)message.attach(part)exceptExceptionase:print(f"附件{file_path}加载失败:{e}")# 发送try:server=smtplib.SMTP_SSL(self.host,self.port)server.login(self.user,self.password)server.sendmail(self.user,to_list,message.as_string())server.quit()returnTrueexceptExceptionase:print(f"发送出错:{e}")returnFalse# 使用示例# sender = EmailSender("smtp.qq.com", "my@qq.com", "auth_code")# sender.send(["boss@qq.com"], "测试", "<h1>Hello</h1>", ["data.xlsx"])

七、常见问题

Q1:报错535 Login Fail. Please enter your authorization code

这是最常见的错误。你用了邮箱登录密码,或者授权码过期了。请去邮箱设置里重新生成一个授权码

Q2:报错ConnectionRefusedError(端口问题)

  • 默认端口 25 经常被云服务器厂商(如阿里云、腾讯云)封禁,防止垃圾邮件。
  • 解决方法:始终使用SMTP_SSL465端口。

Q3:邮件被识别为垃圾邮件?

  • 标题不要太短或包含敏感词。
  • 不要只发一个链接或图片,多写点正文。
  • 不要频繁给同一个邮箱发同样的测试邮件。

八、小结

邮件发送

配置 SMTP

构建邮件

发送过程

开启服务 (POP3/SMTP)

获取授权码 (非密码)

服务器地址 (smtp.qq.com)

MIMEText (纯文本/HTML)

MIMEMultipart (混合)

MIMEApplication (附件)

conn = SMTP_SSL(host, 465)

conn.login(user, code)

conn.sendmail(...)

关键要点

  1. 授权码是关键,千万别用密码。
  2. MIMEMultipart是容器,文本和附件往里塞。
  3. 推荐封装成类,以后只要一行代码就能发邮件。

九、课后作业

  1. 每日天气推送:结合 Requests (Day 27) 获取天气 API,Schedule (Day 41) 定时任务,每天早上 8 点给自己发一封带有今天天气预报的邮件。
  2. 爬虫监控:编写一个脚本监控某个网页(如商品价格),当价格低于预期时,自动发送邮件报警。
  3. 群发工资条 (挑战):读取一个 Excel 表格(包含:姓名、邮箱、工资),遍历表格,给每个人发送一封属于他自己的工资条邮件。

下节预告

Day 44:操作 PDF (PyPDF2)- Word 和 Excel 我们都搞定了,怎么能少了 PDF?明天我们学习如何用 Python 合并、拆分 PDF,甚至提取里面的文字。


系列导航

  • 上一篇:Day 42 - 图像处理Pillow
  • 下一篇:Day 44 - 操作PDFPyPDF2(待更新)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/3 7:33:45

Day 50:【99天精通Python】数据可视化 Matplotlib 基础 - 绘图入门

Day 50&#xff1a;【99天精通Python】数据可视化 Matplotlib 基础 - 绘图入门 前言 欢迎来到第50天&#xff01; “一图胜千言”。在数据分析中&#xff0c;无论你的数据处理得多完美&#xff0c;如果不能用直观的图表展示出来&#xff0c;老板和客户是看不懂的。 Matplotlib …

作者头像 李华
网站建设 2026/4/13 12:57:41

请求成功率,才是容易被忽略的核心指标

如果你做过新闻采集&#xff0c;大概率遇到过这样的场景&#xff1a; 代理买了不少并发开得也不低日志里请求数量看起来很“健康”但真正入库的新闻数据却少得可怜 很多人第一反应是&#xff1a; 是不是新闻站点反爬太狠了&#xff1f; 但在实际工程里&#xff0c;真正的问题…

作者头像 李华
网站建设 2026/4/13 0:07:24

[spring cloud] nacos注册中心和配置中心

1. Nacos 作为服务注册中心 (Service Registry) 1.1 核心原理 Nacos 作为注册中心&#xff0c;主要维护一张“服务列表”。 服务注册 (Registration): 服务提供者&#xff08;Provider&#xff09;启动时&#xff0c;会通过 REST API 发送请求向 Nacos Server 注册自己的信息&a…

作者头像 李华
网站建设 2026/4/1 3:26:29

Qwen3-Embedding-0.6B产品创新:用户反馈语义分析驱动迭代

Qwen3-Embedding-0.6B产品创新&#xff1a;用户反馈语义分析驱动迭代 1. 背景与技术演进 随着大模型在搜索、推荐、内容理解等场景的广泛应用&#xff0c;高质量文本嵌入&#xff08;Text Embedding&#xff09;能力成为构建智能系统的核心基础。传统的通用语言模型虽具备一定…

作者头像 李华
网站建设 2026/3/21 7:56:54

基于Keil uVision5的电机控制程序设计:完整指南

基于Keil uVision5的电机控制程序设计&#xff1a;从零构建高效实时系统你有没有遇到过这样的场景&#xff1f;电机嗡嗡作响&#xff0c;转速不稳&#xff0c;电流波形像心电图一样跳动——而你盯着示波器和代码&#xff0c;却找不到问题出在哪里。在嵌入式电机控制开发中&…

作者头像 李华
网站建设 2026/4/10 1:03:47

fft npainting lama实战教程:分区域修复复杂图像的策略

fft npainting lama实战教程&#xff1a;分区域修复复杂图像的策略 1. 学习目标与前置知识 本文旨在为开发者和图像处理爱好者提供一份完整的 fft npainting lama 图像修复系统 实战指南。通过本教程&#xff0c;您将掌握&#xff1a; 如何部署并启动基于 fft npainting lam…

作者头像 李华