首页 > 解决方案 > 使用 pyInstaller 作为 exe 构建运行时,无法使用 win32com 读取 Outlook 邮件项目 - Python 代码有效

问题描述

我有以下代码,当使用 eclipse 运行 python 代码时,它能够从 Outlook 读取邮件项目并下载附件。但是,当使用 pyinstaller 将相同的代码编译为 exe 时,它​​无法读取邮件项目并出现错误:ComObject Unknown

以下代码读取文件夹中的电子邮件项目,并从具有特定主题的邮件中下载 excel 附件。然后从下载的 xls 文件中删除密码并将其保存为 xlsx 文件以供进一步处理。

下面的代码在 eclipse 环境中运行或在命令提示符下使用 python.exe 调用时运行良好。但使用 pyinstaller 编译的 exe 运行时无法识别电子邮件项目。我在 Exchange 服务器上使用 Windows 10 和 Outlook 2016,我在这里缺少什么?下面是代码块:

import win32com.client as wc
from datetime import date
import os
import configparser

print('Reading Config file')
config=configparser.ConfigParser()
config.sections()
config.read('ReadOutlook.config')
configuration=config['DEFAULT']
mailboxname=configuration['mailboxname']
mailfolder_to_look_for=configuration['mailfolder_to_look_for']
downloadpath=configuration['downloadpath']
ULMISPath=configuration['ULMISPath']
CFMISPath=configuration['CFMISPath']
ulmis_password=configuration['ulmis_password']
cfmis_password=configuration['cfmis_password']
ulmisSubjectcontent=configuration['ulmisSubjectcontent']
cfmisSubjectcontent=configuration['cfmisSubjectcontent']
ulmisfilenamesearch=configuration['ulmisfilenamesearch']
cfmisfilenamesearch=configuration['cfmisfilenamesearch']
print (date.today())

outlook = wc.Dispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")
root = namespace.Folders.Item(mailboxname)
print(root.Name)
#print(root.Name)
MyMails=root.Folders.Item(mailfolder_to_look_for)

def Remove_password_xlsx(filename, pw_str,newfilename):
    print('opening Excel Application')
    xcl = wc.Dispatch("Excel.Application")
    print('opening file:' ,filename)
    wb = xcl.Workbooks.Open(filename, False, False, None, pw_str)
    xcl.DisplayAlerts = False
    print('Removing password for',filename)
    wb.SaveAs(filename, None,'','')
    print('Now saving as xlsx',newfilename)
    wb=xcl.Workbooks.Open(filename,False,False,None)
    wb.SaveAs(newfilename, FileFormat=wc.constants.xlOpenXMLWorkbook,CreateBackup=False)
    xcl.Quit()
for mailitem in range(len(MyMails.Items),0,-1):
    print(MyMails.Items[mailitem].Subject)
    try:
        if(MyMails.Items[mailitem].ReceivedTime.date()==date.today() 
           and ((MyMails.Items[mailitem].Subject.find(ulmisSubjectcontent)!=-1 
                 and MyMails.Items[mailitem].Subject.find('With Collection')!=-1) 
                 or MyMails.Items[mailitem].Subject.find(cfmisSubjectcontent)!=-1)):
            print(MyMails.Items[mailitem].Subject)
            # if i.Attachments:
            for f in MyMails.Items[mailitem].Attachments:
                if f.FileName.find(ulmisfilenamesearch)!=-1:
                    f.SaveAsFile(downloadpath + '\\ULMIS.xls')
                    Remove_password_xlsx(downloadpath+'\\ULMIS.xls'
                                         , ulmis_password,ULMISPath)
                    print('removing ULMIS.xls')
                    os.remove(downloadpath+'\\ULMIS.xls')
                    break
                else:
                    if f.FileName.find(cfmisfilenamesearch)!=-1:
                        f.SaveAsFile(downloadpath + '\\CFMIS.xls')
                        Remove_password_xlsx(downloadpath +'\\CFMIS.xls'
                                             , cfmis_password,CFMISPath)
                        print('removing CFMIS.xls')
                        os.remove(downloadpath+'\\CFMIS.xls')
                        break
                    
    except:
        print('an error occurred')
        pass

打印邮件主题会出现以下错误:

回溯(最后一次调用):文件“ReadOutlook.py”,第 45 行,模块文件 >“win32com\client\dynamic.py”,第 279 行,getitem文件 >“win32com\client\util.py”,行37、在getitem File >"win32com\client\util.py",第 56 行,在 __GetIndex IndexError: list index >out of range

IndexError: list index out of range 由于未处理的异常,无法执行脚本“ReadOutlook”!

标签: pythonoutlookpyinstallerwin32commailitem

解决方案


从 DS_London 上面的评论中,我现在更改了我的代码如下:

import win32com.client as wc
from datetime import date
import os
import configparser
# while creating exe on pyinstaller use "win32timezone" in hidden import section
print('Reading Config file')
config=configparser.ConfigParser()
config.sections()
config.read('ReadOutlook.config')
configuration=config['DEFAULT']
mailboxname=configuration['mailboxname']
mailfolder_to_look_for=configuration['mailfolder_to_look_for']
downloadpath=configuration['downloadpath']
ULMISPath=configuration['ULMISPath']
CFMISPath=configuration['CFMISPath']
ulmis_password=configuration['ulmis_password']
cfmis_password=configuration['cfmis_password']
ulmisSubjectcontent=configuration['ulmisSubjectcontent']
cfmisSubjectcontent=configuration['cfmisSubjectcontent']
ulmisfilenamesearch=configuration['ulmisfilenamesearch']
cfmisfilenamesearch=configuration['cfmisfilenamesearch']
print (date.today())

# outlook = wc.Dispatch("Outlook.Application")
outlook = wc.gencache.EnsureDispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")
root = namespace.Folders.Item(mailboxname)
print(root.Name)
#print(root.Name)
MyMails=root.Folders.Item(mailfolder_to_look_for)

def Remove_password_xlsx(filename, pw_str,newfilename):
    print('opening Excel Application')
    xcl=wc.gencache.EnsureDispatch("Excel.Application")
    # xcl = wc.Dispatch("Excel.Application")
    print('opening file:' ,filename)
    wb = xcl.Workbooks.Open(filename, False, False, None, pw_str)
    xcl.DisplayAlerts = False
    print('Removing password for',filename)
    wb.SaveAs(filename, None,'','')
    print('Now saving as xlsx',newfilename)
    wb=xcl.Workbooks.Open(filename,False,False,None)
    wb.SaveAs(newfilename, FileFormat=wc.constants.xlOpenXMLWorkbook,CreateBackup=False)
    xcl.Quit()
for mailitem in range(len(MyMails.Items),0,-1):
    # print(MyMails.Items[mailitem].ReceivedTime.date())
    try:
        if(MyMails.Items[mailitem].ReceivedTime.date()==date.today() 
           and ((MyMails.Items[mailitem].Subject.find(ulmisSubjectcontent)!=-1 
                 and MyMails.Items[mailitem].Subject.find('With Collection')!=-1) 
                 or MyMails.Items[mailitem].Subject.find(cfmisSubjectcontent)!=-1)):
            print(MyMails.Items[mailitem].Subject)
            # if i.Attachments:
            for f in MyMails.Items[mailitem].Attachments:
                if f.FileName.find(ulmisfilenamesearch)!=-1:
                    f.SaveAsFile(downloadpath + '\\ULMIS.xls')
                    Remove_password_xlsx(downloadpath+'\\ULMIS.xls'
                                         , ulmis_password,ULMISPath)
                    print('removing ULMIS.xls')
                    os.remove(downloadpath+'\\ULMIS.xls')
                    break
                else:
                    if f.FileName.find(cfmisfilenamesearch)!=-1:
                        f.SaveAsFile(downloadpath + '\\CFMIS.xls')
                        Remove_password_xlsx(downloadpath +'\\CFMIS.xls'
                                             , cfmis_password,CFMISPath)
                        print('removing CFMIS.xls')
                        os.remove(downloadpath+'\\CFMIS.xls')
                        break
                    
    except:
        # print('an error occurred')
        pass

在此之后,我收到了 win32timezone 缺少导入的错误,我通过在构建 exe 时在 pyInstaller 中添加 hidden_​​import 参数来纠正这个错误 - 遵循这篇文章: ImportError: No module named win32timezone when I make a singleone exe from a python script with pyInstaller


推荐阅读