Chris Umbel

Exchange webdav automation

Recently a situation arose where it would be very handy for me to write some code to automate some tasks dealing with exchange server that I'd have gone to CDO for in the past.

I was basically trying to pull attachments out of unread mails with specific subjects and mark the owning mail as read. My first move was strait to CDO... Low and behold microsoft REALLY does not want you using CDO from within .net (generally not supported except for circumstances incompatible with my needs) and accessing exchange via ADO is supported only on the exchange server itself and this was prohibited by circumstances beyond my control.

Since I wasn't prepared to use CDOX in an unsupported fashion the only real option I had available was to issue commands to exchange via webdav. It seemed klunky at first, but turned out to be quite handy. You really can go far with automating exchange by HTTP, and I don't mean total hacks like faking browser requests to web outlook.

Consider the following code:

/* send the webdav query */
XmlDocument inboxXml = new XmlDocument();
HttpWebRequest request = (HttpWebRequest)WebRequest.
Create("http:/mail.mydomain.com/exchange/myuser/inbox/");

/* impersonate current process */
request.Credentials = CredentialCache.DefaultCredentials;
request.ContentType = "text/xml";

/* the actual name of our command */
request.Method = "PROPFIND";

/* read the response back from exchange */
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

using (StreamReader reader = 
new StreamReader(response.GetResponseStream()))
{
    inboxXml.LoadXml(reader.ReadToEnd());
}

/* xsd plumbing so our xpath queries will work */
XmlNamespaceManager namespaces = 
new XmlNamespaceManager(inboxXml.NameTable);
namespaces.AddNamespace("a", "DAV:");
namespaces.AddNamespace("d", "urn:schemas:httpmail:");

/* iterate all items in mailbox that are 
proper unread DotCom messages */
foreach (XmlNode mailNode in inboxXml.
SelectNodes(@"/a:multistatus/a:response/a:href", namespaces))
{
    Console.WriteLine(mailNode.InnerText);
}

That code simply asked exchange for a list of mails in a specific mailbox.

Look at where we set the request method, "PROPFIND" in this case. Think of that a function name. It tells the server what action to do i.e. get the properties of a mailbox. Not listed above but also used in my program were "X-MS-ENUMATTS" and "PROPPATCH" list attachments and set an email's state to "read" respectively.

You issue arguments to these webdav requests similarly to how the POST HTTP method works by writing to the request stream before reading the response like so:

byte[] bytes = Encoding.UTF8.GetBytes((string)query);
request.ContentLength = bytes.Length;
System.IO.Stream requestStream = request.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();

where the object "query" is a string such as

<?xml version='1.0'?>
<D:propertyupdate xmlns:D='DAV:' xmlns:hm='urn:schemas:httpmail:'>
 <D:set>
  <D:prop>
   <hm:read>1</hm:read>
  </D:prop>
 </D:set>
</D:propertyupdate>
for a PROPPATCH request setting at item to "read".

I suppose this may seem like an off the wall way of talking to exchange but it can be quite handy.

Tue May 26 2009 23:05:06 GMT+0000 (UTC)

Follow Chris
RSS Feed
Twitter
Facebook
CodePlex
github
LinkedIn
Google