You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Outlook VSTO使用Redemption创建收件箱邮件设置Sender报错如何解决

问题原因分析

  1. 重复创建RDOSession实例:两个方法中都单独创建了RDOSession,频繁创建MAPI会话容易触发COM异常,完全可以复用同一个会话实例。
  2. 硬编码读取GAL的兼容性问题:GAL是Exchange账号的全局地址列表,如果你当前Outlook配置的是Outlook.com、POP3/IMAP这类非Exchange账号,GAL本身为空,调用ResolveName必然抛出异常。
  3. 缺少容错逻辑:ResolveName在匹配不到结果时会直接抛出异常,而非返回null,你没有对匹配失败的场景做处理。
  4. 代码中msg.To赋值用了中文引号,属于语法错误,需改为英文引号。

解决方法

优化后代码

  1. 调整逻辑复用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);
    }
}
  1. 重写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 17:54:01