C#读取Outlook邮件脚本突发失效,报错80080005求排查
上周正常运行的C# Outlook自动读邮件脚本,本周开始抛出以下错误:
"Retrieving the COM class factory for component with CLSID failed due to the following error: 80080005 Server execution failed"
已完成的排查操作:
- 引用了Microsoft.Office.Interop.Outlook.dll(文件版本14.0)
- 虚拟机上Outlook已更新至最新版本
- 无待安装的Windows更新
- 已重启虚拟机
脚本代码如下:
using System; using System.Collections.Generic; using System.Runtime.InteropServices; using olook = Microsoft.Office.Interop.Outlook; namespace ReadingEmails { internal class Program { public static (string[], olook.MailItem[]) ReadMail() { try { List<string> bodyList = new List<string>(); List<olook.MailItem> emailList = new List<olook.MailItem>(); olook.Application outlookApp = new olook.Application(); olook.Folder inbox = outlookApp.Session.GetDefaultFolder(olook.OlDefaultFolders.olFolderInbox) as olook.Folder; olook.Folders childFolders = inbox.Folders; foreach (olook.Folder folder in childFolders) { //Reason behind this that if we have an outlook rule to automate moving emails into specific //folder it will be less emails than the inbox for the script to navigate through if (folder.Name == "testFolder") { //Retrieving mail items from the folder olook.Items mailItems = folder.Items; foreach (object item in mailItems) { if (item is olook.MailItem) { olook.MailItem mailItem = (olook.MailItem)item; //Will only be looking at emails with subject line: Manual Incoming2 //Only looking at unread emails, otherwise we will have infinite loop //of emails being sent if (mailItem != null && mailItem.Subject != null && mailItem.UnRead) { if (mailItem.Subject.Contains("Incoming")) { //will not look at any emails that are replies or fowards. otherwise //we will have infinite loop of emails being sent try { if (!mailItem.Subject.Contains("RE:") || !mailItem.Subject.Contains("FW:")) { Console.WriteLine(DateTime.Now + " : Found Email"); bodyList.Add(mailItem.Body); emailList.Add(mailItem); //make email read so that we can avoid infinite loops of emails //being sent mailItem.UnRead = false; } } catch (System.Exception ex) { Console.WriteLine(ex.Message); } } } } } } } Marshal.ReleaseComObject(outlookApp); return (bodyList.ToArray(), emailList.ToArray()); } catch (System.Exception ex) { Console.WriteLine(ex.Message); } return (null, null); } static void Main(string[] args) { (string[] bodyArray, olook.MailItem[] emails) = ReadMail(); Console.ReadLine(); } } }
针对这个错误,可尝试以下步骤逐一排查:
清理异常挂起的Outlook进程:打开任务管理器,找到所有
OUTLOOK.EXE进程(包括后台运行的),全部结束后重新启动Outlook,再运行脚本。COM组件报错常因之前的Outlook进程未正常退出,占用了资源。修复Outlook COM组件注册:以管理员身份打开命令提示符,执行对应Office版本的注册命令(路径根据你的Office安装位置调整):
# Office 2016/365 示例路径 regsvr32.exe "C:\Program Files\Microsoft Office\root\Office16\OUTLOOK.EXE" # Office 2010 示例路径 regsvr32.exe "C:\Program Files\Microsoft Office\Office14\OUTLOOK.EXE"完善COM对象释放逻辑:原代码仅释放了
outlookApp,但遍历过程中创建的folder、mailItems、mailItem等COM对象未释放,长期运行会导致资源泄漏,引发进程异常。修改代码示例:
在遍历每个mailItem后添加:Marshal.ReleaseComObject(mailItem);遍历完
mailItems后添加:Marshal.ReleaseComObject(mailItems);遍历完每个
folder后添加:Marshal.ReleaseComObject(folder);最后还要释放
inbox和childFolders:Marshal.ReleaseComObject(childFolders); Marshal.ReleaseComObject(inbox);检查用户权限与组策略:确保运行脚本的用户拥有Outlook的完全访问权限,且没有被组策略限制COM组件的调用权限。
验证Interop库与Office版本兼容性:当前使用的Interop库版本14.0对应Office 2010,而Outlook已更新至最新版本,可能存在兼容性问题。尝试更新Interop库到与当前Office版本匹配的版本(比如Office 2016对应v16.0),可通过NuGet安装
Microsoft.Office.Interop.Outlook包获取对应版本。
内容的提问来源于stack exchange,提问作者user23492554

