我想等到 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 事件等待发送/接收完成。但是,我不知道如何实现它。
这是一种(可能不太优雅)的解决方案,它展示了处理 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 帐户会持续同步?)。
只想分享我的代码。它基于@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