Python连接Outlook遇AttributeError及附件提取不全问题求助
问题
我编写了一段Python代码,要实现以下功能:
- 连接Outlook并指定子文件夹
- 获取用户输入的目标日期
- 搜索该日期内带有
report.csv附件的邮件 - 移除邮件主题中的特定关键词
- 提取附件
- 以处理后的邮件主题为文件名保存附件到指定文件夹
代码虽能运行,但仅提取30余份报告中的4份就崩溃,VS Code提示错误出在第54行outlook.GetNamespace.Quit(),错误信息为AttributeError: GetNamespace.GetNamespace。附上代码求问题分析及解决思路:
import os import win32com.client import datetime as dt from datetime import date, timedelta from pathlib import Path EMAIL_ADDRESS = "emailaddress@example.com" FOLDER_NAME = "subfolder_name" OUTPUT_FOLDER = Path(r"Specify Path") #specify the path def connect_to_outlook(): outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace ("MAPI") inbox_folder = outlook.GetDefaultFolder(6) # Inbox folder sub_folder = inbox_folder.Folders(FOLDER_NAME) return sub_folder, outlook, inbox_folder, outlook def extract_csv_attachments(emails): csv_attachments = [(email.Subject.split("[INSERT TEXT TO PARSE/SPLIT")[0].strip(), attachment) for email in emails for attachment in email.Attachments if attachment.FileName == "report.csv"] return csv_attachments try: # Connect to Outlook sub_folder, outlook, inbox_folder, outlook = connect_to_outlook() # Get target date from user input target_date_str = input("Enter a target date (YYYY-MM-DD): ") target_date = dt.datetime.strptime(target_date_str, '%Y-%m-%d') # Construct search criteria and filter emails search_criteria = f'[SenderEmailAddress] = "{EMAIL_ADDRESS}" AND [ReceivedTime] >= "{target_date.strftime("%m/%d/%Y")}" AND [ReceivedTime] < "{(target_date + dt.timedelta(days=1)).strftime("%m/%d/%Y")}"' filtered_emails = sub_folder.Items.Restrict(search_criteria) # Extract CSV attachments from filtered emails csv_attachments = extract_csv_attachments(filtered_emails) # Save extracted attachments to output folder for email_subject, attachment in csv_attachments: attachment.SaveAsFile(OUTPUT_FOLDER / f"{email_subject}.csv") finally: # Release Outlook resources sub_folder = None inbox_folder = None outlook.GetNamespace.Quit() outlook.Quit()
问题分析
- 核心错误:Outlook对象调用逻辑混乱
outlook变量本身是GetNamespace("MAPI")返回的命名空间对象,而非Outlook应用实例。调用outlook.GetNamespace.Quit()完全错误——命名空间对象不存在GetNamespace属性,直接触发AttributeError。 - 重复赋值导致对象指向混乱
connect_to_outlook函数返回值重复写了outlook,导致inbox_folder被覆盖为命名空间对象:return sub_folder, outlook, inbox_folder, outlook- 调用函数时再次重复赋值:
sub_folder, outlook, inbox_folder, outlook = connect_to_outlook(),进一步打乱变量指向,可能提前释放关键资源导致中途崩溃。
- 遍历与资源处理的潜在问题
直接遍历Restrict过滤后的Items集合,未处理COM对象引用泄漏;资源释放逻辑错误,加剧Outlook进程异常风险。
解决思路与修正代码
- 修正对象引用与资源释放
- 明确区分
Outlook.Application实例和MAPI命名空间对象,仅对Application实例调用Quit() - 清理重复赋值错误,确保每个变量指向正确对象
- 明确区分
- 优化稳定性与鲁棒性
- 处理主题分割时的边界情况,避免索引错误
- 对过滤后的邮件排序,避免遍历异常
- 处理文件名非法字符,防止保存失败
修正后的代码:
import os import win32com.client import datetime as dt from datetime import timedelta from pathlib import Path EMAIL_ADDRESS = "emailaddress@example.com" FOLDER_NAME = "subfolder_name" OUTPUT_FOLDER = Path(r"Specify Path") # 指定保存路径 def connect_to_outlook(): # 分离Outlook应用实例与MAPI命名空间 outlook_app = win32com.client.Dispatch("Outlook.Application") mapi_namespace = outlook_app.GetNamespace("MAPI") inbox_folder = mapi_namespace.GetDefaultFolder(6) # 6代表收件箱 sub_folder = inbox_folder.Folders(FOLDER_NAME) # 返回正确的对象集合 return sub_folder, mapi_namespace, inbox_folder, outlook_app def extract_csv_attachments(emails): csv_attachments = [] for email in emails: # 处理主题分割的边界情况 keyword = "[INSERT TEXT TO PARSE/SPLIT]" cleaned_subject = email.Subject.split(keyword)[0].strip() if keyword in email.Subject else email.Subject.strip() for attachment in email.Attachments: if attachment.FileName == "report.csv": csv_attachments.append((cleaned_subject, attachment)) return csv_attachments try: # 获取正确的对象引用 sub_folder, mapi_namespace, inbox_folder, outlook_app = connect_to_outlook() # 获取目标日期 target_date_str = input("输入目标日期(YYYY-MM-DD):") target_date = dt.datetime.strptime(target_date_str, '%Y-%m-%d') # 构造更精确的搜索条件(包含时间) start_date = target_date.strftime("%m/%d/%Y 00:00 AM") end_date = (target_date + timedelta(days=1)).strftime("%m/%d/%Y 00:00 AM") search_criteria = f'[SenderEmailAddress] = "{EMAIL_ADDRESS}" AND [ReceivedTime] >= "{start_date}" AND [ReceivedTime] < "{end_date}"' filtered_emails = sub_folder.Items.Restrict(search_criteria) # 排序避免遍历异常 filtered_emails.Sort("[ReceivedTime]", win32com.client.constants.olAscending) # 提取并保存附件 csv_attachments = extract_csv_attachments(filtered_emails) for email_subject, attachment in csv_attachments: save_path = OUTPUT_FOLDER / f"{email_subject}.csv" # 替换文件名中的非法字符 save_path = save_path.with_name(save_path.name.replace('/', '_').replace('\\', '_').replace(':', '_')) attachment.SaveAsFile(str(save_path)) print(f"已保存:{save_path}") finally: # 正确释放资源:先置空子对象,再退出应用 sub_folder = None inbox_folder = None mapi_namespace = None if 'outlook_app' in locals(): outlook_app.Quit()
内容的提问来源于stack exchange,提问作者CyberCoder
相关产品推荐
相关产品推荐

