(Print this page)

Drag & Drop emails on a .Net application from Outlook with attachments
Published date: Friday, April 8, 2016
On: Moer and Éric Moreau's web site

I answered a question last week on Experts Exchange where the guy needed to be able to drag an email from Outlook and drop it on his application. From there, the application needed to be able to detach any attachment it had.

Back in May 2008, I wrote an article that was doing the first part of it; the part enabling an application to be able to handle a message drop from Outlook. I was missing the process of detaching the attachments.

This month article will complete the requirements.

Downloadable demo code

This month demo code is provided in both VB and C#. The solution was created using Visual Studio 2015 but code could be reused in older versions of Visual Studio as well.

Also noticed that I referenced Outlook 2016. If you download and open the solution, you might have to recreate the reference to the version of Outlook installed on your computer.

Figure 1: The demo application in action

Creating the UI

The UI is very simple. A label button with a border to be used as the drop destination. You will drag your emails from Outlook over that label and drop them there to be processed. Very important, this label has the AllowDrop property set to True. If you forget it, you will never be able to drop anything there.

The other control on that form is a listbox control just to show the results of the various operations.

Adding a reference to Outlook

As you can see in figure 2, you will need to add a reference to the Microsoft Outlook. Object Library. Again, if you are not using Office 2016 and you have downloaded my demo solution, you will have to redo the reference to fit your own installation.

Figure 2: Adding a reference to Outlook

Handling the DragOver event

To be able to hint the user where he can drop his email, we need to change the cursor effect when the mouse is over the label (remember that the AllowDrop property is set to True).

This is easily done by handling the DragOver event handler and checking if data currently hovering the drop zone is of the FileGroupDescriptor type (otherwise the files are not processed) as shown here:

Private Sub Label1_DragOver(ByVal sender As Object, ByVal e As DragEventArgs) Handles Label1.DragOver
    If e.Data.GetDataPresent("FileGroupDescriptor") Then
        'handle a message dragged from Outllok
        e.Effect = DragDropEffects.Copy
    Else
        'otherwise, do not handle
        e.Effect = DragDropEffects.None
    End If
End Sub    

Handling the Dragdrop event

Once the cursor has changed, we need to write code to process the email(s) drop onto the label (our drop zone). Notice that the following code, because it has a loop, can handle any number of emails dropped on the label.

Private Sub Label1_DragDrop(ByVal sender As Object, ByVal e As DragEventArgs) Handles Label1.DragDrop
    lstResults.Items.Clear()
    Try
        If e.Data.GetDataPresent("FileGroupDescriptor") Then
            'supports a drop of a Outlook message
            For Each objMi As MailItem In mobjApplication.ActiveExplorer.Selection()
                'hardcode a destination path for testing
                Dim strFile As String = IO.Path.Combine("c:\temp", FixFileName(objMi.Subject + ".msg"))
                lstResults.Items.Add(strFile)
                objMi.SaveAs(strFile)
                GetAttachmentsInfo(objMi)
            Next
        End If

    Catch ex As System.Exception
        lstResults.Items.Add("An error occured in the drop event")
        lstResults.Items.Add(ex.ToString)
    End Try
End Sub

After we checked if the files are of the FileGroupDescriptor type, we loop through the ActiveExplorer.Selection collection of emails offered by mobjApplication. This object has been declared an instantiated at the top of the class:

Private ReadOnly mobjApplication As New Application

The Windows clipboard object magically and automatically feed this object so you don’t have to query the clipboard yourself.

In my loop, I do a couple of things:

  • Display the file name in the listbox
  • Save the mail object in the Temp folder of my C: drive (make sure you have that folder of change the value here)
  • Call the GetAttachmentsInfo method for the current email message to get its attachment

Getting the attachments

To complete the process, we need to loop through the attachments, if any, for the MailItem object currently processed. This is the code we need:

Private Sub GetAttachmentsInfo(ByVal pMailItem As MailItem)
    If Not IsNothing(pMailItem.Attachments) Then
        For i As Integer = 1 To pMailItem.Attachments.Count
            Dim currentAttachment As Attachment = pMailItem.Attachments.Item(i)
            If Not IsNothing(currentAttachment) Then
                lstResults.Items.Add("attachment #" + i.ToString())
                lstResults.Items.Add("File Name: " + currentAttachment.FileName)
                Dim strFile As String = IO.Path.Combine("c:\temp", FixFileName(currentAttachment.FileName))
                currentAttachment.SaveAsFile(strFile)
                Marshal.ReleaseComObject(currentAttachment)
            End If
        Next
    End If
End Sub

This is as simple as looping through the Attachments collection of the MailItem object and use its SaveAsFile method to save on your disk.

What is FixFileName?

On my original article, somebody indicated that if the subject of the email contains invalid characters for filenames, it just failed.

In this revision, I have added some code to fix that. There is a method named GetInvalidFileNameChars in the Path class of the System.IO namespace that returns an array of characters that invalid in file names. Using this array, we can then detect and remove (or replace with another character as I did) the invalid characters.

The code for FixFileName reads like this:

Private Function FixFileName(ByVal pFileName As String) As String
    Dim invalidChars As Char() = Path.GetInvalidFileNameChars()
    If (pFileName.IndexOfAny(invalidChars) >= 0) Then
        pFileName = invalidChars.Aggregate(pFileName, Function(current, invalidChar) current.Replace(invalidChar, Convert.ToChar("_")))
    End If
    Return pFileName
End Function

Conclusion

That article has been used many times by numbers of people. With the addition of being able to save the attachments, it might just help even more people.


(Print this page)