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

Python脚本下载Gmail附件遇FileExistsError,附件未下载求助

问题排查与修复方案

1. 解决目录创建的FileExistsError

你的脚本在创建目录时逻辑错误:检查当前目录(.)下是否存在attachments子文件夹,若不存在就创建/var/www/html/attachments——这两个目录没有关联,当/var/www/html/attachments已存在时,就会触发FileExistsError。

修复代码:
替换原来的目录创建代码:

detach_dir = '.'
if 'attachments' not in os.listdir(detach_dir):
    os.mkdir('/var/www/html/attachments')

为:

target_dir = '/var/www/html/attachments'
# 安全创建目录,已存在则跳过
try:
    os.makedirs(target_dir, exist_ok=True)
except OSError as e:
    print(f"创建目录失败: {str(e)}")
    sys.exit(1)

exist_ok=True参数会让os.makedirs在目录已存在时不抛出错误,同时支持创建多级目录。

2. 排查附件未下载问题

2.1 修复邮件搜索逻辑

原脚本中搜索主题的参数用了HTML转义的"DASHBOARD",这会导致搜索的是包含"DASHBOARD"的主题,而非DASHBOARD。修改搜索语句:

# 精确匹配主题为DASHBOARD的邮件
typ, data = imapSession.search(None, 'SUBJECT', '"DASHBOARD"')
# 若要模糊匹配(主题包含DASHBOARD),可改为:
# typ, data = imapSession.search(None, 'SUBJECT', 'DASHBOARD')

2.2 修正附件路径拼接

原代码中os.path.join(detach_dir, '/var/www/html/attachments', fileName)存在冗余,且容易混淆。直接使用目标目录拼接路径:

if bool(fileName): 
    filePath = os.path.join(target_dir, fileName)
    if not os.path.isfile(filePath) : 
        print(f"保存附件: {fileName} 到 {filePath}")
        with open(filePath, 'wb') as fp:
            fp.write(part.get_payload(decode=True))

这里改用with语句自动关闭文件,避免资源泄漏。

2.3 优化异常捕获

原脚本的except :会捕获所有异常且不输出具体错误信息,导致无法定位问题。修改为:

except Exception as e:
    print(f"执行出错: {str(e)}")
    print ('No attachments were downloaded')

这样可以看到具体的错误详情,方便排查。

2.4 验证目录权限

确保运行脚本的用户对/var/www/html/attachments有写入权限:

  • 查看目录权限:ls -ld /var/www/html/attachments
  • 若当前用户无权限,可调整目录所有者:sudo chown $USER:$USER /var/www/html/attachments
  • 或临时用sudo运行脚本测试:sudo python3 get_images_from_emails.py

2.5 增加调试日志

在关键步骤添加打印,确认脚本是否找到目标邮件和附件:

# 遍历搜索到的邮件时添加
for msgId in data[0].split():
    print(f"开始处理邮件ID: {msgId}")
    typ, messageParts = imapSession.fetch(msgId, '(RFC822)')
    # ... 其他代码

# 遍历邮件部分时添加
for part in mail.walk():
    print(f"邮件部分类型: {part.get_content_type()}, 文件名: {part.get_filename()}")
    # ... 其他代码

3. 修复邮件移动逻辑(可选)

原脚本会移动所有收件箱邮件到Processed标签,这不符合预期(应该只移动处理过的带DASHBOARD主题的邮件)。修改为:

# 移动已处理的邮件到Processed标签
imapSession.select(mailbox='inbox', readonly=False)
for msgId in data[0].split():
    # 添加Processed标签
    result = imapSession.store(msgId, '+X-GM-LABELS', 'Processed')
    if result[0] == 'OK':
        # 标记为已删除
        imapSession.store(msgId, '+FLAGS', '\\Deleted')
# 清空已删除邮件(Gmail会自动同步到垃圾箱)
imapSession.expunge()

完整修复后的脚本示例

#!/usr/bin/env python3
# 从Gmail下载指定主题邮件的图片附件,并移动邮件到Processed标签

import email
import getpass, imaplib
import os
import sys

# 目标附件存储目录
target_dir = '/var/www/html/attachments'
# 安全创建目录
try:
    os.makedirs(target_dir, exist_ok=True)
except OSError as e:
    print(f"创建目录失败: {str(e)}")
    sys.exit(1)

userName = 'enter-your-gmail-account-name-here'
passwd = 'enter-your-password-here'

try:
    # 连接Gmail IMAP服务器
    imapSession = imaplib.IMAP4_SSL('imap.gmail.com', 993)
    typ, accountDetails = imapSession.login(userName, passwd)
    if typ != 'OK':
        print ('登录失败!')
        raise Exception

    # 选择收件箱
    imapSession.select('Inbox')
    # 搜索主题包含DASHBOARD的邮件
    typ, data = imapSession.search(None, 'SUBJECT', 'DASHBOARD')
    if typ != 'OK':
        print ('搜索收件箱出错。')
        raise Exception

    # 遍历所有匹配的邮件
    if not data[0]:
        print("未找到符合条件的邮件")
    else:
        for msgId in data[0].split():
            print(f"处理邮件ID: {msgId}")
            typ, messageParts = imapSession.fetch(msgId, '(RFC822)')
            if typ != 'OK':
                print ('获取邮件内容出错。')
                raise Exception

            emailBody = messageParts[0][1] 
            mail = email.message_from_bytes(emailBody) 

            # 遍历邮件附件
            for part in mail.walk():
                if part.get_content_maintype() == 'multipart':
                    continue
                if part.get('Content-Disposition') is None:
                    continue

                fileName = part.get_filename()
                if bool(fileName): 
                    filePath = os.path.join(target_dir, fileName)
                    if not os.path.isfile(filePath) : 
                        print(f"保存附件: {fileName} -> {filePath}")
                        with open(filePath, 'wb') as fp:
                            fp.write(part.get_payload(decode=True))
                    else:
                        print(f"附件 {fileName} 已存在,跳过")

    # 移动已处理邮件到Processed标签
    imapSession.select(mailbox='inbox', readonly=False)
    if data[0]:
        for msgId in data[0].split():
            result = imapSession.store(msgId, '+X-GM-LABELS', 'Processed')
            if result[0] == 'OK':
                imapSession.store(msgId, '+FLAGS', '\\Deleted')
        imapSession.expunge()
        print("已处理邮件已移动到Processed标签")

    imapSession.close()
    imapSession.logout()
    print("脚本执行完成")

except Exception as e:
    print(f'执行出错: {str(e)}')
    print ('未下载任何附件')

内容的提问来源于stack exchange,提问作者Jennifer Hamilton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:47:13