Programmatically accessing to OWA through Web Dav


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), _
        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)
        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()
        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

            ' 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

            ' Create a request stream. Write the post data to the stream.
            tmpStream = WebReq.GetRequestStream()
            tmpStream.Write(PostData, 0, PostData.Length)
        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()

        Return WebResp.Cookies

    End Function

End Module
 I hope you enjoyed the post (or at least found it useful).