none
How to retrieve mailItem.BillingInformation programmatically RRS feed

  • Question

  • In this project the user creates a document in a (DevExpress) word processor and then has the option to e-mail the document as an attachment. The customer uses Outlook, the Sent Mail folder being evidence that a mail was sent to the recipient. The word processor document is stored in a SQL database, and the user would like the option to store/recall the summary of the associated e-mail. The program opens Outlook, does the attachment and leaves it to the user to fill in the rest (To, Body, etc). I want to use the Billing Information text field to insert a key linking the e-mail and documents together.

    This is what I do (note that I try both the Billing and Mileage fields):

        mailItem = DirectCast(clsobjOutLook.CreateItem(Outlook.OlItemType.olMailItem), Outlook.MailItem)
        attAttachments = mailItem.Attachments
        attAttachments.Add(pstrSourceFile, Outlook.OlAttachmentType.olByValue, 1, clsstrInputDoc)
        mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML
        mailItem.To = ""
        mailItem.Importance = Outlook.OlImportance.olImportanceHigh
        mailItem.ReadReceiptRequested = True
        mailItem.BillingInformation = clsstrEstRefNo
        mailItem.Mileage = clsstrEstRefNo
        mailItem.Display(True)

    ' The user now deals with the mail item and sends it. The program now picks up:

        objSentFolder = clsobjOutLook.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail)
        sentItems = objSentFolder.Items
        folderItem = sentItems.GetFirst
        While folderItem IsNot Nothing
          sentItem = TryCast(folderItem, Outlook.MailItem)
          If sentItem IsNot Nothing Then
            If sentItem.BillingInformation = clsstrEstRefNo OrElse sentItem.Mileage = clsstrEstRefNo Then
              strTest += vbCrLf & sentItem.Subject          ' Used for development only!!!
            End If
          End If
          folderItem = sentItems.GetNext
        End While
        strTest = "Estate Mail: " & strTest
        MsgBox(strTest)

    Whilst the mailing and scanning of the folder all works, I cannot find the value supposedly stored in the billing field! I get the subject field etc, but not the Billing (or Mileage) field.

    Any ideas? Am I using the wrong field? Any other fields available?

    Regards

    Axel Trunk

    Tuesday, April 19, 2016 12:23 PM

Answers

  • Hi Axel,

    It seems you have found a solution, am I right? If so, I suggest you mark the helpful reply as answer to close this thread. If not, please feel free to let us know your current issue.

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    • Marked as answer by Axel Trunk Monday, April 25, 2016 8:33 AM
    Monday, April 25, 2016 2:50 AM

All replies

  • I wish to use the 'Billing Information' field to store a reference value with an e-mail that will allow me to associate this particular e-mail with an entity in the system (more specifically an Estate in a Deceased Estate Management system) when I scan the 'SentMail' folder after sending (a customer request). I do the following (note that also tried the 'Mileage' field):

        mailItem = DirectCast(clsobjOutLook.CreateItem(Outlook.OlItemType.olMailItem), Outlook.MailItem)
        attAttachments = mailItem.Attachments
        attAttachments.Add(pstrSourceFile, Outlook.OlAttachmentType.olByValue, 1, clsstrInputDoc)
        mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML
        mailItem.To = ""
        mailItem.Importance = Outlook.OlImportance.olImportanceHigh
        mailItem.ReadReceiptRequested = True
        mailItem.BillingInformation = clsstrEstRefNo
        mailItem.Mileage = clsstrEstRefNo
        mailItem.Display(True)
    '
        objSentFolder = clsobjOutLook.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail)
        sentItems = objSentFolder.Items
        folderItem = sentItems.GetFirst
        While folderItem IsNot Nothing
          sentItem = TryCast(folderItem, Outlook.MailItem)
          If sentItem IsNot Nothing Then
            If sentItem.BillingInformation = clsstrEstRefNo OrElse sentItem.Mileage = clsstrEstRefNo Then
              strTest += vbCrLf & sentItem.Subject 'This is just for development!!!
            End If
          End If
          folderItem = sentItems.GetNext
        End While
        strTest = "Estate Mail: " & strTest
        MsgBox(strTest)

    The e-mail is sent successfully but neither the Billing nor Mileage seems to go through. The folder scanning works, but I cannot retrieve the fields.

    Any ideas?

    Regards,

    Axel Trunk

    Monday, April 18, 2016 4:50 PM
  • Hi Axel Trunk,

    This forum is discuss Visual Studio WPF/SL Designer, Visual Studio Guidance Automation Toolkit, Developer Documentation and Help System, and Visual Studio Editor.

    Since your problem is related to Outlook development, I help you move this thread to outlook development forum for a better help. Thanks for your understanding.

    Best Regards,
    Weiwei


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.

    Click HERE to participate the survey.


    • Edited by Weiwei Cai Tuesday, April 19, 2016 3:17 AM
    Tuesday, April 19, 2016 3:17 AM
  • Hello,

    I am moving your question to the Outlook for Developer forum as there are more expertise in this forum for this question.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Tuesday, April 19, 2016 12:31 PM
  • Thank you. MSDN is new to me and I am still stumbling around.
    Tuesday, April 19, 2016 1:13 PM
  • Thank you. I am rather new to MSDN and can't quite yet find my way around. I apologize for not acknowledging your reply in good time.
    Tuesday, April 19, 2016 1:17 PM
  • Where are you checking the Mileage value? Do you see it in OutlookSpy (select the item, click Item button, select the Mileage property)?

    Keep in mind that named MAPI property can be lost when sent through SMTP, so the property most likely will not be present on the message in the recipient's Inbox folder.


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

    Tuesday, April 19, 2016 5:14 PM
  • I do not look for it in Outlook itself, but search for it programmatically.

    I am now also investigating User Properties. Hope to get somewhere with that.

    Tuesday, April 19, 2016 5:18 PM
  • Hi Axel,

    >> I cannot find the value supposedly stored in the billing field! I get the subject field etc, but not the Billing (or Mileage) field.

    Based on the code, it seems you send an email with BillingInformation, and then retrieve BillingInformation in sent Items folder, am I right? What is your project type? I made a simple demo to achieve your requirement with VBA below:

    Sub Billing()
    
    Dim item As Outlook.MailItem
    
    Set item = Application.CreateItem(olMailItem)
    
    With item
    
        .To = "v-tazho@hotmail.com"
    
        .Subject = "test"
    
        .BillingInformation = "this is Bill"
    
        .Mileage = "this is mileage"
    
        .Display
    
        .Send
    
    End With
    
    Sub getSendtBilling()
    
    Dim i As Outlook.Folder
    
    Dim item As Object
    
    Set i = Application.ActiveExplorer.Session.GetDefaultFolder(olFolderSentMail)
    
    For Each item In i.items
    
        If item.BillingInformation = "this is Bill" Then
    
            Debug.Print item.Mileage
    
        End If
    
    Next item
    
    End Sub
    

    I suggest you run retrieving code after you could find the sent item in outlook. You mean you could get subject but not BillingInformation, I suggest you debug your code and check whether the MailItem is what you want.

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    Wednesday, April 20, 2016 2:01 AM
  • Hi,

    I think I'm fairly loosing it. I now add (or so I believe) a user property to the mail created:

        mailItem = DirectCast(clsobjOutLook.CreateItem(Outlook.OlItemType.olMailItem), Outlook.MailItem)
        attAttachments = mailItem.Attachments
        attAttachments.Add(pstrSourceFile, Outlook.OlAttachmentType.olByValue, 1, clsstrInputDoc)
        mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML
        mailItem.To = ""
        mailItem.Importance = Outlook.OlImportance.olImportanceHigh
        mailItem.ReadReceiptRequested = True
        mailItem.BillingInformation = clsstrEstRefNo
        mailItem.UserProperties.Add("EstRefNo", Outlook.OlUserPropertyType.olText, False)
        mailItem.UserProperties("EstRefNo").Value = clsstrEstRefNo
        mailItem.Display(True)
    '
        System.Threading.Thread.Sleep(15000)
        objSentFolder = clsobjOutLook.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail)
        sentItems = objSentFolder.Items
        folderItem = sentItems.GetFirst
        While folderItem IsNot Nothing
          ProgressBarControl1.Increment(1)
          ProgressBarControl1.Update()
          sentItem = TryCast(folderItem, Outlook.MailItem)
          If sentItem IsNot Nothing Then
            objUserProperties = sentItem.UserProperties
            If objUserProperties.Count > 0 Then
              If (Not String.IsNullOrEmpty(sentItem.Subject) AndAlso sentItem.Subject.Contains("Billing")) Then
                strTest += vbCrLf + sentItem.Subject + ": " + objUserProperties("EstRefNo").Value
              End If
            End If
          End If
          folderItem = sentItems.GetNext
        End While
        If String.IsNullOrEmpty(strTest) Then
          strTest = "Estate Mail: " & vbCrLf & "Found nothing!"
        Else
          strTest = "Estate Mail: " & strTest
        End If
        MsgBox(strTest)

    I check that the userproperty IS added to mailItem.  Notice I still write to BillingInformation. This is the weird part: when I add a UserProperty to mailItem, the BillingInformation now appears in the Outlook e-mail. BUT THE USERPROPERTY CANNOT BE FOUND. I test for sentMail.UserProperties.Count > 0, and get nothing.

    What am I overlooking?

    Regards,

    Axel Trunk

    Thursday, April 21, 2016 10:15 AM
  • I just found OutlookSpy. I am now trying User Properties as well, and no, the UserProperty doesn't go through!!! But the really weird part is that when I go about creating a UserProperty, BillingInformation now ACTUALLY APPEARS in the recipient's mail. Given that I should not really use an existing field in the customer's Outlook I want to stick with User Properties. Just can't get it to work! They are duly included in the outgoing mail but simply don't seem to arrive, witness Spy.
    Thursday, April 21, 2016 11:44 AM
  • I also installed MFCMAPI,  to find that the user properties in fact do go through. They are identifiable in the 'Named prop name' column, prefixed with "sz:". Do you have any pointers how I can retrieve this?
    Thursday, April 21, 2016 12:44 PM
  • The named properties are preserved if the message is sent in the TNEF format (the infamous winmail.dat file). Is useTnef named property now set to true on the messages in the Sent Items folder? Outlook sets it if the message has user properties. You can set that property explicitly in your code using MailItem.PropertyAccessor.SetProperty.

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

    Thursday, April 21, 2016 1:57 PM
  • I cannot say whether the TNEF property is set. I cannot override the customer's Outlook settings. I am close to a solution though. Using MFCMapi I found that user properties have a schema name that starts with

    'http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}' followed by the property name e.g. '/EstRefNo'. By using mail item 'PropertyAccessor.GetProperty' I tracked down the elusive value.

    Side effect is that the search slows down considerably. This may not be an issue since I would have to delay searching adequately to confidently search the 'Sent' folder anyway.

    I need to do more testing.

    Thursday, April 21, 2016 4:46 PM
  • Why can't you look at the message with OutlookSpy (click IMessage) to see whether UseTnef is set? And why can't you set it to try on an outgoing message?

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

    Thursday, April 21, 2016 4:49 PM
  • Looking in IMessage, UseTnef = true, and the user properties appear there as well. Under Item,  UserProperties.Count = 0.
    Thursday, April 21, 2016 5:05 PM
  • Ok, so set the Mileage property and UseTnef properties before you send the message and you'll be all set.

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

    Thursday, April 21, 2016 5:15 PM
  • Tried that, using:

        mailItem.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/8582000B", True)
        mailItem.UserProperties.Add("EstRefNo", Outlook.OlUserPropertyType.olText, False)
        mailItem.UserProperties("EstRefNo").Value = clsstrEstRefNo

    but no success.

    Thursday, April 21, 2016 6:01 PM
  • The user properties will no be set on the target mailbox unless these properties were already mapped in that mailbox at least once.

    What about the BillingInformation and Mileage properties?


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

    Thursday, April 21, 2016 6:06 PM
  • I don't want to use BillingInformation if I can avoid it. Since I have no control whatsoever over the customer's Outlook I assume I can not reliably use SetProperty. Hopefully I can still use the slower option.
    Thursday, April 21, 2016 6:13 PM
  • Then you can set a named property in the PS_INTERNET_HEADERS namespace - it will either be carried over as a named property, or it will be available in the MIME headers (PR_TRANSPORT_MESSAGE_HEADERS) on the receiving side.


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

    Thursday, April 21, 2016 7:26 PM
  • I have put a halt to this for the time being. I am not really satisfied with any solution and will look for another way of dealing with the customer's requirement. For what it's worth this is what I found the least intrusive solution (note this is development code!):

    ... 'When creating the e-mail

        mailItem.UserProperties.Add("ESTID", Outlook.OlUserPropertyType.olInteger, False)
        mailItem.UserProperties("ESTID").Value = clslngESTID
    ... ' When scanning the

        objaSchemaNames(0) = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/ESTID"
        objSentFolder = clsobjOutLook.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail)
        sentItems = objSentFolder.Items
        folderItem = sentItems.GetFirst
        sentItem = TryCast(clsobjOutLook.Application.CreateItem(Outlook.OlItemType.olMailItem), Microsoft.Office.Interop.Outlook.MailItem)
        While folderItem IsNot Nothing
          sentItem = TryCast(folderItem, Outlook.MailItem)
          If sentItem IsNot Nothing Then
            objPropAccessor = sentItem.PropertyAccessor
            If Not IsNothing(objPropAccessor) Then
              objESTID = GetPropValue(objPropAccessor, objaSchemaNames(0))
            End If
            If Not IsNothing(objESTID) Then
              If (Not String.IsNullOrEmpty(sentItem.Subject)) Then
                strTest += vbCrLf + sentItem.Subject + ": ESTID = " + objESTID.ToString
              End If
            End If
          End If
          folderItem = sentItems.GetNext
        End While
    ....

    Private Function GetPropValue(pobjPropAccessor As Outlook.PropertyAccessor, pobjSchema As Object) As Object
    ' Searching for the schema is taken out of the Try-Catch block.
    ' When the schema doesn't exist (as will be for most e-mails) an error occurs I can't catch.
      GetPropValue = Nothing
      On Error Resume Next
      GetPropValue = pobjPropAccessor.GetProperty(pobjSchema)

    End Function

    Thanks for all your help. It is appreciated!

    Friday, April 22, 2016 8:51 AM
  • Hi Axel,

    It seems you have found a solution, am I right? If so, I suggest you mark the helpful reply as answer to close this thread. If not, please feel free to let us know your current issue.

    Best Regards,

    Edward


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.


    • Marked as answer by Axel Trunk Monday, April 25, 2016 8:33 AM
    Monday, April 25, 2016 2:50 AM