Macca Blog

My life experiences with code and design

WebDav and Outlook Appointments in .NET

Posted on by Mark

Hello all, I have recently had the task of creating/updating/searching and deleting appointments in an outlook calendar by using WebDav.

This was proven to me to be a difficult task. There was very little documentation around this and not alot of people who tried to help me. So I figured it out by putting together may different Microsoft articles and am going to post the solution to this daunting problem.

The Code all uses a HTTPWebRequest object to send a structured XML request to an exchange address. An example of this XML is as follows:


<?xml version=”1.0″?>
<g:propertyupdate
xmlns:g=’DAV:’
xmlns:e=’http://schemas.microsoft.com/exchange/’
xmlns:mapi=’http://schemas.microsoft.com/mapi/’
xmlns:mapit=’http://schemas.microsoft.com/mapi/proptag/’
xmlns:x=’xml:’
xmlns:cal=’urn:schemas:calendar:’
xmlns:dt=’urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/’
xmlns:header=’urn:schemas:mailheader:’
xmlns:mail=’urn:schemas:httpmail:’>
<g:set>
<g:prop>
<g:contentclass>urn:content-classes:appointment</g:contentclass>
<e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>
<mail:subject>Test Appointment Subject</mail:subject>
<mail:htmldescription>Let’s meet here</mail:htmldescription>
<cal:location>My Place</cal:location>
<cal:dtstart dt:dt=”dateTime.tz”>2006-07-11T13:21:27.000Z</cal:dtstart>
<cal:dtend dt:dt=”dateTime.tz”>2006-07-11T13:21:27.000Z</cal:dtend>
<cal:instancetype dt:dt=”int”>0</cal:instancetype>
<cal:busystatus>BUSY</cal:busystatus>
<cal:meetingstatus>CONFIRMED</cal:meetingstatus>
<cal:alldayevent dt:dt=”boolean”>0</cal:alldayevent>
<cal:reminderoffset>1</cal:reminderoffset>
<cal:responserequested dt:dt=”boolean”>0</cal:responserequested>
<header:to>Mark Macumber</header:to>
<mapi:finvited dt:dt=”boolean”>1</mapi:finvited>
</g:prop>
</g:set>
</g:propertyupdate>

The above XML when sent to an Exchange server will create a new appointment if it does not already exist, if it does exsits (i.e. the address you post this XML to already exists) it will update the properties of that outlook appointment to be whatever are set in the above code.

The code for the add/update are exactly the same, the only thing that seperates them appart is the address of the calendar item. When a request is sent to Exchange, it is given a href address. If this href already exists it will update that appointment, otherwise it will create it.

By the way, I dont post all that often, so if some of this stuff looks way off in terms of formatting, its probably because the < and the > get replaced by the posting engine. So sorry about that, but i did my best.

Here is a method to update/create an appointment in C#:

public void Send()
{
//set the exchange server address
string strExchSvrName = “https://someaddress.com”;

//this will be the name of the appointment that you will need to refer to if updating
string strApptItem = “NameOfMyAppointment.eml”;

//the entire address of the new appointment item, _mailBox is
// the users mailbox address, such as joe.bloggs, so the address will become
// https://someaddress.com/joe.bloggs/Calendar/
string strCalendarUri = strExchSvrName + _mailBox + “/Calendar/”;

// the appointment XML code string
string strApptRequest = “”;

string strDomain;
string strUserName;
string strPassword;

// User name and password of appointment creator.
strUserName = “someUsername”;
strDomain = “theDomain”;
strPassword =”PasswordOfUser”;

// XML namespace info for the WebDAV request.
string strXMLNSInfo = @”
xmlns:g=’DAV:’
xmlns:e=’http://schemas.microsoft.com/exchange/’
xmlns:mapi=’http://schemas.microsoft.com/mapi/’
xmlns:mapit=’http://schemas.microsoft.com/mapi/proptag/’
xmlns:x=’xml:’
xmlns:cal=’urn:schemas:calendar:’
xmlns:dt=’urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/’
xmlns:header=’urn:schemas:mailheader:’
xmlns:mail=’urn:schemas:httpmail:’
“;

// Set the appointment item properties. See the documentation on the properties
// in the urn:schemas:calendar: for more information.
string strCalInfo =
” <cal:location>”+ _location +”</cal:location>”
+ “<cal:dtstart dt:dt=\”dateTime.tz\”>” + _start.ToUniversalTime().ToString(“yyyy-MM-ddTHH:mm:ss.000Z”) + “</cal:dtstart>”
+ “<cal:dtend dt:dt=\”dateTime.tz\”>” + _finish.ToUniversalTime().ToString(“yyyy-MM-ddTHH:mm:ss.000Z”) + “</cal:dtend>”
+ “<cal:instancetype dt:dt=\”int\”>0</cal:instancetype>”
+ “<cal:busystatus>BUSY</cal:busystatus>”
+ “<cal:meetingstatus>CONFIRMED</cal:meetingstatus>”
+ “<cal:alldayevent dt:dt=\”boolean\”>0</cal:alldayevent>”
+ “<cal:reminderoffset>” + _reminderOffset + “</cal:reminderoffset>”
+ “<cal:responserequested dt:dt=\”boolean\”>0</cal:responserequested>”;

string strHeaderInfo = “<header:to>”+ _mailBox +”</header:to>”;

string strMailInfo = “<mail:subject>” + _subject + “</mail:subject> “
+ “<mail:htmldescription>”+ _summary +”</mail:htmldescription>”;

strApptRequest = “”
+”<?xml version=\”1.0\”?>”
+”<g:propertyupdate ” + strXMLNSInfo + “>”
+”<g:set>”
+” <g:prop>”
+” <g:contentclass>urn:content-classes:appointment</g:contentclass>”
+” <e:outlookmessageclass>IPM.Appointment</e:outlookmessageclass>”
+” “+ strMailInfo
+” “+ strCalInfo
+” “+ strHeaderInfo
+” <mapi:finvited dt:dt=\”boolean\”>1</mapi:finvited>”
+” </g:prop>”
+”</g:set>”
+”</g:propertyupdate>”;

// Create a new CredentialCache object and fill it with the network
// credentials required to access the server.
NetworkCredential credentials = new NetworkCredential(strUserName, strPassword, strDomain);
CredentialCache credentialCache = new CredentialCache();
credentialCache.Add(new System.Uri(strCalendarUri), “NTLM”, credentials);

//set it up so it accepts SSL requests
ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy();

// Create the HttpWebRequest object.
HttpWebRequest PROPPATCHRequest = (HttpWebRequest)HttpWebRequest.Create(strCalendarUri + strApptItem);
PROPPATCHRequest.Credentials = credentialCache;
PROPPATCHRequest.Method = “PROPPATCH”;
byte[] bytes = Encoding.UTF8.GetBytes((string)strApptRequest);
PROPPATCHRequest.ContentLength = bytes.Length;

//add proxy to HttpRequest
WebProxy proxy = new WebProxy(“http://proxy:port”);
proxy.Credentials = new NetworkCredential(strUserName, strPassword, strDomain);
PROPPATCHRequest.Proxy = proxy;

Stream PROPPATCHRequestStream = PROPPATCHRequest.GetRequestStream();
PROPPATCHRequestStream.Write(bytes, 0, bytes.Length);
PROPPATCHRequestStream.Close();

PROPPATCHRequest.ContentType = “text/xml”;

WebResponse PROPPATCHResponse = (System.Net.HttpWebResponse)PROPPATCHRequest.GetResponse();

PROPPATCHResponse.Close();
}

You may notice that there are some variables with _ as their starting name, these are just placeholders so you can put whatever you want in them.

You may also notice:

ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy();

This creates a new instance of the class: AcceptAllCertificatePolicy (listed below)

which basically accepts all site certificates.

class AcceptAllCertificatePolicy : ICertificatePolicy
{
public AcceptAllCertificatePolicy()
{}

public bool CheckValidationResult(ServicePoint sPoint, X509Certificate cert, WebRequest wRequest,int certProb)
{
// Always accept
return true;
}
}


Below is the code for the deletion of an appointment, very easy to do:

public void Delete()
{
HttpWebRequest Request;
WebResponse Response;
CredentialCache MyCredentialCache;

string strSourceURI = ConfigurationSettings.AppSettings["ExchangeServer"] + _mailBox + “/Calendar/” + “nameOfMyAppointment.eml”;

string strUserName = “Username”;
string strPassword = “Password”;
string strDomain = “MyDomain”;

// Create a new CredentialCache object and fill it with the network
// credentials required to access the server.
MyCredentialCache = new CredentialCache();
MyCredentialCache.Add( new System.Uri(strSourceURI),
“NTLM”,
new NetworkCredential(strUserName, strPassword, strDomain)
);

// Create the HttpWebRequest object.
Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strSourceURI);

// Add the network credentials to the request.
Request.Credentials = MyCredentialCache;

//accept the site certificate always
ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy();

//add web proxy to the request
WebProxy proxy = new WebProxy(“http://proxy:port”);
proxy.Credentials = new NetworkCredential(strUserName, strPassword, strDomain);

Request.Proxy = proxy;

// Specify the DELETE method.
Request.Method = “DELETE”;

// Send the DELETE method request.
Response = (System.Net.HttpWebResponse)Request.GetResponse();

// Close the HttpWebResponse object.
Response.Close();
}

and thats it!

So I hope this at least helps people a little. I know alot of people out there are wanting this code, which is 100% of the reason why I am posting it. Have fun.

Some links that helped me:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_exch2k_http_webdav_access.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/wss_references_webdav.asp
http://www.msexchange.org/articles/Access-Exchange-2000-2003-Mailbox-WebDAV.html
http://www.troywolf.com/articles/php/exchange_webdav_examples.php
http://blogs.msdn.com/johnrdurant/archive/2005/12/07/vsto_outlook_resourcelist.aspx
http://www.webdav.org/
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_cdo_schema_mapi.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_exch2k_searching_calendar_folders_webdav.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_exch2k_deleting_items_http.asp

One more thing, I dont claim to be an Exchange expert or a webdav expert, the code I have posted is just one way of doing things. If there are better ways, then I am always happy to hear them.

Till next time…

Mark


This entry was posted in Uncategorized. Bookmark the permalink.

3 Responses to WebDav and Outlook Appointments in .NET

  1. Pete

    Looks bloody complicated!

  2. Mark

    well its really not that bad, you just create XML (which is the hardest part) then send the webdav request to the server… Its ultimatly just like a client->server request in the end.

  3. Alex

    My friend told me about his problem.His mails were corrupted and I he used-how to view .ost files.Software solved his problems in seconds,moreover it made it free of charge.Program demonstrated me how convert *.ost files to *.pst files, that can be easily opened by any email client.

Leave a Comment

Your email address will not be published. Required fields are marked *

*


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>