Outlook-Redemption - RDOFolder.Items ItemAdd Событие не вызывается регулярно с Exchange в онлайн-режиме - PullRequest
0 голосов
/ 15 апреля 2020

Системная среда:

Windows 10 Pro - Версия: 1909 - Сборка ОС: 18363,752
Microsoft Outlook 2019 MSO - Версия 1808 - 32-разрядная
Сборка Microsoft Exchange 2016 15.1 (Сборка 1979.3)
- Microsoft Exchange установлен на Microsoft Server 2016
COM-библиотека погашения Outlook - версия 5.22.0.5498

Краткое описание проблемы:

Приложение отправляет электронные письма через Outlook, используя COM-библиотеку Outlook-Redemption. Класс "RedemptionHandler" - это наш класс Singleton, который взаимодействует с COM-библиотекой Outlook-Redemption. Во время создания RedemptionHandler мы создаем RDOSession с классом stati c с именем RedemptionLoader и вызываем Logon () в RDOSession. RDOSession впоследствии используется в Initialize () для получения папок для черновиков и отправляемых писем.

public static class RedemptionLoader
{
   public static RDOSession new_RDOSession()
   {
      return (RDOSession)NewRedemptionObject(new Guid("29AB7A12-B531-450E-8F7A-EA94C2F3C05F"));
   }
}
public class RedemptionHandler
{
   private static RedemptionHandler instance = null;
   private static readonly object padlock = new object();

   private RDOSession _rdoSession;
   private RDOFolder _rdoSentFolder;
   private RDOFolder _rdoDraftsFolder;
   private RDOItems _sentItems = null;

   public EventHandler<MailGesendetEventArgs> MailSuccessfullySent;

   private RedemptionHandler()
   {
      _rdoSession = RedemptionLoader.new_RDOSession();
      _rdoSession.Logon(null, null, false, null, null, null);
      Initialize();
   }

   public static RedemptionHandler Instance
   {
     get
     {
        lock (padlock)
        {
           if (instance == null)
           {
              instance = new RedemptionHandler();
           }
           return instance;
         }
     }
   }

   private void Initialize()
   {
      try
      {
         if (isInitialized) return;
        _rdoSentFolder = _rdoSession.GetDefaultFolder(Redemption.rdoDefaultFolders.olFolderSentMail);
        _sentItems = _rdoSentFolder.Items;
        _sentItems.ItemAdd += MailSent;
        _rdoDraftsFolder = _rdoSession.GetDefaultFolder(Redemption.rdoDefaultFolders.olFolderDrafts);
         isInitialized = true;
      }
      catch
      {
         //TODO
         isInitialized = false;
      }
   }
}

На данный момент у нас есть рабочий экземпляр от нашего RedemptionHandler. COM-объект RDOSession создается и на него ссылаются так же, как и RDOFolder для черновиков и отправленных. Мы также зарегистрировали прослушиватель событий для Sent-Folder для распознавания новых писем в этой папке.

На следующих шагах мы хотим отправить электронное письмо и распознать это письмо, если оно хранится в отправленной папке. Мы используем RDOMail.Fields - Свойство для хранения пользовательских данных в RDOMail-Object.

public RDOMail CreateMail(string recipient, string subject, string body, Guid gdSender, string storagePath)
{
    RDOMail newMail = _rdoDraftsFolder.Items.Add(Redemption.rdoItemType.olMailItem);
    newMail.Recipients.Add(recipient);
    newMail.Recipients.ResolveAll();
    newMail.Subject = subject;
    newMail.HTMLBody = body;
    newMail.BodyFormat = (int)rdoBodyFormat.olFormatHTML;

    // Here we want to store an identifier in the RDOMail.Fields
    int id = newMail.GetIDsFromNames(PropertyGuid, PropertyGdItemId);
    newMail.Fields[id] = Guid.NewGuid().ToString();

    return newMail;
}

После создания почты мы хотим отображать почту пользователю, потому что мы не хотим отправлять данные без разрешения пользователь знает об этом.

public void DisplayMail(RDOMail mail, bool modal = false)
{
     mail.Display(modal, null);
}

Теперь окно Outlook выходит вперед, и пользователь проверяет почту и нажимает кнопку «Отправить».

Почта теперь сохраняется в папке «Отправленные».

Событие MailSent вызывается слушателем RDOFolder.Items.Add.

private void MailSent(RDOMail mail)
{
  var test = mail.Fields[SenderId];
  Console.WriteLine(test);
  // test value is correct!
}

Разница между Exchange в онлайн-режиме и режиме кэширования:

Если мы используем Обмен с Cache-Mode, все отлично работает. Каждый раз, когда мы отправляем электронное письмо, MailSent срабатывает, и мы можем читать данные из свойства RDOMail.Fields-Property. Если мы переключаемся на Exchange без кэша, событие MailSent запускается только один раз, когда отправляется первая почта. Все электронные письма после войны отправляются, но не вызывают событие MailSent. Если мы удаляем эту строку кода, все работает также без Cache-Mode.

var test = mail.Fields[SenderId];

Это потому, что мы думаем, что чтение данных из RDOMail.Fields - Property делает что-то особенное, если кеш-режим из обмен деактивирован.

Нам нужно хранить пользовательские данные в почтовых сообщениях, чтобы проверить, создаются ли новые сообщения в отправляемой папке нашим приложением или нет.

Мы высоко ценим помощь и советы.

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Я пытался решить эту проблему без успеха. Я настроил новый проект без какого-либо другого кода:

public partial class RedemptionTest : Form
    {
        static RDOSession _rdoSession;
        static RDOFolder _rdoSentFolder;
        static RDOFolder _rdoDraftsFolder;
        static RDOItems _draftItems;
        static RDOItems _sentItems;

        public RedemptionTest()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            _rdoSession = RedemptionLoader.new_RDOSession();
            _rdoSession.Logon();
            _rdoSentFolder = _rdoSession.GetDefaultFolder(rdoDefaultFolders.olFolderSentMail);
            _rdoDraftsFolder = _rdoSession.GetDefaultFolder(rdoDefaultFolders.olFolderDrafts);
            _sentItems = _rdoSentFolder.Items;
            _draftItems = _rdoDraftsFolder.Items;
            _draftItems.ItemAdd += DraftAdd;
            _sentItems.ItemAdd += MailSent;
        }

        private void DraftAdd(RDOMail Item)
        {
            Console.WriteLine(Item.Subject);
        }

        private void MailSent(RDOMail Item)
        {
            Console.WriteLine(Item.Subject);
        }

    }

Событие Drafts-Folder вызывается постоянно, а событие MailSent запускается только в первый раз. Я сохранил все RDO-объекты в переменных stati c, чтобы избежать их сбора мусора.

0 голосов
/ 15 апреля 2020

Объект, вызывающий события (RDOItems), должен быть жив, чтобы иметь возможность запускать события. Ваш код использует многоточечную запись, что означает, что компилятор создает неявную переменную для хранения коллекции RDOItems. Как только эта переменная будет освобождена сборщиком мусора, никакие события не будут запущены.

Строка

_rdoSentFolder.Items.ItemAdd += MailSent;

должна быть изменена на

RDOItems _sentItems; //global/class variable
..
_sentItems = _rdoSentFolder.Items;
_sentItems .ItemAdd += MailSent;
...