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
相关产品推荐
相关产品推荐

