Sdílet prostřednictvím


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).

Comments

  • Anonymous
    December 01, 2006
    Great Post! I have been researching methods for retrieving mail items from Exchange public folders for a week or so now. webDAV looks promising and your example is much clearer than most I have seen. Your example works great for my inbox, but when I attempt to search the public folder I get a "501 Not Implemented" error. Do you know if it is possible for Exchange to disabled this type access to public folders while allowing Inbox access? Note: I can use our https://myMail.myCorp.com website to view both my Inbox (/exchange/) and public folders (/public/) .

  • Anonymous
    December 04, 2006
    If anyone is interested... I changed the SCOPE in the SQL from 'deep traversal'  to 'shallow traversal' to access public folders.

  • Anonymous
    December 04, 2006
    I could access public folders even with the 'deep traversal' option. I've read that sometimes if there is a migration from Exchange 2003 to 2007 it may give that error and some Admin task should be run. The Scope should be based on how you want to look for your elements: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_exch2k_scope.asp  There is also a restriction on MAPI stores using deep traversal: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_exch2k_specifying_a_deep_traversal.asp

  • Anonymous
    January 09, 2007
    HI, Can you please tell me how can you do the same through the VB Script.... I've already done it through .Net but I need it in the vb... I'm trying to reuse WinHttp SetRequestHeader and setting sessionid and cadata header but of no use...

  • Anonymous
    January 10, 2007
    There is a VB (not VB Script) sample in http://support.microsoft.com/kb/308373 I don't think you won't need to modify too much code to make it work on VBScript. Here is a Javascript sample http://www.infinitec.de/articles/exchange/webdavwithfba.aspx

  • Anonymous
    January 30, 2007
    Question How do I access my Outlook contacts from my web application? Short Answer You don't, well at

  • Anonymous
    January 30, 2007
    Question How do I access my Outlook contacts from my web application? Short Answer You don't, well at

  • Anonymous
    February 15, 2007
    I'm trying to access  the emails from OWA. I tried this link http://msdn2.microsoft.com/en-us/library/ms879334.aspx I'm getting thie '440 Login Timeout error' I wanted to try your exxample code... but it looks like some lines were disappeared like this one ' Create our destination URL.        Dim strURL As String = "https://" & strServerName & "/exchange/" & strUserName & "/inbox" please help me out. kgeethu_at_hotmail.com

  • Anonymous
    February 15, 2007
    I tried the link and works ok: http://msdn2.microsoft.com/en-us/library/ms879334.aspx I am not really sure by what you mean by some lines disappeared. The code is compilable and runnable "AS IS" (You only need to replace the variables values 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>" )

  • Anonymous
    April 03, 2007
    Hi I tried the same sample code, i got 3 cookies but  got Login Time out error while executing the search command. Any idea?

  • Anonymous
    May 10, 2007
    The comment has been removed

  • Anonymous
    May 11, 2007
    Lothu: It seems that the server is not responding, this can happen for various reasons: 1 Firewall in client or server 2 WebDav could be disabled in Exchange 3 Address is not correct 4 The protocol is not correct (check if the server can use ssl, otherwise use http instead of https) 5 ...

  • Anonymous
    May 11, 2007
    The comment has been removed

  • Anonymous
    July 06, 2007
    Its working fine with me also. I would appreciate if you can help me in getting to know how can I paginate my mails by retreiving fixed 25 mails everytime.

  • Anonymous
    July 30, 2007
    how do i download attachments using webdav... HttpWebRequest1 = New MSXML2.XMLHTTP40 HttpWebRequest1.open("GET", xml1.Value, False, "pradind", "spr@2106") HttpWebRequest1.setRequestHeader("Content-Type", "xml")                                   HttpWebRequest1.send() ReadAnAttatchment = HttpWebRequest1.responseText         here, ReadAnAttatchment is in string format, so, how can i save it in its respective file format( excel,word...etc). any help on this is appreciated.. Thanks.

  • Anonymous
    October 05, 2007
    Hi All, i have got a exchange public folder and i have placed 4 files in that folder. i am accessing the public folder through C#. i am able to get the file count as 4, but i am unable to get the file names in the folder. please help me.

  • Anonymous
    November 07, 2007
    Question HowdoIaccessmyOutlookcontactsfrommywebapplication? ShortAnswer Youdon't,

  • Anonymous
    January 25, 2008
    The comment has been removed

  • Anonymous
    April 30, 2008
    I am also getting 440 Login Timeout Error

  • Anonymous
    June 26, 2008
    I just want to capture the attributes of the mail automatically as soon as it comes into our common mailbox in the exchange server. Any guidance regarding the same is of great help.

  • Anonymous
    July 25, 2010
    Hey David.. Thanks for the Code... But I'm Getting the Error : 440 - Timed Out. Anyone Dare to Help me..?? Thanks anyway...