Python利用SMTP发送邮件的常见问题与解决方案详解

 更新时间:2025年04月21日 08:12:24   作者:码农阿豪@新空间  
在自动化办公和系统开发中,邮件发送功能是常见的需求,本文将从实际案例出发,分析常见的SMTP错误,并提供完整的解决方案,希望对大家有一定的帮助

引言

在自动化办公和系统开发中,邮件发送功能是常见的需求。无论是发送通知、报告,还是传输文件,Python的smtplib和email库提供了便捷的实现方式。然而,在实际开发中,开发者常会遇到各种SMTP错误,如(-1, b'\x00\x00\x00')、AttributeError('characters_written')等,这些问题往往让人束手无策。

本文将从实际案例出发,分析常见的SMTP错误,并提供完整的解决方案,帮助开发者快速定位和解决问题。同时,我们还会优化代码,使其更健壮、更易于维护。

1. 问题背景

在Python中,使用smtplib发送邮件时,通常会遇到两类问题:

  • 连接与认证问题(如授权码错误、SMTP服务器拒绝连接)
  • 数据编码与协议问题(如SSL/TLS握手失败、附件编码错误)

以下是一个典型的邮件发送代码,它可能会触发上述错误:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import os
import logging

logger = logging.getLogger(__name__)

def send_email_with_attachment(filepath, receiver_email):
    sender_email = "your_email@qq.com"
    password = "your_authorization_code"  # QQ邮箱授权码
    smtp_server = "smtp.qq.com"
    smtp_port = 465  # QQ邮箱SSL端口

    msg = MIMEMultipart()
    msg['From'] = sender_email
    msg['To'] = receiver_email
    msg['Subject'] = "文件处理结果通知"

    # 邮件正文
    msg.attach(MIMEText("请查收附件", 'plain'))

    # 添加附件
    try:
        with open(filepath, "rb") as f:
            part = MIMEApplication(f.read(), Name=os.path.basename(filepath))
            part['Content-Disposition'] = f'attachment; filename="{os.path.basename(filepath)}"'
            msg.attach(part)
    except FileNotFoundError:
        logger.error("附件文件不存在")
        return False

    # 发送邮件
    try:
        with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
            server.login(sender_email, password)
            server.sendmail(sender_email, receiver_email, msg.as_string())
        return True
    except Exception as e:
        logger.error(f"发送邮件失败: {e}", exc_info=True)
        return False

运行此代码时,可能会遇到以下错误:

2. 常见错误及解决方案

错误1:SMTPResponseException: (-1, b'\x00\x00\x00')

错误原因

  • 授权码错误或已过期。
  • SMTP服务器(如QQ邮箱)检测到异常登录,拒绝连接。
  • 网络或防火墙拦截了SMTP请求。

解决方案

1.检查授权码

登录QQ邮箱 → 设置 → 账户 → 生成新的授权码,并替换代码中的password。

2.更换SMTP端口(推荐使用587+TLS)

QQ邮箱支持465(SSL)和587(TLS),后者更稳定:

smtp_port = 587  # 改用TLS端口
with smtplib.SMTP(smtp_server, smtp_port) as server:
    server.starttls()  # 启用TLS加密
    server.login(sender_email, password)

3.检查网络环境

关闭防火墙或切换网络(如使用手机热点测试)。

错误2:AttributeError('characters_written')

错误原因

  • Python 3.10+ 与 SMTP_SSL 的兼容性问题。
  • SSL/TLS握手失败,可能是由于OpenSSL版本不匹配。

解决方案

1.改用starttls()(推荐)

避免使用SMTP_SSL,改用SMTP + starttls():

with smtplib.SMTP(smtp_server, 587) as server:
    server.starttls()  # 显式启用TLS
    server.login(sender_email, password)

2.降级Python或升级依赖库

如果仍报错,尝试降级到Python 3.9,或更新pyopenssl:

pip install --upgrade pyopenssl

3. 优化后的邮件发送代码

结合上述解决方案,优化后的代码如下:

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import os
import logging
import base64

logger = logging.getLogger(__name__)

def send_email_with_attachment(filepath, receiver_email):
    """发送带附件的邮件(支持QQ邮箱)"""
    sender_email = "your_email@qq.com"
    password = "your_authorization_code"  # 替换为最新授权码
    smtp_server = "smtp.qq.com"
    smtp_port = 587  # 使用TLS端口

    # 检查附件是否存在
    if not os.path.exists(filepath):
        logger.error(f"附件文件不存在: {filepath}")
        return False

    # 创建邮件内容
    msg = MIMEMultipart()
    msg['From'] = sender_email
    msg['To'] = receiver_email
    msg['Subject'] = "文件处理结果通知"
    msg.attach(MIMEText("请查收附件", 'plain'))

    # 添加附件
    try:
        with open(filepath, "rb") as f:
            part = MIMEApplication(f.read(), Name=os.path.basename(filepath))
            part['Content-Disposition'] = f'attachment; filename="{os.path.basename(filepath)}"'
            msg.attach(part)
    except Exception as e:
        logger.error(f"附件处理失败: {e}")
        return False

    # 发送邮件(使用TLS)
    try:
        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.starttls()  # 启用TLS加密
            server.login(sender_email, password)
            server.sendmail(sender_email, receiver_email, msg.as_string())
        logger.info("邮件发送成功")
        return True
    except smtplib.SMTPException as e:
        logger.error(f"SMTP错误: {e}")
    except Exception as e:
        logger.error(f"未知错误: {e}", exc_info=True)
    return False

优化点

1.更健壮的异常处理

区分SMTPException和其他异常,便于排查问题。

2.附件预检查

发送前验证附件是否存在。

3.日志记录

使用logging记录详细错误信息。

4. SMTP调试技巧

手动测试SMTP连接

使用openssl命令行工具测试SMTP服务是否可用:

openssl s_client -connect smtp.qq.com:587 -starttls smtp -crlf

输入以下命令(替换为你的邮箱和授权码):

EHLO test
AUTH LOGIN
<base64编码的邮箱>  # 示例:echo -n "your_email@qq.com" | base64
<base64编码的授权码>
QUIT

如果返回235 Authentication successful,说明SMTP配置正确。

检查防火墙

在Windows上,运行以下命令放行SMTP端口:

netsh advfirewall firewall add rule name="SMTP" dir=in action=allow protocol=TCP localport=587

5. 总结与最佳实践

常见问题总结

错误原因解决方案
(-1, b'\x00\x00\x00')授权码错误/SMTP拒绝更新授权码,改用starttls()
AttributeError('characters_written')Python 3.10+兼容性问题降级Python或改用SMTP + starttls()
SSL: WRONG_VERSION_NUMBERSSL/TLS配置错误使用starttls() + 端口587

最佳实践

  • 使用TLS(端口587)代替SSL(端口465),兼容性更好。
  • 定期更新授权码,避免因过期导致发送失败。
  • 添加日志记录,便于排查问题。
  • 手动测试SMTP连接,确保服务器可用。

通过本文的分析和优化,你应该能够解决大多数Python邮件发送问题。如果你的场景涉及更复杂的需求(如批量发送、HTML邮件),可以进一步扩展代码逻辑。 

到此这篇关于Python利用SMTP发送邮件的常见问题与解决方案详解的文章就介绍到这了,更多相关Python SMTP发送邮件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python将图片转为矢量图的方法步骤

    python将图片转为矢量图的方法步骤

    这篇文章主要介绍了python将图片转为矢量图的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • PyQt5 python 数据库 表格动态增删改详情

    PyQt5 python 数据库 表格动态增删改详情

    这篇文章主要介绍了PyQt5 python 数据库 表格动态增删改详情,首先手动连接数据库与下一个的程序连接数据库是独立的2个部分,下面来看看文章的详细介绍
    2022-01-01
  • TensorFlow 输出checkpoint 中的变量名与变量值方式

    TensorFlow 输出checkpoint 中的变量名与变量值方式

    今天小编就为大家分享一篇TensorFlow 输出checkpoint 中的变量名与变量值方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • Python中随机数生成random库实战

    Python中随机数生成random库实战

    本文介绍了Python的random库,介绍了生成随机整数、浮点数、序列随机抽样等基本功能,以及设置随机种子、控制概率分布等高级技巧,通过多个实用示例,感兴趣的可以了解一下
    2024-11-11
  • Windows系统下Chromedriver.exe安装及配置详细教程

    Windows系统下Chromedriver.exe安装及配置详细教程

    ChromeDriver.exe是一款实用的chrome浏览器驱动工具,能够用于自动化测试、网络爬虫和操作浏览器,其主要作用是模拟浏览器操作,下面这篇文章主要给大家介绍了关于Windows系统下Chromedriver.exe安装及配置的相关资料,需要的朋友可以参考下
    2023-11-11
  • 基于Python的文件类型和字符串详解

    基于Python的文件类型和字符串详解

    下面小编就为大家分享一篇基于Python的文件类型和字符串详解,具有很的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • python的urllib模块显示下载进度示例

    python的urllib模块显示下载进度示例

    这篇文章主要介绍了python的urllib模块显示下载进度的示例,大家参考使用吧
    2014-01-01
  • python实现给微信指定好友定时发送消息

    python实现给微信指定好友定时发送消息

    这篇文章主要为大家详细介绍了python实现给微信指定好友定时发消息,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • 使用Python设置,更新和获取Excel单元格的值

    使用Python设置,更新和获取Excel单元格的值

    Excel工作簿作为一款广泛使用的数据管理工具,与Python相结合,可以使得自动化处理大量数据成为可能,本文将演示如何使用Python设置、更新以及获取Excel文件中单元格的值,希望对大家有所帮助
    2024-10-10
  • Python Pygame实战之五款童年经典游戏合集

    Python Pygame实战之五款童年经典游戏合集

    本文为大家总结了五款利用Python+Pygame实现的童年经典游戏:推箱子、滑雪、八分音符酱、保卫萝卜和飞机大战,快跟随小编一起学习一下
    2022-04-04

最新评论