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 (22)
  1. jdawg1994 says:

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

  2. jdawg1994 says:

    If anyone is interested… I changed the SCOPE in the SQL from ‘deep traversal’  to ‘shallow traversal’ to access public folders.

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

  4. sandeep says:

    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…

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

  6. Question How do I access my Outlook contacts from my web application? Short Answer You don’t, well at

  7. Wes' Blog says:

    Question How do I access my Outlook contacts from my web application? Short Answer You don’t, well at

  8. Geetha says:

    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

  9. 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>"

    )

  10. Ami Shah says:

    Hi

    I tried the same sample code, i got 3 cookies but  got Login Time out error while executing the search command.

    Any idea?

  11. Lothu says:

    I have tried the above sample code. Languages i used : C#,Windows service

    i am getting the following error in this line:::

    RequestStream = Request.GetRequestStream()—>

    System.Net.WebException: Unable to connect to the remote server —> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

    can u pls help me to resolve this?

  12. 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 …

  13. Lothu says:

    davidhernandez:

    It’s working fine when i call as a seperate component..but when i call thru webservice it’s throwing the above error.

  14. Mohan says:

    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.

  15. praveen says:

    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.

  16. Jayanth Nadig says:

    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.

  17. Echang says:

    Question

    HowdoIaccessmyOutlookcontactsfrommywebapplication?

    ShortAnswer

    Youdon’t,

  18. MrWobbles says:

    I am getting a 440 Login Timeout error on the Response = Request.GetResponse() line of code.  Is there something that I should do on the server side or should this all be able to be done from where the program is run without messing with the server? Any help is appreciated – Thank you.

  19. milap_great says:

    I am also getting 440 Login Timeout Error

  20. kbsudhir says:

    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.

  21. Manivannan says:

    Hey David.. Thanks for the Code…

    But I'm Getting the Error : 440 – Timed Out.

    Anyone Dare to Help me..?? Thanks anyway…

    – Manivannan.N

    http://www.nmanivannan.blogspot.com

Comments are closed.

Skip to main content