开发者

Python3实现SMTP发送邮件的实战指南

开发者 https://www.devze.com 2025-10-28 09:24 出处:网络 作者: xcLeigh
目录一、SMTP 协议与 python 相关库介绍1.1 什么是 SMTP 协议?1.2 Python 核心库说明二、Python 发送邮件的核心语法2.1 创建 SMTP 对象2.2 发送邮件的 sendmail 方法三、实战:四种常见邮件类型的发送实现
目录
  • 一、SMTP 协议与 python 相关库介绍
    • 1.1 什么是 SMTP 协议?
    • 1.2 Python 核心库说明
  • 二、Python 发送邮件的核心语法
    • 2.1 创建 SMTP 对象
    • 2.2 发送邮件的 sendmail 方法
  • 三、实战:四种常见邮件类型的发送实现
    • 3.1 案例 1:发送纯文本邮件
      • 代码实现
      • 运行说明
    • 3.2 案例 2:发送 html 格式邮件
      • 代码实现
      • 效果说明
    • 3.3 案例 3:发送带附件的邮件
      • 代码实现
      • 注意事项
    • 3.4 案例 4:HTML 正文中嵌入图片
      • 代码实现
      • 效果说明
    • 3.5 案例 5:使用第三方 SMTP 服务(QQ 邮箱为例)
      • 准备工作:获取 QQ 邮箱授权码
      • QQ 邮箱 SMTP 配置信息
      • 代码实现(QQ 邮箱发送纯文本邮件)
      • 扩展说明
  • 四、常见问题与解决方案
    • 五、总结与扩展学习

      在日常开发和工作中,我们经常需要实现自动发送邮件的功能,比如监控告警通知、数据报表推送、用户注册验证等。Python 中编程的 smtplib 库和 email 库为我们提供了便捷的 SMTP 邮件发送解决方案,本文将从基础概念出发,逐步讲解如何用 Python3 实现纯文本邮件、HTML 格式邮件、带附件邮件以及嵌入图片的邮件发送,最后还会介绍如何使用第三方 SMTP 服务(以 QQ 邮箱为例)实现跨环境邮件发送,适合零基础开发者学习和实战。

      一、SMTP 协议与 Python 相关库介绍

      在开始代码实战前,我们先了解两个核心知识点:SMTP 协议和 Python 中用于发送邮件的库。

      1.1 什么是 SMTP 协议?

      SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)是一组用于将邮件从源地址传输到目的地址的规则,它定义了邮件服务器之间如何通信,以及如何控制邮件的中转方式。我们日常发送邮件,本质上就是通过 SMTP 协议与邮件服务器交互,完成邮件的投递。

      1.2 Python 核心库说明

      Python 内置了两个关键库,无需额外安装即可使用:

      • smtplib:对 SMTP 协议进行封装,提供了建立 SMTP 连接、登录服务器、发送邮件等核心功能。
      • email:用于构造邮件内容,包括邮件头(发件人、收件人、主题)、邮件正文(纯文本/HTML)、附件、图片等,解决了邮件格式符合 SMTP 协议规范的问题(避免因格式错误导致邮件发送失败或乱码)。

      二、Python 发送邮件的核心语法

      在实现具体功能前,我们先掌握 smtplib 库的核心对象和方法,这是后续所有实战的基础。

      2.1 创建 SMTP 对象

      要发送邮件,首先需要创建 smtplib.SMTP 对象,用于与 SMTP 服务器建立连接。其语法如下:

      import smtplib
      # 语法格式
      smtpObj = smtplib.SMTP([host [, port [, local_hostname]]])
      

      参数说明:

      • host(可选):SMTP 服务器主机地址,可填 IP 或域名(如 QQ 邮箱的 smtp.qq.com)。
      • port(可选):SMTP 服务器端口号,默认端口为 25(非加密),SSL 加密端口通常为 465 或 587(如 QQ 邮箱用 465)。
      • local_hostname(可选):若 SMTP 服务器在本机,可指定为 localhost

      2.2 发送邮件的 sendmail 方法

      创建 SMTP 对象后,通过 sendmail 方法发送邮件,语法如下:

      smtpObj.sendmail(from编程客栈_addr, to_addrs, msg[, mail_options, rcpt_options])
      

      参数说明:

      • from_addr:发件人邮箱地址(如 xxx@qq.com)。
      • to_addrs:收件人邮箱地址列表(即使只有一个收件人,也需用列表格式,如 ['yyy@163.com'])。
      • msg:邮件内容字符串,必须符合 SMTP 协议格式(需包含 FromToSubject 等头部信息,以及正文/附件)。

      三、实战:四种常见邮件类型的发送实现

      接下来,我们通过四个实战案例,逐步掌握不同类型邮件的发送方法,所有代码均可直接修改后运行。

      3.1 案例 1:发送纯文本邮件

      纯文本邮件是最基础的类型,仅包含文字内容,适合简单通知。

      代码实现

      #!/usr/bin/python3
      import smtplib
      from email.mime.text import MIMEText
      from email.header import Header
      
      # 1. 配置邮件基本信息
      sender = 'xcSharp@126.com'  # 发件人邮箱
      receivers = ['xcLeigh@126.com']  # 收件人邮箱列表(可多个)
      
      # 2. 构造邮件正文(三个参数:文本内容、格式(plain=纯文本)、编码)
      message = MIMEText('Python 邮件发送测试...这是纯文本内容', 'plain', 'utf-8')
      
      # 3. 设置邮件头部信息(发件人昵称、收件人昵称、邮件主题)
      message['From'] = Header("xcSharp", 'utf-8')  # 发件人显示的昵称
      message['To'] = Header("xcLeigh", 'utf-8')    # 收件人显示的昵称
      message['Subject'] = Header('Python SMTP 纯文本邮件测试', 'utf-8')  # 邮件主题
      
      # 4. 连接编程客栈 SMTP 服务器并发送邮件
      try:
          # 若使用本机 SMTP 服务器(如已安装 sendmail),直接连接 localhost
          smtpObj = smtplib.SMTP('localhost')
          # 发送邮件(发件人、收件人、邮件内容字符串)
          smtpObj.sendmail(sender, receivers, message.as_string())
          print("纯文本邮件发送成功")
      except smtplib.SMTPException:
          print("Error: 无法发送纯文本邮件")
      

      运行说明

      • 若本机已安装 sendmail 服务(如 linux 系统),直接运行代码即可发送成功。
      • 若本机无 sendmail,可跳过此案例,直接学习 3.5 节(第三方 SMTP 服务)

      3.2 案例 2:发送 HTML 格式邮件

      HTML 格式邮件支持富文本(如链接、表格、样式),适合展示复杂内容(如数据报表、活动通知)。其核心是将 MIMEText 的 _subtype 参数设为 html

      代码实现

      #!/usr/bin/python3
      import smtplib
      from email.mime.text import MIMEText
      from email.header import Header
      
      sender = 'from@runoob.com'
      receivers = ['429240967@qq.com']
      
      # 1. 构造 HTML 格式的邮件正文
      mail_msg = """
      <p>Python 邮件发送测试...</p>
      <p>这是 HTML 格式 的邮件,支持富文本:</p>
      <p>1. 点击访问 <a href="http://www.runoob.com" rel="external nofollow" >菜鸟教程</a></p>
      <p>2. 以下是表格示例:</p>
      <table border="1">
        <tr><th>姓名</th><th>年龄</th></tr>
        <tr><td>张三</td><td>25</td></tr>
        <tr><td>李四</td><td>30</td></tr>
      </table>
      """
      
      # 2. 构造邮件(subtype 设为 html,表明是 HTML 格式)
      message = MIMEText(mail_msg, 'html', 'utf-8')
      message['From'] = Header("菜鸟教程", 'utf-8')
      message['To'] = Header("测试用户", 'utf-8')
      message['Subject'] = Header('Python SMTP HTML 邮件测试', 'utf-8')
      
      # 3. 发送邮件
      try:
          smtpObj = smtplib.SMTP('localhost')
          smtpObj.sendmail(sender, receivers, message.as_string())
          print("HTML 邮件发送成功")
      except smtplib.SMTPException:
          print("Error: 无法发送 HTML 邮件")
      

      效果说明

      发送成功后,收件人邮箱中会显示带链接、表格的富文本内容,而非纯文字。

      3.3 案例 3:发送带附件的邮件

      工作中常需发送带附件的邮件(如日志文件、Excel 报表),核心是使用 MIMEMultipart 类组合“正文 + 附件”。

      代码实现

      #!/usr/bin/python3
      import smtplib
      from email.mime.text import MIMEText
      from email.mime.multipart import MIMEMultipart
      from email.header import Header
      
      sender = 'from@runoob.com'
      receivers = ['429240967@qq.com']
      
      # 1. 创建带附件的邮件实例(MIMEMultipart 用于组合多部分内容)
      message = MIMEMultipart()
      message['From'] = Header("菜鸟教程", 'utf-8')
      message['To'] = Header("测试用户", 'utf-8')
      message['Subject'] = Header('Python SMTP 带附件邮件测试', 'utf-8')
      
      # 2. 添加邮件正文(纯文本或 HTML 均可)
      message.attach(MIMEText('这是带附件的邮件正文...', 'plain', 'utf-8'))
      
      # 3. 构造附件 1(传送当前目录下的 test.txt 文件)
      # 读取文件内容,用 base64 编码(确保二进制文件传输不损坏)
      att1 = MIMEText(open('test.txt', 'rb').read(), 'base64', 'utf-8')
      att1["Content-Type"] = 'application/octet-stream'  # 声明附件类型
      # 设置附件显示名称(filename 为邮件中显示的文件名,可自定义)
      att1["Content-Disposition"] = 'attachment; filename="test.txt"'
      message.attach(att1)  # 将附件添加到邮件
      
      # 4. 构造附件 2(传送 runoob.txt 文件,方法同上)
      att2 = MIMEText(open('runoob.txt', 'rb')python.read(), 'base64', 'utf-8')
      att2["Content-Type"] = 'application/octet-stream'
      att2["Content-Disposition"] = 'attachment; filename="runoob.txt"'
      message.attach(att2)
      
      # 5. 发送邮件
      try:
          smtpObj = smtplib.SMTP('localhost')
          smtpObj.sendmail(sender, receivers, message.as_string())
          print("带附件邮件发送成功")
      except smtplib.SMTPException:
       编程客栈   print("Error: 无法发送带附件邮件")
      

      注意事项

      • 确保附件文件(如 test.txt)在代码运行的当前目录下,否则需指定完整路径(如 C:/files/test.txt)。
      • 附件支持任意格式(如 xlsxpdfzip),只需修改文件名和路径即可。

      3.4 案例 4:HTML 正文中嵌入图片

      若想在 HTML 邮件中直接显示图片(而非作为附件),需将图片以“内嵌资源”的方式添加,核心是通过 Content-ID 关联 HTML 中的图片引用。

      代码实现

      #!/usr/bin/python3
      import smtplib
      from email.mime.image import MIMEImage
      from email.mime.multipart import MIMEMultipart
      from email.mime.text import MIMEText
      from email.header import Header
      
      sender = 'from@runoob.com'
      receivers = ['429240967@qq.com']
      
      # 1. 创建关联型邮件实例(related 表示内容间有关联,如图片引用)
      msgRoot = MIMEMultipart('related')
      msgRoot['From'] = Header("菜鸟教程", 'utf-8')
      msgRoot['To'] = Header("测试用户", 'utf-8')
      msgRoot['Subject'] = Header('Python SMTP 内嵌图片邮件测试', 'utf-8')
      
      # 2. 创建备选内容容器(兼容不支持 HTML 的邮件客户端)
      msgAlternative = MIMEMultipart('alternative')
      msgRoot.attach(msgAlternative)
      
      # 3. 构造 HTML 正文(通过 cid:image1 引用图片,与后续图片的 Content-ID 对应)
      mail_msg = """
      <p>Python 邮件发送测试...</p>
      <p>这是内嵌图片的 HTML 邮件:</p>
      <p><img src="cid:image1"></p>  <!-- 引用图片 ID 为 image1 -->
      """
      msgAlternative.attach(MIMEText(mail_msg, 'html', 'utf-8'))
      
      # 4. 读取图片并添加为内嵌资源
      fp = open('test.png', 'rb')  # 读取当前目录下的 test.png 图片
      msgImage = MIMEImage(fp.read())
      fp.close()
      
      # 5. 设置图片的 Content-ID(需与 HTML 中的 cid 一致)
      msgImage.add_header('Content-ID', '<image1>')
      msgRoot.attach(msgImage)
      
      # 6. 发送邮件
      try:
          smtpObj = smtplib.SMTP('localhost')
          smtpObj.sendmail(sender, receivers, msgRoot.as_string())
          print("内嵌图片邮件发送成功")
      except smtplib.SMTPException:
          print("Error: 无法发送内嵌图片邮件")
      

      效果说明

      发送成功后,图片会直接显示在邮件正文中,而非作为附件下载(部分邮箱可能需要将邮件从垃圾箱移到收件箱才能正常显示图片)。

      3.5 案例 5:使用第三方 SMTP 服务(QQ 邮箱为例)

      前面的案例依赖本机 sendmail 服务,实际开发中更常用 第三方 SMTP 服务(如 QQ 邮箱、网易邮箱、企业邮箱),支持跨环境发送(Windows、MAC、Linux 通用)。

      以 QQ 邮箱为例,需先完成两步准备工作:

      准备工作:获取 QQ 邮箱授权码

      QQ 邮箱不允许直接使用登录密码作为 SMTP 密码,需生成“授权码”(用于第三方应用登录):

      1. 登录 QQ 邮箱,进入 设置 → 账户
      2. 找到“POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 服务”,开启“IMAP/SMTP 服务”。
      3. 按照提示发送短信验证,验证后会生成 16 位授权码,保存该授权码(后续代码中用)。

      QQ 邮箱 SMTP 配置信息

      • SMTP 服务器地址:smtp.qq.com
      • SSL 加密端口:465(推荐使用 SSL 加密,更安全)

      代码实现(QQ 邮箱发送纯文本邮件)

      #!/usr/bin/python3
      import smtplib
      from email.mime.text import MIMEText
      from email.utils import formataddr
      
      # 1. 配置 QQ 邮箱信息(需替换为自己的信息)
      my_sender = '123456@qq.com'    # 发件人 QQ 邮箱账号
      my_pass = 'abcdefghijklmnop'   # 发件人邮箱授权码(不是登录密码!)
      my_user = '654321@qq.com'      # 收件人邮箱账号(可发给自己测试)
      
      def send_qq_mail():
          ret = True  # 标记邮件是否发送成功
          try:
              # 2. 构造纯文本邮件正文
              msg = MIMEText('这是用 QQ 邮箱 SMTP 发送的测试邮件', 'plain', 'utf-8')
              
              # 3. 设置邮件头部(formataddr 避免中文乱码)
              # 格式:(昵称, 邮箱账号)
              msg['From'] = formataddr(["我的 QQ 邮箱", my_sender])
              msg['To'] = formataddr(["测试收件人", my_user])
              msg['Subject'] = "Python SMTP QQ 邮箱测试"  # 邮件主题
      
              # 4. 连接 QQ 邮箱 SMTP 服务器(SSL 加密)
              # 注意:使用 SMTP_SSL 而非 SMTP,端口为 465
              server = smtplib.SMTP_SSL("smtp.qq.com", 465)
              server.login(my_sender, my_pass)  # 登录 SMTP 服务器
              
              # 5. 发送邮件(收件人列表需用列表格式)
              server.sendmail(my_sender, [my_user,], msg.as_string())
              
              # 6. 关闭连接
              server.quit()
          except Exception as e:
              print(f"发送失败原因:{e}")
              ret = False
          return ret
      
      # 调用函数发送邮件
      ret = send_qq_mail()
      if ret:
          print("QQ 邮箱邮件发送成功")
      else:
          print("QQ 邮箱邮件发送失败")
      

      扩展说明

      • 若需发送 HTML 邮件、带附件邮件,只需将 3.2/3.3/3.4 节 中的“邮件构造逻辑”替换到本案例中即可。
      • 其他邮箱(如网易 163)的配置类似:网易 SMTP 服务器为 smtp.163.com,端口 465,同样需要开启 SMTP 服务并获取授权码。

      四、常见问题与解决方案

      在实战中可能遇到邮件发送失败的问题,以下是高频问题及解决方法:

      问题现象可能原因解决方案
      报错 smtplib.SMTPAuthenticationError1. 授权码错误

      2. 未开启 SMTP 服务

      1. 重新生成 QQ/网易邮箱授权码(注意区分登录密码与授权码)

      2. 登录邮箱进入“设置-账户”,开启 IMAP/SMTP 服务

      邮件发送成功但收件箱未收到1. 邮件被判定为垃圾邮件

      2. 收件人邮箱地址错误

      1. 检查垃圾箱,将发件人添加到联系人白名单

      2. 核对 receivers 列表中的邮箱地址,确保无拼写错误

      报错 smtplib.SMTPConnectError1. SMTP 服务器地址或端口错误

      2. 本地网络防火墙拦截端口

      1. 确认第三方邮箱 SMTP 地址(如 QQ 是 smtp.qq.com)和端口(465 用于 SSL)

      2. 临时关闭防火墙,或在防火墙设置中允许 Python 程序访问网络

      HTML 邮件乱码或图片不显示1. 编码未设置为 utf-8

      2. HTML 中图片 cid 与 Content-ID 不匹配

      1. 构造 MIMEText 时确保编码参数为 utf-8

      2. 检查图片 Content-ID 与 HTML 中 src="cid:xxx" 的值完全一致(包括尖括号,如 <image1>

      五、总结与扩展学习

      通过本文的学习,我们已经掌握了 Python3 发送各类 SMTP 邮件的核心方法,从基础的纯文本邮件到复杂的带附件、内嵌图片邮件,再到跨环境的第三方 SMTP 服务调用,基本能覆盖日常开发中自动发送邮件的需求,如服务器监控告警、定时数据报表推送、用户注册验证码发送等场景。

      若需进一步拓展功能,可参考以下方向:

      1. 定时发送邮件:结合 schedule 库或 APScheduler 库,实现每天/每周定时发送邮件(如周报自动推送)。
      2. 批量发送个性化邮件:读取 Excel/CSV 中的收件人信息和个性化内容(如姓名、订单号),循环生成并发送邮件。
      3. 添加邮件抄送/密送:在 sendmail 方法的 to_addrs 列表中添加抄送(CC)或密送(BCC)地址,同时在邮件头部通过 message['Cc']/message['Bcc'] 设置显示名称。
      4. 更复杂的邮件格式:使用 email.mime.application 类发送 PDF、Excel 等特殊格式附件,或通过 email.mime.multipart 组合纯文本+HTML 双版本正文(兼容不同邮件客户端)。

      以上就是Python3实现SMTP发送邮件的实战指南的详细内容,更多关于Python3 SMTP发送邮件的资料请关注编程客栈(www.devze.com)其它相关文章!

      0

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      关注公众号