在自动化办公和系统开发中,邮件发送功能是常见的需求。无论是发送通知、报告,还是传输文件,Python的smtplib和email库提供了便捷的实现方式。然而,在实际开发中,开发者常会遇到各种SMTP错误,如(-1, b'\x00\x00\x00')、AttributeError('characters_written')等,这些问题往往让人束手无策。
本文将从实际案例出发,分析常见的SMTP错误,并提供完整的解决方案,帮助开发者快速定位和解决问题。同时,我们还会优化代码,使其更健壮、更易于维护。
SMTPResponseException: (-1, b'\x00\x00\x00')AttributeError('characters_written')在Python中,使用smtplib发送邮件时,通常会遇到两类问题:
以下是一个典型的邮件发送代码,它可能会触发上述错误:
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运行此代码时,可能会遇到以下错误:
SMTPResponseException: (-1, b'\x00\x00\x00')检查授权码
password。更换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)检查网络环境
AttributeError('characters_written')SMTP_SSL 的兼容性问题。改用starttls()(推荐)
避免使用SMTP_SSL,改用SMTP + starttls():
with smtplib.SMTP(smtp_server, 587) as server:
server.starttls() # 显式启用TLS
server.login(sender_email, password)降级Python或升级依赖库
如果仍报错,尝试降级到Python 3.9,或更新pyopenssl:
pip install --upgrade pyopenssl结合上述解决方案,优化后的代码如下:
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 FalseSMTPException和其他异常,便于排查问题。logging记录详细错误信息。使用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错误 | 原因 | 解决方案 |
|---|---|---|
(-1, b'\x00\x00\x00') | 授权码错误/SMTP拒绝 | 更新授权码,改用starttls() |
AttributeError('characters_written') | Python 3.10+兼容性问题 | 降级Python或改用SMTP + starttls() |
SSL: WRONG_VERSION_NUMBER | SSL/TLS配置错误 | 使用starttls() + 端口587 |
通过本文的分析和优化,你应该能够解决大多数Python邮件发送问题。如果你的场景涉及更复杂的需求(如批量发送、HTML邮件),可以进一步扩展代码逻辑。 Happy coding! 🚀