VSTO: обработка почты с помощью newmailex перед правилами outlook переместить почту

Я создаю аддон для Outlook 2007, который считывает элемент почты при его получении, а затем перезаписывает его. Аддон отлично работает и переписывает почту для элементов, у которых нет правила Outlook, которое перемещает их в другую папку. Если есть правило, оно все равно прекрасно примерно в 50% случаев. В остальных 50% случаев правило перемещает почтовый элемент до завершения моего аддона. Я получаю следующую ошибку:

"операция не может быть выполнена, поскольку объект был удален."

Я использую событие NewMailEx для вызова моей функции перезаписи:

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
    this.Application.NewMailEx += new Outlook.ApplicationEvents_11_NewMailExEventHandler(olApp_NewMail);
}

в Outlook 2007 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, а также на моем компьютере), ища тот же почтовый идентификатор. Когда я, наконец, повторю, где почта, EntryID перемещенной почты очень отличается от entryIDCollection.

может быть, я иду по неправильному пути. Кто-нибудь знает, как остановить распространение события, пока я не закончу, или как отследить перемещенное письмо?

вот мой код для обхода папок в случае, если кому-то интересно:

        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) { }
            }

        }

2 ответов


Непроверенные Идеи : Если вы надежно получаете событие NewMailEx, отметьте почту свойством пользователя или пробегом с GUID, а затем используйте поиск для этого.

Это может не работать, так как вы не сможете войти до того, как правило перемещает почту.

Как вы разработали EntryId изменения whe элемент перемещается.

другой способ вам нужно посмотреть на реквизит MAPI, чтобы получить PR_SEARCH_KEY, который dosent изменяется при перемещении почты.


ответ 76mel работал отлично! Я публикую свой результирующий код на случай, если другие захотят сделать что-то подобное (я новичок и не уверен в правилах публикации большого количества кода, поэтому извините, если это противоречит правилам):

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) { }
        }

    }
}

кстати, что-то, что я, вероятно, изменю, я пропущу запрос определенных папок, чтобы ускорить его немного (журнал, удаленные элементы, нежелательная электронная почта, черновики, RSS-каналы, Microsoft Дома, задачи, заметки, контакты, календарь, отправленные элементы, исходящие).