Introduction
In this article I present a short form load event that you can place into a blank
WinForms project and once you provide the appropriate values to the public variables in the uppermost portion of the code you should be able to run the application and see that it will extract all attachments from a defined Exchange mailbox to a local file.
Background
This is a small portion of an application I made that searches and extracts certain attachments from a specific Exchange 2007 mailbox and once extracted were read via StreamReader
and their fixed length string contents were uploaded to a SQL instance. This article covers the first part of that task because I found little information when trying to connect to EWS to extract attachments, at least for VB.NET.
Note
I have a portion of the completed code below that has logic to delete the messages it extracts attachments from but I have commented this portion out. I left it intact so that you may uncomment this if deleting the messages is something you wanted to do. I found that I had to delete the messages on my project because otherwise the mailbox would take too long to process and the application would eventually timeout, which can be adjusted but that is beyond the scope of this article.
Add a Web Reference
You will need the URL for your Exchange Web Service, which is also the URL you decalare in the below Global Variable named strExchAsmx
. As instructed here you add a web reference in VS2010 by adding a Service Reference, press advanced and then add a Web reference.
Code
Instead of breaking the code into smaller blocks and providing instruction I have opted to add comment info in the code so that if you cut and paste it is available to you in your project.
Import these classes. You will likely get an error on the ReadMail.exchange
because this is the name of my project and web reference. Here you need to import the web reference that you created above.
Imports ReadMail.exchange
Imports System.Net
Imports System.IO
Imports System.Text
Declare these Global Variables
Public strUsername As String = "mailboxusernamehere"
Public strPassword As String = "mailboxpasswordhere"
Public strExchAsmx As String = "https://yourexchangeserverhere/EWS/Exchange.asmx"
Public strAttachPath As String = "C:\Mail\"
Place this in the pageload event or whatever subroutine you want to initate the process
Using exchangeServer As New ExchangeServiceBinding()
Dim creds As ICredentials = New NetworkCredential(strUsername, strPassword)
exchangeServer.Credentials = creds
exchangeServer.Url = strExchAsmx
Dim findItemRequest As New FindItemType()
findItemRequest.Traversal = ItemQueryTraversalType.Shallow
Dim itemProperties As New ItemResponseShapeType()
itemProperties.BaseShape = DefaultShapeNamesType.AllProperties
findItemRequest.ItemShape = itemProperties
Dim folderIDArray As DistinguishedFolderIdType() = New DistinguishedFolderIdType(0) {}
folderIDArray(0) = New DistinguishedFolderIdType()
folderIDArray(0).Id = DistinguishedFolderIdNameType.inbox
findItemRequest.ParentFolderIds = folderIDArray
Dim findItemResponse As FindItemResponseType = exchangeServer.FindItem(findItemRequest)
Dim folder As FindItemResponseMessageType = _
DirectCast(findItemResponse.ResponseMessages.Items(0), FindItemResponseMessageType)
Dim folderContents As New ArrayOfRealItemsType()
folderContents = DirectCast(folder.RootFolder.Item, ArrayOfRealItemsType)
Dim items As ItemType() = folderContents.Items
If items Is Nothing OrElse items.Count() <= 0 Then
MsgBox("No Items Found!")
Me.Close()
Exit Sub
End If
Dim itemIds As BaseItemIdType() = New BaseItemIdType(items.Count() - 1) {}
For i As Integer = 0 To items.Count() - 1
itemIds(i) = items(i).ItemId
Next
Dim getItemType As New GetItemType()
getItemType.ItemIds = itemIds
getItemType.ItemShape = New ItemResponseShapeType()
getItemType.ItemShape.BaseShape = DefaultShapeNamesType.AllProperties
getItemType.ItemShape.BodyType = BodyTypeResponseType.Text
getItemType.ItemShape.BodyTypeSpecified = True
Dim getItemResponse As GetItemResponseType = exchangeServer.GetItem(getItemType)
Dim messages As ItemType() = New ItemType(getItemResponse.ResponseMessages.Items.Count() - 1) {}
Dim f As Integer = 0
Dim j As Integer = 0
Dim h As Integer = 0
For j = 0 To messages.Count() - 1
messages(j) = DirectCast(getItemResponse.ResponseMessages.Items(j), _
ItemInfoResponseMessageType).Items.Items(0)
If (messages(j).HasAttachments = True) Then
f = f + 1
Dim request As New GetAttachmentType()
Dim responseShape As New AttachmentResponseShapeType()
responseShape.BodyType = BodyTypeResponseType.Text
responseShape.BodyTypeSpecified = True
request.AttachmentShape = responseShape
Dim ids As RequestAttachmentIdType() = New RequestAttachmentIdType(0) {}
ids(0) = New RequestAttachmentIdType()
ids(0).Id = Convert.ToString(messages(j).Attachments(0).AttachmentId.Id)
request.AttachmentIds = ids
Try
Dim response As GetAttachmentResponseType = exchangeServer.GetAttachment(request)
Dim rmta As ResponseMessageType() = response.ResponseMessages.Items
For Each responseMessage As ResponseMessageType In rmta
Dim airmt As AttachmentInfoResponseMessageType = _
TryCast(responseMessage, _
AttachmentInfoResponseMessageType)
Dim attachments As AttachmentType() = airmt.Attachments
For Each attachment As AttachmentType In attachments
If TypeOf attachment Is FileAttachmentType Then
Dim TheFileAttachment As FileAttachmentType = _
DirectCast(attachment, FileAttachmentType)
Using File2Disk As Stream = New _
FileStream(strAttachPath & "\" & _
messages(j).Attachments(0).Name, FileMode.Create)
File2Disk.Write(TheFileAttachment.Content, 0, _
TheFileAttachment.Content.Length)
File2Disk.Flush()
File2Disk.Close()
End Using
Else
Dim TheItemAttachment As ItemType = _
DirectCast(attachment, ItemAttachmentType).Item
Dim ContentBytes() As Byte = _
Convert.FromBase64String(TheItemAttachment.MimeContent.Value)
Using Item2Disk As Stream = New _
FileStream(strAttachPath & "\" & _
messages(j).Attachments(0).Name + ".eml", FileMode.Create)
Item2Disk.Write(ContentBytes, 0, ContentBytes.Length)
Item2Disk.Flush()
Item2Disk.Close()
End Using
End If
h = h + 1
Next
Next
Catch x As Exception
Console.WriteLine(x.Message)
End Try
End If
Next
MsgBox(j & " messages read, " & f & _
" messages had attachments and " & h _
& " of those attachments were extracted!")
Me.Close()
End Using