VSTO:在outlook规则移动邮件之前使用newmailex处理邮件

VSTO:在outlook规则移动邮件之前使用newmailex处理邮件,outlook,vsto,Outlook,Vsto,我正在为Outlook2007创建一个插件,该插件在收到邮件时读取邮件,然后重写它。该插件工作得很好,可以为没有Outlook规则的项目重写邮件,从而将这些项目移动到另一个文件夹中。如果有规定的话,在50%的情况下仍然可以。另外50%的情况下,规则会在我的加载项完成之前移动邮件项目。我得到以下错误: “无法执行该操作,因为该对象已被删除。” 我正在使用NewMailEx事件调用我的重写函数: private void ThisAddIn_Startup(object sender, System

我正在为Outlook2007创建一个插件,该插件在收到邮件时读取邮件,然后重写它。该插件工作得很好,可以为没有Outlook规则的项目重写邮件,从而将这些项目移动到另一个文件夹中。如果有规定的话,在50%的情况下仍然可以。另外50%的情况下,规则会在我的加载项完成之前移动邮件项目。我得到以下错误:

“无法执行该操作,因为该对象已被删除。”

我正在使用NewMailEx事件调用我的重写函数:

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    this.Application.NewMailEx += new Outlook.ApplicationEvents_11_NewMailExEventHandler(olApp_NewMail);
}
在Outlook2007中,NewMailEx为邮件提供了一个entryID。此entryID最初用于确定要使用的邮件对象:

Outlook.NameSpace outlookNS = this.Application.GetNamespace("MAPI");
Outlook.MAPIFolder mFolder = this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
Outlook.MailItem mail;
try
{
    mail = (Outlook.MailItem)outlookNS.GetItemFromID(entryIDCollection, Type.Missing);
}
catch (Exception e) { Debug.WriteLine("exception with non-mail item " + entryIDCollection + ": " + e.ToString()); return; }
我想我可以使用这个entryID(上面的代码可以使用),然后遍历我的所有文件夹(在exchange上以及在我的计算机上),寻找相同的邮件id。当我最终遍历邮件所在的位置时,移动的邮件的entryID与EntrydCollection非常不同

也许我走错了方向。有人知道在我完成之前如何阻止事件传播,或者如何追踪移动的电子邮件吗

以下是我的代码,用于在任何人好奇时遍历文件夹:

        try
        {
            mail.Subject = new_subj;
            mail.Body = "";
            mail.HTMLBody = text;
            mail.ClearConversationIndex();
            mail.Save();
        }
        catch (Exception ex)
        {
            //It wasn't caught in time, so we need to find the mail:
            ArrayList unreadFolders = new ArrayList();
            foreach (Outlook.Folder f in outlookNS.Folders) unreadFolders.Add(f);

            while (unreadFolders.Count > 0)
            {
                Outlook.Folder currentFolder = unreadFolders[0] as Outlook.Folder;
                Debug.WriteLine("reading folder: " + currentFolder.Name);
                unreadFolders.RemoveAt(0);


                foreach (Outlook.Folder f in currentFolder.Folders) unreadFolders.Add(f);

                try
                { 
                    Outlook.Items items = currentFolder.Items.Restrict("[UnRead] = true");
                    for (int itemNum = 1; itemNum <= items.Count; itemNum++)
                    {
                        if (!(items[itemNum] is Outlook.MailItem)) continue;
                        Outlook.MailItem m = items[itemNum];
                        if (m.EntryID == entryIDCollection)
                        {
                            m.Subject = new_subj;
                            m.Body = "";
                            m.HTMLBody = text;

                            m.ClearConversationIndex();
                            m.Save();
                            return;
                        }

                    }
                }
                catch (Exception exc) { }
            }

        }
试试看
{
mail.Subject=新主题;
mail.Body=“”;
mail.HTMLBody=文本;
mail.ClearConversationIndex();
mail.Save();
}
捕获(例外情况除外)
{
//没有及时收到,所以我们需要找到邮件:
ArrayList unreadFolders=新建ArrayList();
foreach(outlookNS.Folders中的Outlook.Folders)未读文件夹。添加(f);
while(unreadFolders.Count>0)
{
Outlook.Folder currentFolder=未读文件夹[0]作为Outlook.Folder;
Debug.WriteLine(“读取文件夹:+currentFolder.Name”);
未读文件夹。删除(0);
foreach(currentFolder.Folders中的Outlook.Folder f)未读文件夹。添加(f);
尝试
{ 
Outlook.Items=currentFolder.Items.Restrict(“[UnRead]=true”);

对于(int itemNum=1;itemNum未经测试的想法:如果您可靠地获取了NewMailEx事件,请使用用户属性或带有GUID的里程数标记邮件,然后使用Search进行搜索

这可能不起作用,因为在规则移动邮件之前,您可能无法进入

正如您计算出的,当项目移动时,EntryId会发生变化


另一方面,您需要查看MAPI道具,以获取在邮件移动时会发生更改的PR_搜索键。

76mel的答案非常有效!我正在发布生成的代码,以防其他人想做类似的事情(我是新手,不确定发布大量代码的规则,如果违反规则,请道歉):

私有字符串getPRSearchKey(Outlook.MailItem m)
{
返回m.PropertyAccessor.BinaryToString(m.PropertyAccessor.GetProperty(“http://schemas.microsoft.com/mapi/proptag/0x300B0102"));
}
私有void olApp_NewMail(字符串entrydcollection)
{
Outlook.NameSpace outlookNS=this.Application.GetNamespace(“MAPI”);
Outlook.MAPIFolder mFolder=this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
Outlook.MailItem邮件;
字符串搜索键;
串旧主题;
串旧_体;
尝试
{
mail=(Outlook.MailItem)outlookNS.GetItemFromID(entryIDCollection,Type.Missing);
pr_search_key=getprsearch key(邮件);
//在移动邮件项之前保存pr_搜索键、主题和正文
//这样我们就不用担心它们消失了
旧主题=mail.Subject;
old_body=mail.body;
}
catch(异常e){Debug.WriteLine(“非邮件项异常”+entrydcollection+”:“+e.ToString());return;}
//
//…处理邮件的正文和主题
//
尝试
{
mail.Subject=新主题;
mail.Body=“”;
mail.HTMLBody=文本;
mail.ClearConversationIndex();
mail.Save();
}
捕获(例外情况除外)
{
//没有及时收到,所以我们需要找到邮件:
ArrayList unreadFolders=新建ArrayList();
foreach(outlookNS.Folders中的Outlook.Folders)未读文件夹。添加(f);
while(unreadFolders.Count>0)
{
Outlook.Folder currentFolder=unreadFolders[unreadFolders.Count-1]作为Outlook.Folder;
Debug.WriteLine(“读取文件夹:+currentFolder.Name”);
unreadFolders.RemoveAt(unreadFolders.Count-1);
foreach(currentFolder.Folders中的Outlook.Folder f)未读文件夹。添加(f);
尝试
{ 
Outlook.Items=currentFolder.Items.Restrict(“[UnRead]=true”);

对于(int itemNum=1;itemNum太好了!我让它在收到邮件时抓取PR_SEARCH_键。我还抓取了正文和主题。然后我修改了主题和主体。当我尝试更新正文/主题时,失败了,我让它搜索文件夹并找到匹配的邮件。虽然PR_SEARCH_键在邮件项目被复制(两个副本可能共享相同的PR_SEARCH_键),这很好,因为当它出现时,我还没有复制任何副本。我尝试对此进行投票,但我太新了,无法投票:(我会在下面发布我的代码(没有注释字符)而且,有时当我收到newmailex时,邮件已经被移动了(稍后发现)。我修改了第一个catch语句,以便如果pr_search_key==“”,抓取所有未读的邮件,看看我是否修改了它们…我有点烦。我看到的另一个问题是,当我的电脑从睡眠中醒来时,收到的任何新邮件都不会发送newmailex,因此所有这些邮件都会丢失。非常烦人的是,这个答案很简单
private string getPRSearchKey(Outlook.MailItem m)
{
    return m.PropertyAccessor.BinaryToString(m.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x300B0102"));
}

private void olApp_NewMail(string entryIDCollection)
{
    Outlook.NameSpace outlookNS = this.Application.GetNamespace("MAPI");
    Outlook.MAPIFolder mFolder = this.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
    Outlook.MailItem mail;

    string pr_search_key;
    string old_subj;
    string old_body;
    try
    {
        mail = (Outlook.MailItem)outlookNS.GetItemFromID(entryIDCollection, Type.Missing);
        pr_search_key = getPRSearchKey(mail);
        //save the pr_search_key, subject, and body before the mailItem gets moved
        // then we can work on it without worrying about them disappearing
        old_subj = mail.Subject;
        old_body = mail.Body;
    }
    catch (Exception e) { Debug.WriteLine("exception with non-mail item " + entryIDCollection + ": " + e.ToString()); return; }

    //
    // ... do stuff with the mail's body and subject
    //

    try
    {
        mail.Subject = new_subj;
        mail.Body = "";
        mail.HTMLBody = text;

        mail.ClearConversationIndex();
        mail.Save();
    }
    catch (Exception ex)
    {
        //It wasn't caught in time, so we need to find the mail:
        ArrayList unreadFolders = new ArrayList();
        foreach (Outlook.Folder f in outlookNS.Folders) unreadFolders.Add(f);

        while (unreadFolders.Count > 0)
        {
            Outlook.Folder currentFolder = unreadFolders[unreadFolders.Count-1] as Outlook.Folder;
            Debug.WriteLine("reading folder: " + currentFolder.Name);
            unreadFolders.RemoveAt(unreadFolders.Count - 1);


            foreach (Outlook.Folder f in currentFolder.Folders) unreadFolders.Add(f);

            try
            { 
                Outlook.Items items = currentFolder.Items.Restrict("[UnRead] = true");
                for (int itemNum = 1; itemNum <= items.Count; itemNum++)
                {
                    if (!(items[itemNum] is Outlook.MailItem)) continue;
                    Outlook.MailItem m = items[itemNum];
                    if (getPRSearchKey(m) == pr_search_key)
                    {
                        m.Subject = new_subj;
                        m.Body = "";
                        m.HTMLBody = text;

                        m.ClearConversationIndex(); //don't think this works
                        m.Save();
                        return;
                    }

                }
            }
            catch (Exception exc) { }
        }

    }
}