You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

发送带附件邮件时执行成功却报错,疑似重复处理最后文件

听起来这个问题挺挠人的——功能明明正常跑通了,结果每次都在最后一个文件上炸锅,还定位到是邮件处理的代码段,连单文件场景都中招。我来帮你捋捋几个最可能的原因和解决办法:

1. Windows路径转义的隐形坑(最常见)

Windows用反斜杠\表示路径,但在Python字符串里\是转义字符,比如\t会被解析成制表符、\U会触发Unicode转义,这会导致实际生成的路径和你写的完全不一样,最后触发FileNotFoundError。

解决办法:

  • 用原始字符串:在路径前加r,比如r'C:\Users\h\your_file.txt'
  • 或者用双反斜杠:'C:\\Users\\h\\your_file.txt'
  • 更稳妥的是用pathlib库处理路径,彻底规避转义问题:
from pathlib import Path

# 正斜杠在Windows上也能正常工作
file_path = Path('C:/Users/h/your_file.txt')
# 或者依然用反斜杠,配合原始字符串
file_path = Path(r'C:\Users\h\your_file.txt')

2. 邮件对象的重复引用或资源未释放

如果你是循环处理多文件发送邮件,很可能不小心在循环外保留了最后一个附件的引用,导致发送完成后代码重复访问它;或者打开文件时没正确关闭句柄,导致文件被占用,后续检查时误以为文件不存在。

正确的附件添加写法:
确保每次循环都新建邮件对象,并用with语句安全打开文件(自动释放句柄):

from pathlib import Path
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders

file_list = [r'C:\Users\h\file1.txt', r'C:\Users\h\file2.txt']

for file_path in file_list:
    # 每次循环都新建邮件实例,避免交叉引用
    msg = MIMEMultipart()
    msg['Subject'] = f"Attachment: {Path(file_path).name}"
    msg['From'] = "your_email@example.com"
    msg['To'] = "recipient@example.com"

    # 用with语句自动关闭文件句柄
    with open(file_path, 'rb') as att:
        part = MIMEBase('application', 'octet-stream')
        part.set_payload(att.read())
    encoders.encode_base64(part)
    # 只传文件名,避免路径混乱
    part.add_header('Content-Disposition', f'attachment; filename="{Path(file_path).name}"')
    msg.attach(part)

    # 发送邮件
    with smtplib.SMTP('smtp.example.com', 587) as server:
        server.starttls()
        server.login('your_email@example.com', 'your_password')
        server.send_message(msg)

3. 邮件库的隐式操作

一些封装过的邮件库(比如yagmail)可能会在发送后自动清理临时文件,如果你用了临时文件作为附件,发送后文件被删除,后续代码访问就会报错。如果是这种情况,要么使用持久化文件路径,要么在发送完成后再执行文件清理操作。

快速排查小技巧

  1. 打印实际路径:在添加附件前打印file_path,确认路径和预期一致:
print(f"Processing file: {file_path}")

如果输出有乱码或缺失,就是转义问题。

  1. 捕获完整错误信息:在疑似报错的代码段加try-except,打印完整路径和错误:
try:
    # 你怀疑有问题的邮件处理代码
except FileNotFoundError as e:
    print(f"Missing file path: {e.filename}")
    print(f"Full error details: {str(e)}")

这样能精准定位到底是哪个路径出了问题。

  1. 简化代码测试:把移动文件的代码暂时注释掉,只保留邮件发送逻辑,看单文件场景还会不会报错。如果不报错了,就是后续代码和邮件处理的交互问题;如果依然报错,就聚焦邮件代码本身。

内容的提问来源于stack exchange,提问作者Dane Looman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:10:36