Programmatically accessing to OWA through Web Dav
Hello,
I have been playing around a couple of days with WebDav and I found it really interesting how simple it was to retrieve and modify messages from OWA.
WebDav (World Wide Web Distributed Authoring and Versioning) is a standard that help us edit and manage files on remote servers through the http protocol. For example BizTalk 2000 uses WebDav to manage the schemas (XDR) of the messages. And as I said before Microsoft Exchange Server exposes the mail through WebDav.
It is really simple to get started to do some programming since there are many resources and samples on the web. But I found some posts that were a little bit misleading and could create some confusion.
There are some posts that gives examples on how to access WebDav, they tell us that since webdav is based in http we can use any programming language that have support for making http request (which is 100% true) But then they give us a .Net sample and starts using the COM component MSXML2.XMLHTTP30, which may be correct if we are using VB6 or JavaScript but with .Net we should avoid using Interop and also there is a native class in the .Net framework which is HttpWebRequest.
Then if we have OWA configured to support Forms Authentication we are likely to bump into a "440 Login Timeout" error (even though it takes less than 1 second to show the error) The problem is that if forms are enabled we first need to authenticate first, grab the authentication cookies and pass it to the next request which will be our WebDav command(s). The catch here is that even though reusing the cookies the 440 error does not disappear. The trick (that at least worked for me) was to use the HttpCookieCollection instead of working with the cookies as plain strings.
You can find a full example of how to search using OWA-WebDav through the inbox for an email which contains a certain word in the subject, using both HttpWebRequest and HttpCookieCollection.
Imports System
Imports System.Net
Imports System.IO
Imports System.Xml
Imports System.Text.RegularExpressions
Module Module1
' Code to call the Authentication:
Private CookieJar As CookieContainer
Private strCookies As String
Private WebReq As HttpWebRequest
Sub Main()
Dim strServerName As String = "<ENTER SERVER NAME>"
Dim strDomain As String = "<ENTER DOMAIN NAME>"
Dim strUserID As String = "<ENTER USER ID>"
Dim strPassword As String = "<ENTER PASSWORD>"
Dim strUserName As String = "<ENTER USER NAME>"
Dim term As String = "<ENTER A STRING TO SEARCH>"
' Create our destination URL.
Dim strURL As String = "https://" & strServerName & "/exchange/" & strUserName & "/inbox"
' Enter your WebDAV-related code here.
Dim QUERY As String = "<?xml version=""1.0""?>" _
& "<g:searchrequest xmlns:g=""DAV:"">" _
& "<g:sql>SELECT ""urn:schemas:httpmail:subject"", " _
& """urn:schemas:httpmail:from"", ""DAV:displayname"", " _
& """urn:schemas:httpmail:textdescription"" " _
& "FROM SCOPE('deep traversal of """ & strURL & """') " _
& "WHERE ""DAV:ishidden"" = False AND ""DAV:isfolder"" = False " _
& "AND ""urn:schemas:httpmail:subject"" LIKE '%" & term & "%' " _
& "ORDER BY ""urn:schemas:httpmail:date"" DESC" _
& "</g:sql></g:searchrequest>"
Dim Response As System.Net.HttpWebResponse
Dim RequestStream As System.IO.Stream
Dim ResponseStream As System.IO.Stream
Dim ResponseXmlDoc As System.Xml.XmlDocument
Dim SubjectNodeList As System.Xml.XmlNodeList
Dim SenderNodeList As System.Xml.XmlNodeList
Dim BodyNodeList As System.Xml.XmlNodeList
Dim URLNodeList As System.Xml.XmlNodeList
Dim Request As HttpWebRequest = CType(System.Net.WebRequest.Create(strURL), _
System.Net.HttpWebRequest)
Request.CookieContainer = New CookieContainer()
Request.CookieContainer.Add(AuthenticateSecureOWA(strServerName, strDomain, strUserID, strPassword))
Request.Credentials = New System.Net.NetworkCredential( _
strUserName, strPassword, strDomain)
Request.Method = "SEARCH"
Request.ContentType = "text/xml"
Request.KeepAlive = True
Request.AllowAutoRedirect = False
Dim bytes As Byte() = System.Text.Encoding.UTF8.GetBytes(QUERY)
Request.Timeout = 30000
Request.ContentLength = bytes.Length
RequestStream = Request.GetRequestStream()
RequestStream.Write(bytes, 0, bytes.Length)
RequestStream.Close()
Request.Headers.Add("Translate", "F")
Response = Request.GetResponse()
ResponseStream = Response.GetResponseStream()
' Create the XmlDocument object from the XML response stream.
ResponseXmlDoc = New System.Xml.XmlDocument()
ResponseXmlDoc.Load(ResponseStream)
SubjectNodeList = ResponseXmlDoc.GetElementsByTagName("d:subject")
SenderNodeList = ResponseXmlDoc.GetElementsByTagName("d:from")
URLNodeList = ResponseXmlDoc.GetElementsByTagName("a:href")
BodyNodeList = ResponseXmlDoc.GetElementsByTagName("d:textdescription")
End Sub
Private Function AuthenticateSecureOWA(ByVal strServerName As String, ByVal strDomain As String, ByVal strUserName As String, ByVal strPassword As String) As CookieCollection
Dim AuthURL As System.Uri
Try
' Construct our destination URI.
AuthURL = New System.Uri("https://" + strServerName + "/exchweb/bin/auth/owaauth.dll")
Catch ex As Exception
Throw NewApplicationException("Error occurred while you are creating the URI for OWA authentication!" + vbCrLf + vbCrLf + ex.Message)
End Try
'Dim WebReq As HttpWebRequest
CookieJar = New CookieContainer
' Create our request object for the constructed URI.
WebReq = CType(WebRequest.Create(AuthURL), HttpWebRequest)
WebReq.CookieContainer = CookieJar
' Create our post data string that is required by OWA (owaauth.dll).
Dim strPostFields As String = "destination=https%3A%2F%2F" & strServerName & "%2Fexchange%2F" + strUserName + "%2F&username=" + strDomain + "%5C" + strUserName + "&password=" + strPassword + "&SubmitCreds=Log+On&forcedownlevel=0&trusted=0"
WebReq.KeepAlive = True
WebReq.AllowAutoRedirect = False
WebReq.Method = "POST"
' Store the post data into a byte array.
Dim PostData() As Byte = System.Text.Encoding.ASCII.GetBytes(strPostFields)
' Set the content length.
WebReq.ContentLength = PostData.Length
Dim tmpStream As Stream
Try
' Create a request stream. Write the post data to the stream.
tmpStream = WebReq.GetRequestStream()
tmpStream.Write(PostData, 0, PostData.Length)
tmpStream.Close()
Catch ex As Exception
Throw NewApplicationException("Error occurred while trying OWA authentication!" + vbCrLf + vbCrLf + ex.Message)
End Try
' Get the response from the request.
Dim WebResp As HttpWebResponse = WebReq.GetResponse()
WebResp.Close()
Return WebResp.Cookies
End Function
End Module
I hope you enjoyed the post (or at least found it useful).