0

I'm trying to import an outlook message to my vb.net form to populate textboxes/richtextboxes. I've used some code from Eric Moreau which handles the import function. The problem is that the code imports the message and saves it to a temporary folder. My issue here is that I would need a solution without any kind of saving. Instead it should populate a richtextbox field and then I will use that richtextbox to save it to my.settings of the application. I can't seem to figure out what to change in order to change the behaviour from saving to actually populating a field of mine. The code is below (All cred to Eric Moreau for the original code)

Option Strict On

Public Class MailDnD
Dim objOL As New Microsoft.Office.Interop.Outlook.Application

Private Sub me_DragDrop(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
    lblFile.Text = String.Empty
    Try

        If e.Data.GetDataPresent(DataFormats.FileDrop) Then
            'supports a drop of a file from Windows Explorer

            ' copy the name of the dragged files into a string array
            Dim draggedFiles As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())

            'handle each file passed as needed
            For Each fileName As String In draggedFiles
                'hardcode a destination path for testing
                Dim strDestinationFile As String = _
                            IO.Path.Combine(My.Settings.TempFolder.ToString, _
                                            IO.Path.GetFileName(fileName))
                'test if source and destination are the same
                If strDestinationFile.Trim.ToUpper = fileName.Trim.ToUpper Then
                    lblFile.Text += strDestinationFile + _
                                    " - E-post meddelandet är redan importerat!" + _
                                    Environment.NewLine
                Else
                    lblFile.Text += "Importerar - " + _
                                    strDestinationFile + Environment.NewLine
                    IO.File.Copy(fileName, strDestinationFile)
                End If
            Next

        ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
            'supports a drop of a Outlook message

            'Dim objMI As Object - if you want to do late-binding
            Dim objMI As Microsoft.Office.Interop.Outlook.MailItem

            For Each objMI In objOL.ActiveExplorer.Selection()
                'hardcode a destination path for testing
                Dim strFile As String = _
                            IO.Path.Combine(My.Settings.TempFolder.ToString, _
                                            (objMI.Subject + ".msg").Replace(":", ""))
                lblFile.Text += strFile + Environment.NewLine
                objMI.SaveAs(strFile)
            Next
        End If
        lblFormat.Text = String.Empty

    Catch ex As Exception
        lblFile.Text = "Ett fel uppstod vid import, vänligen testa igen" + Environment.NewLine + ex.ToString
    End Try
End Sub

''' <summary>
''' Reset the status label
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub me_DragLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.DragLeave
    lblFormat.Text = String.Empty
End Sub

''' <summary>
''' Handle the DragOver event
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Private Sub me_DragOver(ByVal sender As Object, ByVal e As System.Windows.Forms.DragEventArgs) Handles Me.DragOver
    If e.Data.GetDataPresent(DataFormats.FileDrop) Then
        'handle a file dragged from Windows explorer
        e.Effect = DragDropEffects.Copy
        lblFormat.Text = "Dra över e-post meddelandet"
    ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then
        'handle a message dragged from Outllok
        e.Effect = DragDropEffects.Copy
        lblFormat.Text = "Dra över e-post meddelandet"
    Else
        'otherwise, do not handle
        e.Effect = DragDropEffects.None
        lblFormat.Text = ""
    End If
End Sub

Just to clarify the import function works as intended. It saves the outlook message to the folder but I kinda want it to not save and instead import the message line to line to a richtextbox inside my application. Hook me up if you need more information

Kind regards,

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
Xetra
  • 73
  • 1
  • 8
  • Public Class MailDnD Dim objOL As New Microsoft.Office.Interop.Outlook.Application should ofc be a part of the whole code part – Xetra Oct 30 '17 at 20:13
  • Anyone? Only 12 views so far :( – Xetra Oct 31 '17 at 09:28
  • So if I understand it correctly you _don't_ want to save the message to a temporary file, but instead read the message's contents into a `RichTextBox`? If I'm correct so far, let me ask you this: How will you handle when the user drops multiple messages at the same time? And is this something you actually want to display to the user, or do you just need save it to `My.Settings` directly (or both)? – Visual Vincent Oct 31 '17 at 09:57
  • Yes I want to store the message info on a richtextbox and then save that richtextbox to my.settings. From there I can pull the info whenever I want from my.settings. The multiple files problem wont be an issue as this is made to myself and I will only pull 1 file at the time. – Xetra Oct 31 '17 at 10:28
  • The problem is that when you're dragging mails directly from Outlook your only option is to store them in a temporary file, as there does not seem to be a good way of storing the `MailItem` as raw memory data. – Visual Vincent Oct 31 '17 at 10:38
  • However implementing a solution that reads a file to your `RichTextBox` isn't that hard, though I have one question: What do you actually want to show in the `RichTextBox`/What do you want to store in `My.Settings`? Because loading the mail file itself will most likely only make the RTB show lots of jibberish, so it comes down to what you want to store in `My.Settings`: _The entire file_ or just, for example, the body of the mail? – Visual Vincent Oct 31 '17 at 10:42
  • Hmm okay, well a read solution could be of use too. I basically want the body of the email to populate the richtextbox, and the subject on a textbox. I already have a solution for the subject as the filename is named exactly as the subject. Do you by any chance have a solution that reads the temporary file and populate a richtextbox with the body of that email? My idea is that I can delete the temporary file after it has been read. The issue is that this solution should be as empty of temporary files as possible. But 1 temp file at the time doesn't bother me. – Xetra Oct 31 '17 at 10:48
  • I do, but it'll take me a little while to construct it. – Visual Vincent Oct 31 '17 at 10:57
  • Though the good news is that since you only want _parts_ of the e-mail you won't be needing a temporary file after all. :) – Visual Vincent Oct 31 '17 at 11:05
  • Ohh okay? Yes I kinda just want the body of the email and ofc the subject but as I said with my current code the temp file is named after the subject :) EDIT: When I thought some more about it I kinda need the sender email too, will that be a problem? – Xetra Oct 31 '17 at 11:44
  • Not at all! The only problem would be if you need _every_ existing piece of information from the mail. -- I'm almost done with the code! – Visual Vincent Oct 31 '17 at 11:54
  • Thanks man! I will try your solution to see if it fits the my projects needs. – Xetra Oct 31 '17 at 12:01
  • There we go! Sorry for taking so long, I'm not that much into Office VSTO and I wanted to make sure everything was done correctly and efficiently. – Visual Vincent Oct 31 '17 at 12:30

1 Answers1

0

Tweaking your code to only get one item isn't that hard. You basically just need to remove the loops and make it select the first item instead.

I switched to the DragEnter event instead of DragOver since the former is only raised once the mouse enters the form, while the latter is raised continuously until the object is dropped or the mouse leaves the form. The drop data cannot change while the mouse is over the form anyway, so therefore you don't need to check it all the time.

I also took the liberty of correcting some "särskrivningar" :), renaming some variables for better understanding, and tweaking so that it won't allow you to drop more than one file/item at a time.

I've commented most of the code, but if you have any questions or if anything's unclear just let me know!

Dim Outlook As New Microsoft.Office.Interop.Outlook.Application

''' <summary>
''' Custom method called by the DragDrop event when a mail is dropped onto the application. 
''' Handles the updating of the User Interface.
''' </summary>
''' <param name="Mail">The mail dropped onto the application.</param>
''' <remarks></remarks>
Private Sub OnMailDropped(ByVal Mail As Microsoft.Office.Interop.Outlook.MailItem)
    SenderTextBox.Text = Mail.SenderEmailAddress
    SubjectTextBox.Text = Mail.Subject
    BodyRichTextBox.Text = Mail.Body
End Sub

Private Sub MailDnD_DragDrop(sender As Object, e As System.Windows.Forms.DragEventArgs) Handles Me.DragDrop
    Try
        If e.Data.GetDataPresent(DataFormats.FileDrop) Then 'Supports the drop of a file from Windows Explorer.

            'Copy the names of the dragged files into a string array.
            Dim DraggedFiles As String() = CType(e.Data.GetData(DataFormats.FileDrop), String())

            'Check that only one file is selected.
            If DraggedFiles.Length = 0 Then
                lblFile.Text = "Inget e-postmeddelande valt!"
                Return 'Do not continue.

            ElseIf DraggedFiles.Length > 1 Then
                lblFile.Text = "Du kan endast importera ett e-postmeddelande i taget!"
                Return 'Do not continue.

            End If

            'Get the file path of the dragged file.
            Dim FileName As String = DraggedFiles(0) 'Regular arrays are zero-based, which means the very first item has index 0.

            'Load the file into a MailItem.
            Dim Mail As Microsoft.Office.Interop.Outlook.MailItem = _
                CType(Outlook.Session.OpenSharedItem(FileName), Microsoft.Office.Interop.Outlook.MailItem)

            'Update the status label.
            lblFile.Text = "Importerade: " & FileName

            'Invoke our custom method.
            OnMailDropped(Mail)

        ElseIf e.Data.GetDataPresent("FileGroupDescriptor") Then 'Supports the drop of a Outlook message.

            'Check that only one mail is selected.
            If Outlook.ActiveExplorer().Selection.Count = 0 Then
                lblFile.Text = "Inget e-postmeddelande markerat!"
                Return 'Do not continue.

            ElseIf Outlook.ActiveExplorer().Selection.Count > 1 Then
                lblFile.Text = "Du kan endast importera ett e-postmeddelande i taget!"
                Return 'Do not continue.

            End If

            'Get the selected mail.
            Dim Mail As Microsoft.Office.Interop.Outlook.MailItem = _
                CType(Outlook.ActiveExplorer().Selection(1), Microsoft.Office.Interop.Outlook.MailItem)
            'In Office applications the collections are one-based, thus we do ".Selection(1)" for the first item instead of ".Selection(0)".

            'Update the status label.
            lblFile.Text = "Importerade: " & Mail.Subject

            'Invoke our custom method.
            OnMailDropped(Mail)

        End If
    Catch ex As Exception
        lblFile.Text = "Ett fel uppstod vid import, vänligen testa igen" + Environment.NewLine + ex.ToString
    End Try
End Sub

Private Sub MailDnD_DragEnter(sender As Object, e As System.Windows.Forms.DragEventArgs) Handles Me.DragEnter
    If e.Data.GetDataPresent(DataFormats.FileDrop) _
        AndAlso CType(e.Data.GetData(DataFormats.FileDrop), String()).Length = 1 Then 'Allow only one file at a time.

        'Handle a file dragged from Windows explorer
        e.Effect = DragDropEffects.Copy
        lblFormat.Text = "Dra över e-postmeddelandet"

    ElseIf e.Data.GetDataPresent("FileGroupDescriptor") _
        AndAlso Outlook.ActiveExplorer().Selection.Count = 1 Then 'Allow only one mail at a time.

        'Handle a message dragged from Outlook
        e.Effect = DragDropEffects.Copy
        lblFormat.Text = "Dra över e-postmeddelandet"

    Else
        'Otherwise, do not handle
        e.Effect = DragDropEffects.None
        lblFormat.Text = ""
    End If
End Sub

Notes about the code:

  • The custom OnMailDropped() method is called every time a valid e-mail item/file is dropped onto your form.

  • SenderTextBox is the text box which will display the sender's e-mail address.

  • SubjectTextBox is the text box which will display the e-mail's subject.

  • BodyRichTextBox is the text box which will display the e-mail body.

As you also might have noticed I'm concatenating strings with the ampersand (&) instead of the plus (+). This is because in VB.NET & is the native string concatenation operator. Using the + can in some cases cause problems.
See The difference between + and & for joining strings in VB.NET for more info.

Hope this helps!

Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • Woah that's some solid work right there! It works exactly as I wanted it to work. Thanks a lot! I checked out your profile and your website btw, nice to see that there's more Doom fans out there! :) – Xetra Oct 31 '17 at 13:10
  • @OliverPersson : Glad I could help! -- Haha, yeah... My ugly website. It's looked like that since I created it in 2012. At the time I knew **nothing** about HTML or Javascript ;). Since then I've learned a lot though and I am actually working on a new, fresh version of the website. – Visual Vincent Oct 31 '17 at 13:19
  • Btw now when I have you on the line, do you by any chance know how I can make a new my.setting for each action the user does? Like for example everytime the user clicks a button it will create my.settings.Ärende+1 for example? So if the user clicks the button 3 times it will create my.settings.Ärende1/2/3 ? I don't need a whole code example, just the syntax on how I can write it – Xetra Oct 31 '17 at 13:20
  • @OliverPersson : Unfortunately settings are static and cannot be changed at runtime. However you can make a setting hold a list of strings by changing the setting type to `System.Collections.Specialized.StringCollection` as shown in this image: https://i.stack.imgur.com/zJgKN.png – Visual Vincent Oct 31 '17 at 13:26
  • @OliverPersson : To initialize the list you **must** copy-paste this into the `Value` of the setting: `` – Visual Vincent Oct 31 '17 at 13:28
  • @OliverPersson : See this for more info on how to use it: http://www.vb-helper.com/howto_net_list_setting.html – Visual Vincent Oct 31 '17 at 13:29