Search This Blog

Thursday, April 14, 2011

Connecting to User Mailbox using Exchange Web Services Managed API

Email Management software nowadays connect to exchange servers and archives e-mails based on some criteria. Have you ever wondered how the software is able to connect to Microsoft Exchange and manage the capture of e-mails?
this article is the introduction to the know-how, we will be exposed to the new Exchange Managed web services API that allows you to do awesome tasks on top of exchange.

let's do it!

Prepare the Environment
-          Install Microsoft Exchange Web Services Managed API from the following Web Site:

Create a New Visual Basic .Net windows Application Project
-          Open A New Microsoft Visual Basic .Net Windows Project, I am using VS 2010 in this sample
-          Add a reference to “Microsoft.Exchange.WebServices” , browse to the reference file in  “<Install Drive>\Program Files\Microsoft\Exchange\Web Services\1.1”
-          Open a New windows Form, add a button, text boxes as follows:



The 4 text boxes will represent the environment data; it will have the information about the exchange server, the admin credentials that we will use to connect to that exchange server, and the user account mail box that we will read messages from.

Control Label
Text Box Control Name
Usage
Exchange Server Name
txtExchangeServerName
This is going to have the value of the FULL  exchange server name in the following format:
<ServerName>.<DomainName>.com
Admin Account Name
txtAdminAccountPassword
This is the administrative user name that will connect to the exchange server, it should have admin privileges on the exchange server,
Admin Account Password
txtAdminAccountPassword
The password of the admin account
User / Mailbox Account
txtAccountName
This is the mailbox account that we will fetch emails from

o   Exchange Server Name text Box: txtExchangeServerName.
o    Text Box: txtExchangeAdminName
o   Admin Account Password: txtAdminAccountPassword
o   User / Mailbox Account: txtAccountName
-          Add a Grid control to the form, the grid control will show the e-mails of the selected mailbox.

-          Go to source code and import the following classes


Usage
Imports Microsoft.Exchange.WebServices.Data

Will be used to reference the following objects:
-          Exchange Service
-          Folder
-          SearchFilter
-          ItemView
-          FindItemsResults(Of Item)
-          EmailMessage
-          WellKnownFolderName
-          LogicalOperator
-          EmailMessageSchema
Imports System.Net

Will be used to reference the following Objects:
-          NetworkCredential

Connect to mailbox and fetch emails
In this section, I will demonstrate the code to connect to a mailbox and fetch the emails.
Open source control, open the buttun1_click event,  then write the following code to instantiate an abject for the exchange service, this object will take care of establishing the connection to the exchange server:
Dim oService As ExchangeService = New ExchangeService(ExchangeVersion.Exchange2010)
It is to that I am using exchange server 2010 in my sample. Should you need to connect to 2007, you will have to change the parameter ExchangeVersion.Exchange2010 to the 2007 option

Then, create a variable to hold the URI address, pass the variable to the exchange service object:

Dim strServerURI As String = "https://" & txtExchangeServerName.Text & "/ews/exchange.asmx"
oService.Url = New Uri(strServerURI)

The URI address is going to be as this format: https://rsvr1.rdom.com/ews/exchange.asmx where rsvr1.rdom.com is the full name of the exchange server. In order to double check that it is the correct format, take the URL and insert it in the browser, if it returns XML WSDL information, it means it is working and the connectivity is OK, if it does not return valid data, then there is definitely a problem with the server or with the URL itself.

We need now to pass the admin credential and the domain name information; this information will be used when connecting to the exchange server

'---pass the Admin credential and domain information for admin connectivity
Dim strDomainName As String = Split(txtExchangeServerName.Text, ".")(1)
oService.Credentials = New NetworkCredential _
(txtExchangeAdminUserName.Text, txtExchangeAdminPassword.Text, strDomainName)

Now you need to connect to the user mailbox:
'---conenct to the user mailbox
Dim strMailboxUser As String = txtAccountName.Text
oService.ImpersonatedUserId = New ImpersonatedUserId(ConnectingIdType.SmtpAddress, strMailboxUser)


Then you need to select which folder you need to access, in our example, we will access the user “Inbox” folder:

Now comes the trick of the day, if you run the code until above point, you will be receiving the following error:

This happens when you are connecting to exchange in a secured socket layer connectivity, I have spent some time looking for a solution to this issue, until I knew that you will need to override the way that handles the secured connectivity, we will be telling the environment to accept my connection to the exchange server. In order to do this, I have created a class that will take care of this functionality:

Imports System.Net
Imports System.Net.Security
Imports System.Security
Imports System.Security.Cryptography.X509Certificates

Public Class TrustAllCertificatePolicy

Public Shared Sub OverrideCertificateValidation()
        ServicePointManager.ServerCertificateValidationCallback = New RemoteCertificateValidationCallback(AddressOf RemoteCertValidate)
    End Sub

Private Shared Function RemoteCertValidate(ByVal sender As Object, ByVal cert As X509Certificate, ByVal chain As X509Chain, ByVal [error] As System.Net.Security.SslPolicyErrors) As Boolean
        Return True
End Function

End Class

Then in the code, put the following line before the code that connects to the user inbox, so t will be as follows:
TrustAllCertificatePolicy.OverrideCertificateValidation()
This would solve the problem, and now let us continue with the email fetching.
To get e-mails, you will need to establish a search filter, search filters is a good way of sending multiple criteria to exchange server to get the requested e-mails, in our case here, we need to get the read and unread e-mails (all e-mails)

We will pass the search filters as array of filters, as follows:
  Dim arrSearchFilter(1) As SearchFilter
  arrSearchFilter(0) = New SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, True)
  arrSearchFilter(1) = New SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, False)

Now execute the search folder on the user inbox

Dim oSearchFilter As SearchFilter = Nothing
oSearchFilter = New SearchFilter.SearchFilterCollection(LogicalOperator.Or, arrSearchFilter)

The rest of the code is to create a DataTable with columns, and bind the results to it and display it in grid.



            Dim oView As ItemView = New ItemView(20)

            '---Fire the query for the unread items
            oResults = oService.FindItems(WellKnownFolderName.Inbox, oSearchFilter, oView)
            Dim oMessage As EmailMessage = Nothing

            oMessageCollection = New DataTable
            Dim oColumn As New DataColumn
            oColumn.ColumnName = "ID"
            oColumn.AutoIncrement = True
            oMessageCollection.Columns.Add(oColumn)

            oColumn = New DataColumn
            oColumn.ColumnName = "Subject"
            oMessageCollection.Columns.Add(oColumn)

            oColumn = New DataColumn
            oColumn.ColumnName = "From"
            oMessageCollection.Columns.Add(oColumn)

            oColumn = New DataColumn
            oColumn.ColumnName = "Date Received"
            oMessageCollection.Columns.Add(oColumn)

            Dim oRow As DataRow

            For Each oMessage In oResults
                oRow = oMessageCollection.NewRow
                oRow("Subject") = oMessage.Subject
                oRow("From") = oMessage.From.Name
                oRow("Date Received") = oMessage.DateTimeReceived
                oMessageCollection.Rows.Add(oRow)
                oRow = Nothing
            Next
            '---Loop through the items and do whatever is required.
            DataGridView1.DataSource = oMessageCollection

            DataGridView1.DataSource = oMessageCollection

5 comments:

blog said...
This comment has been removed by the author.
blog said...
This comment has been removed by the author.
blog said...
This comment has been removed by the author.
blog said...

Very good article. But it would be appreciated to explain howto impersonate useraccounts, otherwise it ends in an error 401.

Filmproduktion von VerTrend Media Production

Unknown said...


Thank you for the information. You have a very good article. I found it informative and useful. Keep up the good work and God bless!

www.gofastek.com