You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C# WPF使用Microsoft.Office.Interop.Outlook发送加密邮件时,如何禁用或自动处理Outlook弹窗?

解决Outlook Interop加密邮件时的确认对话框问题

我之前处理过类似的Outlook自动化场景,结合你的需求(不能修改注册表),给你两个可行的解决方案:

方案1:提前验证收件人证书,从根源避免弹窗

与其等发送阶段触发弹窗卡死程序,不如在构建邮件时就主动检查每个收件人是否持有有效加密证书,这样能直接抛出异常或标记问题账户,完全绕开Outlook的确认对话框。

因为是公司内部账户,你可以通过Outlook对象模型结合MAPI属性验证证书,也可以直接查询公司Active Directory(AD通常会存储员工的PKI证书信息)。

示例代码:通过Outlook对象模型验证收件人证书

using Outlook = Microsoft.Office.Interop.Outlook;

// 假设已创建otlMail邮件对象
foreach (Outlook.Recipient recip in otlMail.Recipients)
{
    // 先解析收件人信息
    if (!recip.Resolve())
    {
        throw new Exception($"无法解析收件人:{recip.Name}");
    }

    Outlook.AddressEntry addrEntry = recip.AddressEntry;
    // 只处理Exchange内部账户
    if (addrEntry.Type != "EX")
    {
        continue;
    }

    Outlook.ExchangeUser exUser = addrEntry.GetExchangeUser();
    if (exUser == null)
    {
        throw new Exception($"无法获取收件人Exchange信息:{recip.Name}");
    }

    // 检查收件人是否有SMIME加密证书
    const string PR_SMIME_CERTIFICATE = "http://schemas.microsoft.com/mapi/proptag/0x3A160102";
    try
    {
        var certData = exUser.PropertyAccessor.GetProperty(PR_SMIME_CERTIFICATE);
        if (certData == null)
        {
            throw new Exception($"收件人 {recip.Address} 缺少有效加密证书");
        }
    }
    catch (Exception ex)
    {
        throw new Exception($"验证收件人证书失败:{recip.Address}", ex);
    }
}

// 验证通过后再设置加密属性并发送
try
{
    const string PR_SECURITY_FLAGS = "http://schemas.microsoft.com/mapi/proptag/0x6E010003";
    long prop = Convert.ToInt64(otlMail.PropertyAccessor.GetProperty(PR_SECURITY_FLAGS));
    var ulFlags = 0x1; // SECFLAG_ENCRYPTED
    otlMail.PropertyAccessor.SetProperty(PR_SECURITY_FLAGS, ulFlags);
    otlMail.Send();
}
catch (Exception ex)
{
    // 处理发送异常逻辑
}

方案2:通过Windows API自动处理弹窗

如果某些场景下无法提前验证证书,你可以用Windows API监听并自动操作Outlook的确认对话框。这个方法需要借助P/Invoke调用系统函数,查找目标窗口并模拟按钮点击。

示例代码:自动处理加密确认对话框

using System;
using System.Runtime.InteropServices;
using System.Threading;
using Outlook = Microsoft.Office.Interop.Outlook;

public class OutlookDialogHandler
{
    // P/Invoke 系统函数声明
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    private const uint BM_CLICK = 0x00F5;
    private static IntPtr _dialogHandle;

    // 启动弹窗监听线程
    public static void StartListening()
    {
        Thread listenerThread = new Thread(ListenForDialog)
        {
            IsBackground = true
        };
        listenerThread.Start();
    }

    private static void ListenForDialog()
    {
        while (true)
        {
            // 查找Outlook加密错误对话框(窗口标题固定)
            _dialogHandle = FindWindow("#32770", "Microsoft Outlook");
            if (_dialogHandle != IntPtr.Zero)
            {
                // 查找"继续"按钮(如果是其他语言版本,需修改按钮文本)
                IntPtr continueBtn = FindWindowEx(_dialogHandle, IntPtr.Zero, "Button", "继续");
                if (continueBtn != IntPtr.Zero)
                {
                    // 模拟点击"继续"按钮
                    SendMessage(continueBtn, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
                }
                // 若需要点击"发送未加密邮件",替换按钮文本即可
                // IntPtr sendUnencryptedBtn = FindWindowEx(_dialogHandle, IntPtr.Zero, "Button", "发送未加密邮件");
            }
            Thread.Sleep(500); // 每隔500ms检查一次
        }
    }
}

// 使用方式:在发送邮件前启动监听
OutlookDialogHandler.StartListening();

try
{
    // 设置加密属性并发送邮件
    const string PR_SECURITY_FLAGS = "http://schemas.microsoft.com/mapi/proptag/0x6E010003";
    long prop = Convert.ToInt64(otlMail.PropertyAccessor.GetProperty(PR_SECURITY_FLAGS));
    var ulFlags = 0x1; // SECFLAG_ENCRYPTED
    otlMail.PropertyAccessor.SetProperty(PR_SECURITY_FLAGS, ulFlags);
    otlMail.Send();
}
catch (Exception ex)
{
    // 处理发送异常逻辑
}

注意:这个方法依赖对话框的标题和按钮文本,若你的Outlook是其他语言版本,需要对应修改窗口标题和按钮文本内容。另外,监听线程需在应用程序生命周期内保持运行。


内容的提问来源于stack exchange,提问作者krzyhur

火山引擎 最新活动