Outlook VSTO使用Redemption创建收件箱邮件设置Sender报错如何解决
问题原因分析
- 重复创建RDOSession实例:两个方法中都单独创建了RDOSession,频繁创建MAPI会话容易触发COM异常,完全可以复用同一个会话实例。
- 硬编码读取GAL的兼容性问题:GAL是Exchange账号的全局地址列表,如果你当前Outlook配置的是Outlook.com、POP3/IMAP这类非Exchange账号,GAL本身为空,调用
ResolveName必然抛出异常。 - 缺少容错逻辑:
ResolveName在匹配不到结果时会直接抛出异常,而非返回null,你没有对匹配失败的场景做处理。 - 代码中
msg.To赋值用了中文引号,属于语法错误,需改为英文引号。
解决方法
优化后代码
- 调整逻辑复用RDOSession,优先适配非Exchange环境,增加容错,找不到匹配联系人时可手动构造测试用地址条目:
private void CreateMailItemWithRedemption() { //FYI: outlookApp is set in Ribbon load event //Outlook.Application outlookApp = Globals.ThisAddIn.Application as Microsoft.Office.Interop.Outlook.Application; var outlookNameSpace = outlookApp.GetNamespace("MAPI"); RDOSession session = new RDOSession(); try { session.MAPIOBJECT = outlookNameSpace.MAPIOBJECT; RDOFolder folder = session.GetDefaultFolder(rdoDefaultFolders.olFolderInbox); RDOMail msg = folder.Items.Add("IPM.Note"); msg.Sent = true; DateTime dt = new DateTime(2021, 8, 29, 5, 10, 20, DateTimeKind.Utc); msg.ReceivedTime = dt; msg.Subject = "Mail created with Redemption"; msg.To = "******@outlook.com"; // 修正为英文引号 msg.Sender = GetAddressEntry(session, "John Do"); // 传入已创建的会话复用 msg.Save(); } finally { // 释放COM对象避免Outlook残留进程 Marshal.ReleaseComObject(session); } }
- 重写
GetAddressEntry方法:
private RDOAddressEntry GetAddressEntry(RDOSession session, string _name) { RDOAddressList addressList = null; // 优先尝试Exchange环境的GAL try { addressList = session.AddressBook.GAL; if (addressList != null) { RDOAddressEntry contact = addressList.ResolveName(_name); if (contact != null) { MessageBox.Show(contact.ToString()); return contact; } } } catch { // GAL不存在或解析失败,降级到本地联系人列表 } // 尝试读取本地联系人地址列表,英文环境列表名是"Contacts" addressList = session.AddressBook.AddressLists["联系人"]; if (addressList == null) { // 遍历所有地址列表找匹配结果 foreach (RDOAddressList list in session.AddressBook.AddressLists) { try { if (list.ResolveName(_name) != null) { addressList = list; break; } } catch { } } } // 所有地址列表都匹配不到,手动构造测试用地址条目 if (addressList == null) { return session.AddressBook.CreateOneOffEntryID(_name, "SMTP", "test@test.com", false, false); } RDOAddressEntry result = addressList.ResolveName(_name); MessageBox.Show(result.ToString()); return result; }
补充说明
- 如果仅用于测试,不需要真实存在的联系人,直接调用
CreateOneOffEntryID构造临时地址条目即可,不需要走地址簿解析流程,效率更高。 - 解析联系人时传入邮箱地址比传入姓名的匹配成功率更高,可根据实际需求调整参数。
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

