同步所有文件夹outlook win32 Python

问题描述 投票:0回答:2

我想等到 Outlook 中的所有文件夹都同步后才开始下载附件。如果我在没有打开 Outlook 并先同步所有文件夹的情况下运行代码,则代码不会下载最新的电子邮件。

代码如下:

import os
import win32com


class DailyExtracts:

    def __init__(self):
        self.outlook = win32com.client.Dispatch("outlook.application").GetNamespace("MAPI")
        self.root = self.outlook.Folders.item(1)
        self.daily_reports = self.root.Folders[".data"].Folders["daily_reports"]


    def download_extracts(self):
        for message in self.daily_reports.Items:
            for attachment in message.Attachments:
                fname = attachment.Filename
                attachment.SaveAsFile(os.path.join(os.path.expanduser(r"~\Downloads"), fname))
                message.Unread = False

我读到可以使用 SyncObjects.SyncEnd 事件等待发送/接收完成。但是,我不知道如何实现它。

python pywin32 win32com
2个回答
1
投票

这是一种(可能不太优雅)的解决方案,它展示了处理 Outlook 事件的基本原理。处理 COM 事件(例如由 Outlook 生成的事件)的问题在于它们是异步的,并且代码必须等待事件被触发。此代码使用线程的消息循环进行阻塞,直到所有同步事件返回为止。

处理程序类的功能超出了 OP 的需要,而且还响应同步错误。

import win32com.client as wc
import pythoncom

import win32api
import win32con

nSync = 0

#Class to handle the SyncObject events from Outlook
class SyncHandler(object):
    #Save the dispatch interface to identify the SyncObject if needed
    def set(self,disp):
        self._disp = disp

    def _process(self):
        #Decrement sync counter
        global nSync
        nSync -= 1
        print(nSync,'Sync remaining to complete')

        #If nothing left to sync, then send WM_QUIT to thread message loop
        if nSync <= 0:
            print('Closing message loop')
            win32api.PostThreadMessage(win32api.GetCurrentThreadId(), win32con.WM_QUIT, 0, 0)
    
    def OnSyncStart(self):
        print('Starting sync on',self._disp.Name)

    def OnSyncEnd(self):    
        print('Sync complete on',self._disp.Name)
        self._process()

    def OnProgress(self,state,description,value,max):
        print('Sync progress: {0:} {1:} {2:}%'.format(self._disp.Name,description,100 * value/max))

    def OnError(self,code,description):
        print('Sync Error',description)
        self._process()

#Get the application Dispatch interface
ol = wc.Dispatch('Outlook.Application')
syncObjects = ol.GetNamespace('MAPI').SyncObjects

#Find out how many SyncObjects we have
nSync = syncObjects.Count
print('Number of Sync objects:',nSync)

for syncObj in syncObjects:
    #Set up an event handler and specify the event handler class
    handler = wc.WithEvents(syncObj,SyncHandler)
    handler.set(syncObj)
    syncObj.Start()
  
#This will block until a WM_QUIT message is sent to the message queue
pythoncom.PumpMessages()

print('Sync completed')

我在有多个电子邮件帐户的 Outlook 客户端上对此进行了测试,它似乎工作正常,尽管我感觉它只同步非 Exchange 帐户(因为我猜 Exchange 帐户会持续同步?)。


0
投票

只想分享我的代码。它基于@DS_London 的解决方案。

import win32com.client

class SyncHandler(object):
    _sync_obj_count = 0

    def set(self, disp):
        self._disp = disp

    def OnSyncStart(self):
        SyncHandler.incr_sync_count()

    def OnSyncEnd(self):
        SyncHandler.decr_sync_count()

    @staticmethod
    def incr_sync_count():
        SyncHandler._sync_obj_count += 1

    @staticmethod
    def decr_sync_count():
        SyncHandler._sync_obj_count -= 1

    @staticmethod
    def get_sync_count():
        return SyncHandler._sync_obj_count

class OutlookApp:

    def __init__(self):
        self._app = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")


    def sync(self):
        for sync_obj in self._app.SyncObjects:
            handler =  win32com.client.WithEvents(sync_obj, SyncHandler)
            handler.set(sync_obj)
            sync_obj.Start()

        while SyncHandler.get_sync_count() > 0:
            pass
© www.soinside.com 2019 - 2024. All rights reserved.