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.aspAnonymous
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.aspxAnonymous
January 30, 2007
Question How do I access my Outlook contacts from my web application? Short Answer You don't, well atAnonymous
January 30, 2007
Question How do I access my Outlook contacts from my web application? Short Answer You don't, well atAnonymous
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.comAnonymous
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 removedAnonymous
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 removedAnonymous
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 removedAnonymous
April 30, 2008
I am also getting 440 Login Timeout ErrorAnonymous
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...
- Manivannan.N www.nmanivannan.blogspot.com