news 2026/2/22 17:16:39

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/2/19 2:04:33

Day 47:【99天精通Python】NumPy 进阶 - 维度变换与布尔索引

Day 47&#xff1a;【99天精通Python】NumPy 进阶 - 维度变换与布尔索引 前言 欢迎来到第47天&#xff01; 在昨天&#xff0c;我们已经掌握了 NumPy 数组的创建和基础运算。今天我们将继续深入&#xff0c;学习两个非常强大的功能&#xff1a; 维度变换&#xff1a;把一维的 1…

作者头像 李华
网站建设 2026/2/21 13:14:25

SGLang路由组件怎么用?流量调度全解析

SGLang路由组件怎么用&#xff1f;流量调度全解析 1. 引言&#xff1a;SGLang中的流量调度挑战 随着大语言模型&#xff08;LLM&#xff09;在生产环境中的广泛应用&#xff0c;推理服务的性能、稳定性和成本控制成为核心关注点。传统的单体式推理架构已难以应对高并发、长上…

作者头像 李华
网站建设 2026/2/21 9:29:41

PyTorch-2.x部署答疑:常见GPU不可用问题解决方案

PyTorch-2.x部署答疑&#xff1a;常见GPU不可用问题解决方案 1. 引言 在深度学习开发过程中&#xff0c;PyTorch作为主流框架之一&#xff0c;其2.x版本带来了更高效的编译优化&#xff08;如torch.compile&#xff09;和对新硬件的更好支持。然而&#xff0c;在实际部署中&a…

作者头像 李华
网站建设 2026/2/20 22:45:25

智能搜索系统:bert-base-chinese语义理解

智能搜索系统&#xff1a;bert-base-chinese语义理解 1. 技术背景与核心价值 在现代自然语言处理&#xff08;NLP&#xff09;系统中&#xff0c;语义理解是实现智能搜索、问答系统和文本分类等高级功能的核心能力。传统关键词匹配方法难以捕捉用户查询的真实意图&#xff0c…

作者头像 李华
网站建设 2026/2/21 9:48:33

[spring cloud] OpenFeign远程调用

1. OpenFeign 核心原理 用一句话总结&#xff1a;OpenFeign 是一个声明式的 HTTP 客户端&#xff0c;通过动态代理将接口方法映射为 HTTP 请求。 它的核心工作流程如下&#xff1a; 启动扫描&#xff1a;Spring Boot 启动时&#xff0c;EnableFeignClients 注解会扫描所有标有…

作者头像 李华
网站建设 2026/2/21 15:44:41

Hunyuan模型性能监控:Prometheus+Grafana集成教程

Hunyuan模型性能监控&#xff1a;PrometheusGrafana集成教程 1. 引言 1.1 学习目标 本文将详细介绍如何为腾讯混元团队开发的 HY-MT1.5-1.8B 翻译模型构建一套完整的性能监控系统。通过集成 Prometheus 和 Grafana&#xff0c;您将能够实时采集、可视化并告警模型推理服务的…

作者头像 李华