PythonSMTP发邮件实战教程
想要掌握Python邮件发送?本文为你提供一份详尽的实战教程,深入解析如何使用Python的smtplib和email模块,轻松实现邮件发送功能。我们不仅会教你如何处理邮件内容的编码问题,避免乱码,还会详细讲解如何添加附件,让你的邮件更加丰富多彩。此外,本文还总结了常见的邮件发送失败原因,例如认证失败、连接失败以及收件人被拒绝等,并提供相应的排查建议和解决方案。通过本文,你将学会如何构建稳定可靠的Python邮件发送系统,或者你还可以选择使用更高级的第三方邮件发送服务提供商的API,它们提供了更高级、更稳定的邮件发送解决方案,例如SendGrid、Mailgun、AWS SES (Simple Mail Service)、阿里云邮件推送等。
Python发送邮件时处理编码和附件需使用email模块。1. 对于文本或HTML内容,使用MIMEText类并指定字符集(如utf-8),确保正确编码避免乱码;2. 附件处理需构建MIMEMultipart容器,每个附件作为MIMEBase对象,经Base64编码并添加Content-Disposition头指定文件名。常见发送失败原因包括:1. 认证失败,需使用授权码而非登录密码,并确认SMTP服务已开启;2. 连接失败,检查服务器地址、端口及网络状况,确保SSL/TLS配置正确;3. 收件人被拒绝,确认收件地址有效且未被服务器拦截。此外,可通过开启调试模式、手动测试及查看异常信息辅助排查问题。
Python发送邮件主要依赖其内置的smtplib
和email
模块。smtplib
负责实际的SMTP(Simple Mail Transfer Protocol)连接和邮件发送,而email
模块则帮助我们构建符合MIME标准的邮件内容,比如添加附件、设置HTML格式等。这套组合拳用起来效率很高,但要真正做到稳定可靠地发送,有些坑点是需要提前了解的。

解决方案
import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email import encoders import os def send_email_via_smtp(sender_email, sender_password, receiver_email, subject, body, smtp_server, smtp_port, is_html=False, attachments=None): """ 通过SMTP协议发送邮件。 Args: sender_email (str): 发件人邮箱地址。 sender_password (str): 发件人邮箱密码或授权码。 receiver_email (str): 收件人邮箱地址。 subject (str): 邮件主题。 body (str): 邮件正文。 smtp_server (str): SMTP服务器地址。 smtp_port (int): SMTP服务器端口(通常是465或587)。 is_html (bool): 正文是否为HTML格式。 attachments (list): 附件文件路径列表。 """ try: # 构建邮件内容 if attachments: msg = MIMEMultipart() else: msg = MIMEText(body, 'html' if is_html else 'plain', 'utf-8') msg['From'] = sender_email msg['To'] = receiver_email msg['Subject'] = subject if attachments: msg.attach(MIMEText(body, 'html' if is_html else 'plain', 'utf-8')) for filepath in attachments: if not os.path.exists(filepath): print(f"警告:附件文件不存在 - {filepath}") continue part = MIMEBase('application', 'octet-stream') with open(filepath, 'rb') as file: part.set_payload(file.read()) encoders.encode_base64(part) part.add_header('Content-Disposition', f'attachment; filename="{os.path.basename(filepath)}"') msg.attach(part) # 连接SMTP服务器并发送邮件 print(f"尝试连接SMTP服务器: {smtp_server}:{smtp_port}") server = None if smtp_port == 465: # SSL加密 server = smtplib.SMTP_SSL(smtp_server, smtp_port) elif smtp_port == 587: # TLS加密 server = smtplib.SMTP(smtp_server, smtp_port) server.starttls() # 启动TLS加密 else: raise ValueError("不支持的SMTP端口,请使用465 (SSL) 或 587 (TLS)。") # server.set_debuglevel(1) # 调试模式,会打印详细的SMTP交互日志 server.login(sender_email, sender_password) server.sendmail(sender_email, receiver_email, msg.as_string()) server.quit() print("邮件发送成功!") except smtplib.SMTPAuthenticationError as e: print(f"SMTP认证失败:请检查邮箱地址或授权码是否正确。错误信息:{e}") print("提示:部分邮箱服务(如QQ、163)需要开启SMTP服务并使用授权码而非登录密码。") except smtplib.SMTPConnectError as e: print(f"SMTP连接失败:请检查SMTP服务器地址和端口是否正确,或网络是否存在问题。错误信息:{e}") except smtplib.SMTPRecipientsRefused as e: print(f"收件人被拒绝:可能收件人地址无效或服务器拒绝接收。错误信息:{e.recipients}") except Exception as e: print(f"发送邮件时发生未知错误:{e}") # 示例用法 (请替换为您的实际信息) if __name__ == "__main__": SENDER_EMAIL = "your_email@example.com" # 你的邮箱 SENDER_PASSWORD = "your_email_password_or_app_password" # 你的邮箱密码或授权码 RECEIVER_EMAIL = "recipient_email@example.com" # 收件人邮箱 SMTP_SERVER = "smtp.example.com" # 邮箱服务商的SMTP服务器地址,例如 'smtp.qq.com', 'smtp.163.com', 'smtp.gmail.com' SMTP_PORT = 465 # 或 587 # 简单文本邮件 print("\n--- 发送纯文本邮件 ---") send_email_via_smtp( sender_email=SENDER_EMAIL, sender_password=SENDER_PASSWORD, receiver_email=RECEIVER_EMAIL, subject="Python SMTP测试邮件 - 纯文本", body="这是一封由Python脚本发送的纯文本测试邮件。", smtp_server=SMTP_SERVER, smtp_port=SMTP_PORT ) # HTML格式邮件 print("\n--- 发送HTML格式邮件 ---") html_body = """ <html> <body> <p>你好,</p> <p>这是一封<b>HTML格式</b>的测试邮件,由Python脚本发送。</p> <p>你可以尝试点击这个链接:<a href="https://www.python.org">Python官网</a></p> <img src="https://www.python.org/static/community_logos/python-logo-only.png" alt="Python Logo" width="100"> <p>祝好!</p> </body> </html> """ send_email_via_smtp( sender_email=SENDER_EMAIL, sender_password=SENDER_PASSWORD, receiver_email=RECEIVER_EMAIL, subject="Python SMTP测试邮件 - HTML格式", body=html_body, smtp_server=SMTP_SERVER, smtp_port=SMTP_PORT, is_html=True ) # 带有附件的邮件 (请确保有这些文件在当前目录下,或者提供完整路径) # 比如创建一个名为 'test.txt' 和 'image.png' 的文件 # with open('test.txt', 'w') as f: # f.write("这是一个附件测试文件。") # from PIL import Image # img = Image.new('RGB', (60, 30), color = 'red') # img.save('image.png') print("\n--- 发送带附件的邮件 ---") # 假设 'test.txt' 和 'image.png' 存在于脚本同目录下 # 实际使用时,请替换为真实文件路径 test_attachments = ['test.txt', 'image.png'] # 确保这些文件存在 send_email_via_smtp( sender_email=SENDER_EMAIL, sender_password=SENDER_PASSWORD, receiver_email=RECEIVER_EMAIL, subject="Python SMTP测试邮件 - 带附件", body="这是一封带有附件的测试邮件,请查收!", smtp_server=SMTP_SERVER, smtp_port=SMTP_PORT, attachments=test_attachments )
如何处理邮件内容编码和附件?
说实话,邮件内容编码和附件这块,初次接触时确实会觉得有点绕,因为这涉及到MIME(Multipurpose Internet Mail Extensions)标准。简单来说,邮件不仅仅是纯文本,它可能包含各种字符集、HTML格式、图片、文档等等,MIME就是一套规则,告诉邮件客户端如何正确解析这些复杂的内容。
email
模块就是Python实现MIME标准的利器。对于纯文本或HTML,我们用MIMEText
类,它会自动处理编码问题,比如你指定'utf-8'
,它就会在邮件头里加上Content-Type: text/plain; charset="utf-8"
或者text/html; charset="utf-8"
。这很关键,否则收件人看到的可能就是乱码。

而附件,那更是MIME的拿手好戏。它需要将邮件拆分成多个“部分”(Part),用MIMEMultipart
来做这个容器。每个附件都是一个独立的MIMEBase
对象。比如,你要发一个PDF,你就得读取PDF文件的二进制内容,然后用encoders.encode_base64
进行Base64编码(因为邮件传输协议通常是基于文本的,二进制数据需要转换),最后加上Content-Disposition
头,告诉收件箱“这是一个附件,它的原始文件名是什么”。代码里我已经把这个逻辑封装进去了,MIMEMultipart
作为主容器,邮件正文和各个附件都是它的子部分。这样做,收件方就能清晰地看到邮件内容和可下载的附件了。
为什么我的邮件发送失败了?常见问题与排查
这大概是大家用Python发邮件最常遇到的问题了,我个人也踩过不少坑。遇到发送失败,别急着怀疑人生,通常是以下几个原因:

认证失败 (SMTPAuthenticationError):
- 密码错误? 检查你输入的密码是否正确。
- 授权码? 很多邮箱服务商(比如QQ邮箱、163邮箱、Gmail等)出于安全考虑,不再允许直接使用登录密码进行SMTP认证,而是需要你登录网页版邮箱,在设置里开启SMTP服务,然后生成一个“授权码”或“客户端专用密码”。这个授权码才是你在Python脚本里需要使用的密码。这个是最常见的坑,没有之一。
- 账户未开启SMTP服务? 同样,需要在邮箱设置里手动开启SMTP服务。
连接失败 (SMTPConnectError):
- 服务器地址或端口错误?
smtp.example.com
这样的地址和465/587这样的端口号,一定要和你的邮箱服务商提供的一致。比如Gmail是smtp.gmail.com
,QQ邮箱是smtp.qq.com
。 - 网络问题? 检查你的网络连接是否正常,防火墙是否阻止了Python程序访问外部SMTP端口。有时候公司内网会有严格的端口限制。
- SSL/TLS配置问题? 如果是465端口,通常是直接SSL连接 (
SMTP_SSL
);如果是587端口,则需要先建立普通连接,再调用starttls()
方法升级为TLS加密连接。端口和加密方式不匹配会导致连接失败。
- 服务器地址或端口错误?
收件人被拒绝 (SMTPRecipientsRefused):
- 收件人地址无效? 检查收件人邮箱地址是否拼写错误或不存在。
- 服务器拒绝? 有时发件服务器会拒绝向某些域名或地址发送邮件,可能是对方服务器的黑名单,或者你的邮件被判定为垃圾邮件特征。
排查建议:
- 开启调试模式:在
smtplib.SMTP
或smtplib.SMTP_SSL
对象创建后,调用server.set_debuglevel(1)
。这会打印出SMTP服务器和客户端之间的详细通信日志,你能清楚看到是哪个环节出了问题,比如认证失败的具体原因码。 - 手动测试:尝试使用邮件客户端(如Outlook、Thunderbird)配置相同的SMTP服务器、端口、邮箱和密码,看能否正常发送。如果客户端也无法发送,那问题多半出在邮箱设置或网络上。
- 查看错误信息:Python的异常信息通常很详细,比如
SMTPAuthenticationError
就明确告诉你认证出了问题。
除了SMTP,还有其他发送邮件的方式吗?
当然有,SMTP是底层协议,但很多时候我们并不需要直接去操作它。想象一下,你造房子不需要从挖矿炼铁开始,直接买钢筋水泥多方便。邮件发送也是类似。
现在非常流行的是使用第三方邮件发送服务提供商的API。这些服务商,比如SendGrid、Mailgun、AWS SES (Simple Email Service)、阿里云邮件推送等,它们提供了更高级、更稳定的邮件发送解决方案。
它们的优势在于:
- 简化开发:你不需要关心SMTP的细节,只需要调用它们提供的API(通常是RESTful API),传入发件人、收件人、主题、正文等参数即可。
- 高送达率:这些服务商有专业的团队来维护IP信誉,确保你的邮件能顺利进入收件箱,而不是被当成垃圾邮件。这对于批量发送、营销邮件尤其重要。
- 统计分析:它们通常提供邮件的发送状态、打开率、点击率、退订率等详细数据,方便你进行后续分析和优化。
- 弹性扩展:面对大量的邮件发送需求,这些服务可以轻松扩展,而你自己搭建的SMTP服务器可能很快就会遇到性能瓶颈。
- 处理复杂场景:比如邮件模板、批量发送、延时发送、Webhook通知等,这些都是它们服务的亮点。
虽然直接使用SMTP能让你对邮件发送过程有更深的理解和控制,但对于生产环境或有更高要求的场景,我个人更倾向于推荐使用这些专业的第三方服务。它们能让你把精力放在业务逻辑上,而不是邮件发送的各种技术细节和坑点上。
好了,本文到此结束,带大家了解了《PythonSMTP发邮件实战教程》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多文章知识!

- 上一篇
- JavaScript移除事件监听器方法详解

- 下一篇
- Deepseek满血版与GeniusAI解析全攻略
-
- 文章 · python教程 | 4分钟前 |
- Python多进程操作数据库详解
- 367浏览 收藏
-
- 文章 · python教程 | 13分钟前 | 代码可维护性 warnings模块 warnings.filterwarnings() 警告管理 PYTHONWARNINGS
- 关闭Pythonwarnings模块警告的几种方法
- 338浏览 收藏
-
- 文章 · python教程 | 16分钟前 | Python HTTP请求头 X-Forwarded-For 网络代理检测 误报处理
- Python实现网络代理检测方法详解
- 231浏览 收藏
-
- 文章 · python教程 | 26分钟前 |
- Python压缩zip文件教程详解
- 298浏览 收藏
-
- 文章 · python教程 | 33分钟前 |
- Python获取文件时间戳:os.stat()详解
- 271浏览 收藏
-
- 文章 · python教程 | 36分钟前 |
- Python循环修改列表常见问题及解决方法
- 117浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python中break的作用及用法详解
- 475浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Scrapy中间件开发:Python插件编写教程
- 489浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python地理数据处理:Geopandas入门教程
- 126浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python词云生成教程:实战指南
- 501浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 511次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 498次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 千音漫语
- 千音漫语,北京熠声科技倾力打造的智能声音创作助手,提供AI配音、音视频翻译、语音识别、声音克隆等强大功能,助力有声书制作、视频创作、教育培训等领域,官网:https://qianyin123.com
- 180次使用
-
- MiniWork
- MiniWork是一款智能高效的AI工具平台,专为提升工作与学习效率而设计。整合文本处理、图像生成、营销策划及运营管理等多元AI工具,提供精准智能解决方案,让复杂工作简单高效。
- 177次使用
-
- NoCode
- NoCode (nocode.cn)是领先的无代码开发平台,通过拖放、AI对话等简单操作,助您快速创建各类应用、网站与管理系统。无需编程知识,轻松实现个人生活、商业经营、企业管理多场景需求,大幅降低开发门槛,高效低成本。
- 180次使用
-
- 达医智影
- 达医智影,阿里巴巴达摩院医疗AI创新力作。全球率先利用平扫CT实现“一扫多筛”,仅一次CT扫描即可高效识别多种癌症、急症及慢病,为疾病早期发现提供智能、精准的AI影像早筛解决方案。
- 188次使用
-
- 智慧芽Eureka
- 智慧芽Eureka,专为技术创新打造的AI Agent平台。深度理解专利、研发、生物医药、材料、科创等复杂场景,通过专家级AI Agent精准执行任务,智能化工作流解放70%生产力,让您专注核心创新。
- 201次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览