繁体   English   中英

"python win32com:在 Outlook 中删除多封电子邮件"

[英]python win32com: Delete multiple emails in Outlook

我需要通过 win32com 模块从 python 中删除 Outlook 中的多封电子邮件。

我知道有一个 VBA 方法 MailItem.Delete() 通过 COM 可用于 win32com 并且它有效; 但是当删除多于一封电子邮件时它非常非常慢,因为必须按顺序删除电子邮件,即循环遍历 MailItem 电子邮件集合。

有什么方法可以一次删除选定的 mailItems 集合,例如 MailItemCollection.DeleteAll()?

另外,如果以上是不可能的; 是否有可能通过多线程方法删除许多电子邮件,即将mailItems 的集合划分为4 个子集; 有4个线程在上面运行吗?

我想,因为我可以通过它的 GUI 非常快速地删除 Outlook 中的多封电子邮件,所以必须有一种方法可以让我通过 COM API 做同样的事情。

不在 OOM 中 - MailItem.DeleteItems.Remove(Index)就是你所得到的。

在扩展 MAPI 级别(C++ 或 Delphi,但不是 Python)上,您可以使用IMAPIFolder.DeleteMessages (它采用条目 ID 列表)删除多条消息。 或者您可以使用IMAPIFolder.EmptyFolder (删除文件夹中的所有邮件)。

如果使用Redemption (任何语言;我是它的作者)是一种选择,您可以使用RDOFolder2 EmptyFolderRDOFolder 项目 RemoveMultiple RDOFolder可以从RDOSession 中检索。 如果您将 Outlook 的MAPIFolder对象作为参数传递, GetRDOObjectFromOutlookObject

除了@Dimitry 的一个很好的答案之外,我将添加一条对您来说可能很重要的评论:如果您在迭代时开始从 Items 中删除,则可能会发生奇怪的事情。 例如在我的系统上有以下 Python 代码:

for mail in folder.Items:
    mail.Delete()

for index, mail in enumerate(folder.Items, 1):
    folder.Remove(index)

两者都只删除folder中的一半项目! 原因似乎是 Items 在内部使用一系列索引来提供迭代器,因此每次删除一个元素时,列表的尾部都会移动一个......

要删除文件夹中的所有项目,请尝试:

for i in range(len(folder.Items)):
    folder.Remove(1)

如果您需要按某个标准进行过滤,请考虑先收集 EntryID,然后删除对 ID 的搜索:

ids = []
for i in range(len(folder.Items), 1):
    if to_be_deleted(folder.Items[index]):
        ids.append(index)
for id in ids:
    outlook.GetEntryByID(id).Delete()

我想象它的性能更糟,不过:c

上面 Dedalus 的精彩回答。 想要制作更简洁的代码版本:

import win32com.client

outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")

# Select main Inbox
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items

# Delete all messages from a specific sender
sender = 'myname@abc.com'
try:
    for message in messages:
        try:
            s = message.sender
            s = str(s)
            if s == sender:
                 message.Delete()
        except:
            pass
except:
    pass

您可能不需要两次“尝试”,但我发现将脚本应用于长时间且频繁使用的收件箱时它更稳定。 通常我将它与将 message = inbox.Items 限制在一周内的脚本结合起来,这样它就不会处理整个收件箱。

对我来说,它通过反向迭代项目来工作。

:

for mail in folder.Items:
    if 'whatever' in mail.Subject: # just a condition (optional)
        mail.Delete()

新代码:

for mail in reversed(folder.Items): # just tried deleting Items in reverse order
    if 'whatever' in mail.Subject: # just a condition (optional)
        mail.Delete()

希望这可以帮助某人。

我错过了什么吗? Application 和 NameSpace 对象似乎都没有 GetEntryByID 方法,尽管 Dedalus 指出的其余部分是正确的。

命名空间对象有一个 GetItemFromID 方法,而 MailItem 对象有一个 EntryID 属性,只要它们不被重新组织到不同的文件夹中,它就会唯一地标识它们。

文档: https : //docs.microsoft.com/en-us/office/vba/outlook/how-to/items-folders-and-stores/working-with-entryids-and-storeids

我的完整解决方案:

import win32com.client

outlook = win32com.client.gencache.EnsureDispatch("Outlook.Application")

folders = outlook.GetNamespace("MAPI")

inbox= folders.GetDefaultFolder(6)

messages=inbox.Items

email_ids = []

folder_id = inbox.StoreID 

# Here create a function to isolate/exclude. Below is just an example of filtering by a subject line.

email_subjects = ['Subj1','Subj2','Subj3']

for i in range(len(messages)):

    if any(header in inbox.Items[i].Subject for header in email_subjects):

        email_ids.append(inbox.Items[i].EntryID)

for id in email_ids:
    folders.GetItemFromID(id, folder_id).Delete()

我已经在本地 Outlook 中实现了一个替代解决方案,通过直接使用 VBA 代码或 Outlook 过滤规则将电子邮件项目从.inbox 文件夹移动到已删除项目文件夹或存档文件夹。 这样,我每周只需手动清空一次已删除的项目文件夹(当然这个周期性步骤也可以编程)。 我观察到这种策略可以更有效,而不是使用代码删除每个项目(你提到了 internal.indexes 问题)。

"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM