VSTO: обработка почты с использованием newmailex до того, как правила Outlook переместят почту - PullRequest
8 голосов
/ 20 февраля 2010

Я создаю аддон для 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 предоставляет запись ID для почты.Этот 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 (который работает в приведенном выше коде) и перебрать все мои папки (при обмене нану как на моем компьютере) искал тот же почтовый идентификатор.Когда я, наконец, перехожу туда, где находится почта, 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 ]

5 голосов
/ 21 февраля 2010

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 дома, Задачи, Заметки, Контакты, Календарь, Отправленные, Исходящие).

5 голосов
/ 20 февраля 2010

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

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

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

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

...