0
votes

System-Environment:

Windows 10 Pro - Version: 1909 - OS System Build: 18363.752
Microsoft Outlook 2019 MSO - Version 1808 - 32-Bit
Microsoft Exchange 2016 15.1 Build (Build 1979.3)
-- Microsoft Exchange is installed on Microsoft Server 2016
Outlook Redemption COM-Library - Version 5.22.0.5498

Issue Summary:

The application sends emails via Outlook using the Outlook-Redemption COM-Library. The class "RedemptionHandler" is our Singleton-Class which interacts with the Outlook-Redemption COM-Library. During the construction of the RedemptionHandler we create a RDOSession with a static class named RedemptionLoader and call Logon() on the RDOSession. The RDOSession is used afterwards in Initialize() to retrieve the Folders for Drafts and mails which are sent.

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;
      }
   }
}

At this point, we have a working instance from our RedemptionHandler. The COM-Object RDOSession is created and referenced within just as the RDOFolder for Drafts and Sent. We have also registrered an event-listener for the Sent-Folder to recognize new Mails in this folder.

In the next steps we want to send an email and recognize this email if its stored in the sent-folder. We use the RDOMail.Fields - Property to store custom data within the 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;
}

After the mail creation we want to display the mail to the user because we dont want to send data without letting the user know about it.

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

The Outlook window now comes to front and the user checks the mail and clicks on send.

The Mail is now stored in the Sent-Folder.

The MailSent Event gets invoked by the RDOFolder.Items.Add Listener.

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

Difference between Exchange in Online-Mode and Cache-Mode:

If we use the Exchange with Cache-Mode, everything works fine. Everytime we send an email, the MailSent is triggered and we can read data from the RDOMail.Fields-Property. If we switch to Exchange without Cache, the MailSent Event is triggered only once, when the first mail is sent. All emails afterwars are sent but dont trigger the MailSent-Event. If we delete this line of code, everything works also fine without Cache-Mode.

var test = mail.Fields[SenderId];

This is because we think that reading data from the RDOMail.Fields - Property does something special if the cache-mode from exchange is deactivated.

We need to store custom data within the mails to check if new mails in the sent-folder are created by our application or not.

We highly appreciate help and hints.

3

3 Answers

1
votes

I tried to fix this issue without success. I've set-up a new Project without any other code:

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

    }

The Drafts-Folder Event is fired all the time, the MailSent Event is only fired the first time. I have stored all RDO-Objects in static variables to avoid them from being garbage collected.

0
votes

The object raising the events (RDOItems) must be alive be able to fire the events. Your code is using multiple dot notation, which means the compiler creates an implicit variable to hold the RDOItems collection. As soon as that variable is released by the Garbage Collector, no events will be fired.

The line

_rdoSentFolder.Items.ItemAdd += MailSent;

must be changed to

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

Have the same issue in Outlook VSTO add-in using Redemption. Happens for both Sent and Inbox folder. The same code works correctly in cached mode but fires events only once in Online mode. Native Outlook object model Items.ItemAdd works correctly in Online mode for the same folder.

Currently, we were able to do a workaround for this by unsubscribing and resubscribing to event right in the event handler. Like this:

private void SentItems_ItemAdd(RDOMail rdoMail)
{
    _sentItems.ItemAdd -= SentItems_ItemAdd;
    _sentItems.ItemAdd += SentItems_ItemAdd;

    Log.Debug("SentItems.ItemAdd");
    SentMailItemAdd?.Invoke(rdoMail);
}