如何释放Outlook中COM对象的内存,当处理数千封电子邮件时,该对象会耗尽内存?

问题描述

我有一个Python脚本,可获取收件箱文件夹中所有电子邮件的电子邮件ID。 但是,Outlook收到数千封电子邮件时会抛出内存不足异常。

例外:

get_emails_and_ids

我尝试了两种不同的方法:迭代一次(get_emails)和两次(get_email_idsPropertyAccessor)。

这似乎与获得get_emails几千次有关。如果我只是使用PropertyAccessor来接收电子邮件,则可以很好地处理38,000封电子邮件,但是当我开始使用pip install -U pypiwin32 获取ID数以千计时,那就是它用尽了内存。我必须释放旧的属性访问器吗?

安装:

#!/usr/bin/env python

from typing import Any,List,Tuple,Set

import traceback
import win32com.client

PidTagInternetMessageId = "http://schemas.microsoft.com/mapi/proptag/0x1035001F"

primary_account_email = "[email protected]"
primary_source_folder_name = "InBox"


def get_emails(folder) -> List:
    return [item for item in folder.Items if "_MailItem" in str(type(item))]


def get_email_ids(emails) -> Set[str]:
    return {email_id for email in emails if len(email_id := email.PropertyAccessor.GetProperty(PidTagInternetMessageId)) > 0}


def get_emails_and_ids(folder) -> Tuple[List,Set[str]]:
    emails = []
    email_ids = set()

    for item in folder.Items:
        if "_MailItem" in str(type(item)):
            emails.append(item)
            property_accessor = item.PropertyAccessor
            email_id = property_accessor.GetProperty(PidTagInternetMessageId)
            email_ids.add(email_id)

    return emails,email_ids


def print_emails() -> None:
    outlook = win32com.client.gencache.Ensuredispatch("outlook.application")
    namespace = outlook.GetNamespace("MAPI")

    primary_account = namespace.Folders[primary_account_email]
    primary_folders = primary_account.Folders
    primary_source_folder = primary_folders[primary_source_folder_name]
    primary_emails,primary_email_ids = get_emails_and_ids(primary_source_folder)
    # primary_emails = get_emails(primary_source_folder)
    # primary_email_ids = get_email_ids(primary_emails)

    print(primary_email_ids)


def main(*args: Tuple[Any,...]) -> None:
    try:
        print(f"Printing emails...")
        print_emails()
        print()
        print("Done.")
    except Exception:
        traceback.print_exc()
    print()

    print("Press enter to exit...")
    input()


if __name__ == "__main__":
    main()

代码

export const addProduct = (product,imageUrl) => {
  return (dispatch) => {
    return new Promise((resolve,reject) => {
      const fileData = new FormData();
      fileData.append("imageUrl",imageUrl);
      fileData.append("productData",product);
      axios({
        method: "post",url: "/api/products/add-product",data: fileData,headers: {
          "Content-Type": "multipart/form-data",},});
    });
  };
};

解决方法

尝试用从1到Items.Count的循环替换“ for”循环(使用Items(i)检索一个项目)-不确定是否使用Python,但使用其他语言“ foreach” “循环倾向于保留引用的集合的所有项目,直到循环退出为止。

,

我的解决方案是不将所有电子邮件(MailItem objects)存储在列表中。如果我需要列表中的电子邮件,则在处理电子邮件时,应该list.pop()或将其从列表中立即删除。使用PropertyAccessor并将电子邮件保留在列表中会导致Outlook将对象保留在内存中,并导致Outlook内存不足。

我放弃了get_emailsget_emails_and_ids函数,并重新编写了get_email_ids函数以仅存储电子邮件ID,而不将电子邮件对象存储在列表中:>

def get_email_ids(folder) -> Tuple[Set[str],int]:
    email_ids = set()

    items = folder.Items
    i = 0
    for item in items:
        if "_MailItem" in str(type(item)):
            i += 1

            property_accessor = item.PropertyAccessor
            email_id = property_accessor.GetProperty(PidTagInternetMessageId)
            if len(email_id) > 0:
                email_ids.add(email_id)

            if i % 500 == 0:
                print(f"    Retrieved {i} email IDs.")

    return email_ids,i

我编写的其他脚本现在要快得多,并且至少需要10分钟。以前,它以前每秒要处理几封电子邮件,并且要花几个小时。