none
Outlook duplicates my mailitem in cached mode on send? RRS feed

  • Question

  • Hello,

    I'm intercepting the "Send" button of Outlook to convert the e-mail the user tries to send. In this moment, I read content, convert it and replace attachments etc. This needs about two or more seconds (depending on the content).

    If the account is configured to work in cached mode, it now creates duplicates of the message. The recipient (and my send items) now getting the message in original format and the converted one. It looks like Outlook created some copy of the MailItem before my work and also sent this one. Turning cached mode off, solves the problem.

    Is anyone having an idea about how to stop this behaviour? Customer wants to use the cached mode (what I fully understand).

    Thanks!

    Friday, November 29, 2013 11:43 AM

All replies

  • Hello Schlangengott,

    >> I'm intercepting the "Send" button of Outlook to convert the e-mail the user tries to send.

    The proper solution is to use the ItemSend event of the Application class in Outlook. Do you get the same results with ItemSend?

    BTW Do you have any other COM add-ins registered for Outlook? What Outlook version do you have installed?

    Friday, November 29, 2013 11:59 AM
  • Please show the relevant snippet of your code.

    What exactly do you mean by "I'm intercepting the "Send" button"? Are you using a mouse hook to intercept the click event? Or you actually use Application.ItemSend or MailItem.Send events?


    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Friday, November 29, 2013 5:00 PM
  • I'm using the MailItem.Send event. Currently, I try to change a test tool to use the Application.SendItem function. If this helps, I have to change a lot :-(

    I will report, if it helped. But this may need a few weeks as I can not work fulltime on this.

    Thanks!

    Thursday, December 5, 2013 7:06 AM
  • Please show your code...

    Dmitry Streblechenko (MVP)
    http://www.dimastr.com/redemption
    Redemption - what the Outlook
    Object Model should have been
    Version 5.5 is now available!

    Thursday, December 5, 2013 4:38 PM
  • Hello Dmitry,

    I now changed the AddIn to use Application.ItemSend instead of MailItem.Send, but problems still occur. As it is a lot of code, I try to show some reduced set to explain what I'm doing (I replaced product name with ABC):

    The user is having two choices: (A) press "New Email" as standard or (B) choose "New ABC Email". In case of (B) I do the following:

    NewMailItem = MyApplication.CreateItem(Outlook.OlItemType.olMailItem)
    rgfProperty = NewMailItem.UserProperties.Add("SendAsABC", Outlook.OlUserPropertyType.olYesNo)
    rgfProperty.Value = True
    NewMailItem.Save()
    NewMailItem.Display()
    Connect.ABCToCleanup.Add(NewMailItem.EntryID)
    NewMailItem = Nothing
    rgfProperty = Nothing

    The Dialog now offers the user two choices again: (1) press "Send" or (2) press "send ABC" (which is our own button). Thus, we have different situations:

    User has chosen (A) and now is choosing (1): Nothing to do, standard email.
    User has chosen (A) and now is choosing (2): Need to convert
    User has chosen (B) and now is choosing (1): Need to convert
    User has chosen (B) and now is choosing (2): Need to convert

    Case (B) + (1) is the reason for setting the user property. With this, I can find out later that it needs to get converted.

    In case of (1), I'm checking about the property in Application_ItemSend() event:
    If Item.Class <> Outlook.OlObjectClass.olMail Then
        Return ' only working with email
    End If
    
    Dim rgfProperty As Outlook.UserProperty = Item.UserProperties.Find("SendAsABC")
    If rgfProperty Is Nothing Then
        Return
    End If
    If rgfProperty.Value = True Then
        ' send as ABC!
        Item = ABC_Make(Item)
        If Item Is Nothing Then
            Cancel = True ' do not continue
        End If
    End If
    rgfProperty = Nothing
    If the user has chosen (2) (button "send ABC"), I do the following in the Event of the button:

    ABC_Make(MailItem)

    Inside of the ABC_Make(MailItem) function, I do the conversion and also reset the property (this avoids double conversion in Application_ItemSend() later).

    The problems might happen inside of the ABC_Make() function. There is a lot of code inside, but this is done in short:
    ' Set Redemption SafeMailItem reference
    MailItem.Save()
    roMail.Item = MailItem
    
    ' (resolve subject, body, attachments etc.)
    ' (save extracted content to temporary files)
    
    ' Calling external executable to take all temporary files and convert it to
    ' some encrypted message container.
    
    ' Close inspector window
    MailItem.GetInspector.Close(Outlook.OlInspectorClose.olDiscard)
    
    ' Replace Body with template
    roMail.Item.HTMLBody = Template
    roMail.Save()
    
    ' delete all old attachments of this e-mail
    For x = roMail.Attachments.Count To 1 Step -1
        roMail.Attachments.Item(x).Delete()
    Next x
    
    ' add the generated ABC-file ( RGFFilename ) as new (and only) attachment
    Dim rgfAttachment As Outlook.Attachment = roMail.Attachments.Add(RGFFilename, Outlook.OlAttachmentType.olByValue, 1)
    
    ' set mime-type to vnd.ABC
    rgfAttachment.Fields(&H370E001E) = "application/vnd.ABC"
    
    rgfAttachment = Nothing
    SafeUser = Nothing
    
    roMail.Save()
    
    ' Make this a mail item (1st workaround for winmail.dat sending)
    roMail.Fields(PR_MESSAGE_CLASS) = "IPM.Note" ' prevent sending winmail.dat!
    
    ' Try to force OL to not use TNEF encoding in any case! (2nd workaround)
    Const PT_BOOLEAN As Integer = &HB
    Dim pr_UseTnef As Integer
    pr_UseTnef = roMail.GetIDsFromNames("{00062008-0000-0000-C000-000000000046}", &H8582) Or PT_BOOLEAN
    roMail.Fields(pr_UseTnef) = False
    
    Dim rgfProperty As Outlook.UserProperty = MailItem.UserProperties.Find("SendAsABC")
    If Not rgfProperty Is Nothing Then
        If rgfProperty.Value = True Then
            ' to prevent double conversion if "New ABC Email" is combined with
            ' "send ABC" button in ThisAddIn.Application_ItemSend
            rgfProperty.Value = False
        End If
    End If

    This are the symptoms on some IMAP account:
    - Sometimes, an unencrypted version stays in draft folder.
    - Sometimes, the message is sent as winmail.dat.

    What are the mistakes?

    Thanks you!
    Wednesday, December 11, 2013 11:12 AM
  • Hello Schlangengott,

    First of all, if you develop an add-in or automate Outlook from a standalone app I would recommend releasing underlying COM objects instantly. For example:

    NewMailItem.UserProperties.Add("SendAsABC", Outlook.OlUserPropertyType...)

    The UserProperties property of the MailItem class returns an instance of the UserProperties class which should be released after. Moreover, the Add method of the UserProperties class returns a new instance of the UserProperty class which is not released too. The Marshal.releaseComObject is used for this.

    Item.UserProperties.Find("SendAsABC")
    

    An instance of the UserProperties class is not released there too. Note, the Find method returns an instance of the UserProperty class which should be released after.

    Finally, you need to inspect the code of your add-in and add statements for releasing all underlying COM objects. Note, each object you get from the Outlook Object Model is an RCW which has a corresponding COM object.

    Wednesday, December 11, 2013 3:38 PM
  • Hello Eugene. I understand and I will try to update the code like this. But two questions:

    1. Shouldn't a language like .NET automatically clean up local used objects and references at the end of the function/sub? I think this is why garbage collection was invented? Or does the RCW stay and will get re-used later?
    2. I did not experience any issues about unreleased objects in the past. The AddIn functionality is fine on POP3 accounts and the AddIn unloads perfectly if Outlook closes (no processes left etc). Do you think this might be the reason for one of my problems (duplicate items on IMAP accounts)?

    Thanks!

    Thursday, December 12, 2013 7:06 AM
  • Hello Schlangengott,

    1. Theoretically the GC swipes the heap and all underlying COM objects are released at that time. But you don't know when exactly it happens. For example, you send a message and do some stuff in the ItemSend event handler. If you don't release connected objects (for example, the user properties collection) a mail will not be unloaded in time. That is why I always recommend releasing Outlook objects instantly. There are two ways:

    • Set the referenced object to null and call GC.Collect and GC.WaitForPendingFinalizers twice.
    • Use the Marshal.ReleaseComObject method.

    2. Who knows :) To exclude this factor you need to review the source code and release all underlying COM objects instantly.

    Thursday, December 12, 2013 8:04 AM
  • I just read some articles about Marshal.ReleaseComObject(). So do you think I should use Marshal.ReleaseComObject(myUserProperties) instead of myUserProperties = Nothing? Or do I need to set myUserProperties = Nothing after releasing the COM object in addition?

    Also found the function Marshal.FinalReleaseComObject(). Shouldn't I use this one to make sure? Or is this no good idea?

    http://msdn.microsoft.com/de-de/library/system.runtime.interopservices.marshal.finalreleasecomobject%28v=vs.90%29.aspx

    Kind regards



    Thursday, December 12, 2013 10:16 AM
  • Just setting managed references to null (Nothing in VB.NET) will not release an underlying COM object until the garbage collector is run. 

    Thursday, December 12, 2013 11:20 AM