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

Python win32com读取Outlook邮件仅到2024/05/31问题求助

问题描述

我用Python的win32com库编写了读取Outlook指定文件夹邮件的代码,可实现匹配主题下载附件并解压文件功能。但运行时发现,无论选择哪个文件夹,代码仅能扫描处理2024年5月31日及之前的邮件,无法处理该日期之后的邮件,请求帮忙排查代码中的问题。

原代码
from logging import root
import os
import win32com.client
from datetime import datetime, timedelta
import zipfile

date_format = "%m/%d/%Y %H:%M"

def recursively_find_folder(folder, target_name):
    if folder.Name == target_name:
        return folder
    for subfolder in folder.Folders:
        found_folder = recursively_find_folder(subfolder, target_name)
        if found_folder:
            return found_folder

#function to check the emails mentioned in outlook folder and down load the attachements based on email subject
def download_attachments(folder_name, output_folder, start_time, end_time, target_subject):
    outlook_app = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
    #root_folder = outlook_app.Folders.Item(3)  # Assume the first folder is the mailbox
    root_folder = outlook_app.GetDefaultFolder(6)  # Assume the first folder is the mailbox
      
    target_folder = recursively_find_folder(root_folder, folder_name)

    if target_folder:
        print(f"Found folder: {target_folder.Name}")

        # Iterate through items in the folder
        items = target_folder.Items
        items.sort("[ReceivedTime]", True)

        for item in items:
            print("Item:: ", item)
            print("    Subject:: ", item.Subject.lower())
            print("    Recevied Time: ", item.ReceivedTime)
            # Check if the email matches the criteria
            for subject in target_subject:
                print(subject)
                print("Email Received Time: ", datetime.strptime(item.ReceivedTime.strftime('%m/%d/%Y %H:%M'), date_format))
                if (
                    start_time <= datetime.strptime(item.ReceivedTime.strftime('%m/%d/%Y %H:%M'), date_format) <= end_time
                    and subject.lower().strip() in item.Subject.lower().strip()
                    and item.Attachments.Count > 0
                ):
                    print(f"Processing email: {item.Subject}")
                    for attachment in item.Attachments:
                        # Save attachments to the output folder
                        attachment.SaveAsFile(os.path.join(output_folder, attachment.FileName))
                        print(f"Downloaded attachment: {attachment.FileName}")
                else:
                    print("Nothing Happened!!!")

    else:
        print(f"Folder '{folder_name}' not found.")
        
#--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

#function to find zip folder and unzip it
def find_and_unzip_report_file(folder_path, extraction_path):
    # Check if the folder exists
    if not os.path.exists(folder_path):
        print(f"Error: Folder '{folder_path}' not found.")
        return

    # Get a list of all files in the folder
    files = os.listdir(folder_path)

    # Find the report file based on the name pattern
    report_file = next((file for file in files if file.lower().startswith('report') and file.lower().endswith('.zip')), None)

    if report_file:
        # Construct the full path to the zip file
        zip_file_path = os.path.join(folder_path, report_file)

        # Create the extraction path if it doesn't exist
        os.makedirs(extraction_path, exist_ok=True)

        # Unzip the contents of the zip file
        with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
            zip_ref.extractall(extraction_path)
        
        os.rename(folder_path + 'CC CM Provisioning - INC SLA - ALL.csv', folder_path + 'CC CM Provisioning - INC SLA - ALL' + '-' + report_file[7:24] + '.csv')
        
        os.remove(zip_file_path)
        print(f"Successfully unzipped '{zip_file_path}' to '{extraction_path}'.")
    else:
        print("Error: Report file not found in the specified folder.")


if __name__ == "__main__":
    folder_to_download = "service_tickets"
    output_directory = "//prod_drive/meta/downloads/"
    # Get the first day of the current month
   
    start_date_time = (datetime.today().replace(day=1, hour=23, minute=0, second=0, microsecond=0) - timedelta(days=1)).strftime('%m/%d/%Y %H:%M')
    
    end_date_time = (datetime.today().replace(day=1, hour=23, minute=10, second=0, microsecond=0) - timedelta(days=1)).strftime('%m/%d/%Y %H:%M') 
    date_format = "%m/%d/%Y %H:%M"
    start_time = datetime.strptime(start_date_time, date_format)
    print("Start Time:", start_time)
    end_time = datetime.strptime(end_date_time, date_format)
    print("End Time: ", end_time)
    target_subject = ['CC CM Provisioning - INC SLA - ALL','CC CM Provisioning - SCTASK SLA - All','CC CM Provisioning - SCTASK - All']


    download_attachments(folder_to_download, output_directory, start_time, end_time, target_subject)
    
    find_and_unzip_report_file(output_directory, output_directory)
问题排查与修复方案

1. Outlook Items集合的加载限制

Outlook的Items集合默认不会一次性加载所有邮件,通常只会加载最近的一批旧数据(比如前250条),直接遍历无法获取未加载的新邮件。解决方法是使用**Restrict方法先过滤时间范围**,让Outlook直接返回符合条件的所有邮件,而非遍历全部已加载项。

2. 日期时间转换的精度丢失

代码中把item.ReceivedTime转成字符串再转回datetime,会丢失秒和微秒信息,可能导致新邮件的时间判断逻辑出错。应该直接从ReceivedTime的属性中提取年、月、日等信息构建datetime对象,跳过字符串中转步骤。

3. 修改后的核心代码

替换download_attachments函数中的邮件遍历部分为以下代码:

if target_folder:
    print(f"Found folder: {target_folder.Name}")

    items = target_folder.Items
    items.Sort("[ReceivedTime]", True)

    # 构建Outlook兼容的时间过滤条件(Jet语法,日期需用单引号包裹)
    start_filter = start_time.strftime('%Y-%m-%d %H:%M')
    end_filter = end_time.strftime('%Y-%m-%d %H:%M')
    filter_str = f"[ReceivedTime] >= '{start_filter}' AND [ReceivedTime] <= '{end_filter}'"
    
    # 过滤出符合时间范围的邮件
    filtered_items = items.Restrict(filter_str)

    for item in filtered_items:
        # 直接从ReceivedTime属性构建datetime对象,避免精度丢失
        received_dt = datetime(
            item.ReceivedTime.year,
            item.ReceivedTime.month,
            item.ReceivedTime.day,
            item.ReceivedTime.hour,
            item.ReceivedTime.minute,
            item.ReceivedTime.second
        )
        print("    Subject:: ", item.Subject.lower())
        print("    Received Time: ", received_dt)
        
        # 匹配主题并处理附件
        for subject in target_subject:
            if (subject.lower().strip() in item.Subject.lower().strip() 
                and item.Attachments.Count > 0):
                print(f"Processing email: {item.Subject}")
                for attachment in item.Attachments:
                    save_path = os.path.join(output_folder, attachment.FileName)
                    attachment.SaveAsFile(save_path)
                    print(f"Downloaded attachment: {attachment.FileName}")

额外注意事项

  • 确保root_folder指向正确的邮箱根目录:当前代码用GetDefaultFolder(6)获取的是收件箱,如果目标文件夹不在收件箱下,需要修改为对应的根邮箱(比如outlook_app.Folders.Item("你的邮箱地址"))。
  • Restrict方法的过滤语法需严格遵循Outlook的Jet查询语法,日期格式必须为yyyy-mm-dd hh:mm。

内容的提问来源于stack exchange,提问作者Nikhil Ravindran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:29:59