Outlook VSTO设置SendUsingAccount仅生效一次的问题排查
问题:Outlook VSTO插件设置SendUsingAccount仅首次生效
我希望Outlook VSTO插件在从“Public”账户发送邮件时,将“发件人”设置为默认账户。首次新建邮件时功能正常,但后续操作失效。
原始代码
public partial class ThisAddIn { private Account defaultAcct = null; private Inspectors inspectors; private void ThisAddIn_Startup(object sender, System.EventArgs e) { inspectors = this.Application.Inspectors; inspectors.NewInspector += new InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector); Accounts accounts = Application.Session.Accounts; foreach (Account account in accounts) { var displayName = account.DisplayName; if(displayName.Contains("example.com")) { defaultAcct = account; break; } } } void Inspectors_NewInspector(Inspector Inspector) { if (Inspector.CurrentItem is MailItem) { MailItem mailItem = Inspector.CurrentItem as MailItem; if (mailItem.Sent == false) { if (mailItem.SendUsingAccount != null) { if (mailItem.SendUsingAccount.DisplayName == "Public") { MessageBox.Show("In Public, set from to: " + defaultAcct.DisplayName); // shows every time mailItem.SendUsingAccount = defaultAcct; // Only gets set the first time } } } } } }
更新说明
测试时修改了代码,Subject每次都能正常设置,但SendUsingAccount仍仅首次生效:
void Inspectors_NewInspector(Inspector Inspector) { if (Inspector.CurrentItem is MailItem) { MailItem mailItem = Inspector.CurrentItem as MailItem; mailItem.SendUsingAccount = defaultAcct; mailItem.Subject = "test"; } }
问题原因及解决方法
问题出在NewInspector事件触发时机过早:当Outlook新建邮件时,NewInspector事件先触发,但此时MailItem的SendUsingAccount可能还未被Outlook完全初始化,或者后续Outlook会根据当前选中的账户重新覆盖这个值,导致你的设置被冲掉。而Subject没有这个问题,因为它不会被Outlook自动重置。
解决步骤:
- 在NewInspector事件中,不为MailItem直接设置SendUsingAccount,而是绑定它的
Open事件 - 在
Open事件处理函数中再执行SendUsingAccount的设置逻辑,此时MailItem已经完全加载,设置不会被覆盖 - 为避免重复绑定事件,可使用字典记录已处理过的MailItem
修改后的代码示例
public partial class ThisAddIn { private Account defaultAcct = null; private Inspectors inspectors; // 记录已绑定Open事件的MailItem,避免重复绑定 private Dictionary<MailItem, MailItemEvents_OpenEventHandler> _mailItemEvents = new Dictionary<MailItem, MailItemEvents_OpenEventHandler>(); private void ThisAddIn_Startup(object sender, System.EventArgs e) { inspectors = this.Application.Inspectors; inspectors.NewInspector += Inspectors_NewInspector; Accounts accounts = Application.Session.Accounts; foreach (Account account in accounts) { if(account.DisplayName.Contains("example.com")) { defaultAcct = account; break; } } } void Inspectors_NewInspector(Inspector Inspector) { if (Inspector.CurrentItem is MailItem mailItem && !mailItem.Sent) { // 检查是否已绑定过事件 if (!_mailItemEvents.ContainsKey(mailItem)) { MailItemEvents_OpenEventHandler openHandler = null; openHandler = (sender, ref bool cancel) => { var currentItem = sender as MailItem; if (currentItem != null && defaultAcct != null) { // 检查当前发件账户是否为Public if (currentItem.SendUsingAccount != null && currentItem.SendUsingAccount.DisplayName == "Public") { currentItem.SendUsingAccount = defaultAcct; } // 解绑事件,避免内存泄漏 currentItem.Open -= openHandler; _mailItemEvents.Remove(currentItem); } }; mailItem.Open += openHandler; _mailItemEvents.Add(mailItem, openHandler); } } } private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { // 清理事件绑定 foreach (var kvp in _mailItemEvents) { kvp.Key.Open -= kvp.Value; } _mailItemEvents.Clear(); } }
额外注意点
- 确保
defaultAcct正确获取到了目标账户,可在Startup中加日志或弹窗验证 - 处理Outlook的对象生命周期,及时解绑事件避免内存泄漏
- 若使用的是Outlook 2016及以上版本,也可以尝试监听
Application.ItemLoad事件,逻辑类似但触发时机更晚
内容的提问来源于stack exchange,提问作者Barry Ralphs
相关产品推荐
相关产品推荐

