EXCHANGE WebDAV 101 Exchange WebDAV 101 danba Last Revised: 6/28/06 Revision 1.6 Note: This information is provided as-is and is not official Microsoft Documentation. It’s intended to be for educational purposes only and the samples should only be used against a test system for. WebDAV 101. Last Revised 6/28/06. Version 1.6 1 EXCHANGE WebDAV 101 I. Introduction If you are not familiar with WebDAV for its use against Exchange, you may be wondering “What is WebDAV and what is it good for?” What it comes down to HTTP requests being done against an IIS virtual server mapped into Exchange. XML is usually passed to Exchange in the call in order to perform some specific action on an item in an Exchange store. XML is often returned, which contains requested information and possibly other data. It can also be used to read and write items directly into folders. WebDAV itself is an ISAPI filter, so calls to Exchange are done to IIS virtual directories on the Exchange server. WebDAV is good for doing many different things (creating and reading items), however not everything is documented. WebDAV does support working with items such as messages, contacts, folders, etc. You can create, delete, modify, move (within a store) or copy (within a store) an item. Also, you will be able to use it to upload files to the exchange stores. WebDAV is often used when there is no ability to run code on the exchange server or the code needs to be executed outside of the network. It will work with MAPI and non-MAPI stores. HTTP and HTTPS are supported along with different authentication methods (Basic, Windows, etc). Note that WebDAV is available for both Exchange 2000 and 2003 - however it is not available for Exchange 5.5. For .NET applications accessing Exchange items off the Exchange Server, only WebDAV is supported - unless you can run the code directly on the Exchange server. WebDAV calls are thread-safe where as many messaging APIs are not or have other issues which make them not supported under .NET code. Please review the following: Support Policy for Microsoft Exchange APIs with .NET Framework Applications http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B813349 With WebDAV, you will be able to interact with Exchange items with the code running on any machine which can do an HTTP call and pass the needed information. This allows the code to run from pretty much any device or OS. Most things such as working with calendar items, email, permissions and such can be handled via WebDAV. However, some things such as Outlook specific items (tasks, etc) are not supported. One downside which people run into is the need to learn XML in order to do the call. While needing to know some basic XML is needed, it’s not too hard to pickup the needed skill. WebDAVs strengths are working with properties and items in Exchange Stores – however, WebDAV itself has no business-logic built-in – its up to the developer to provide that. WebDAV can be used by both Outlook and Outlook Express. With Outlook Express, its usage is very limited since you’ll pretty much be limited to messages. Other applications such as BizTalk can also talk to Exchange via WebDAV. As time goes by, you are likely to see more applications which will use WebDAV. In Exchange 12, WebDAV is deemphasized and Web Services are the suggested API to use instead. WebDAV 101. Last Revised 6/28/06. Version 1.6 2 EXCHANGE WebDAV 101 II. WebDAV Basics In order to do WebDAV development, you will need to know some basics. First we will go over the basics of a WebDAV call. Next, you should know the basics of the XML language and how it is used in different languages. After that, you should understand the basic WebDAV verbs used to perform different actions. Next, it’s important to understand authentication. A. The Request WebDAV calls are performed by an HTTP request. The request can be done by any component capable of doing an HTTP call – this means that non-Microsoft components can be used to do the call. In non-managed applications, the XML DOM is often used to create the request object (Example: MSXML2.ServerXMLHTTP30). .NET applications should use the native HttpWebRequest class for the request. Using non-.NET languages: For non .net applications, you should use the XML DOM. For .NET applications, you should use .NET classes. The XML DOM is the Microsoft XML parser COM object and can be called from any language which is COM enabled. .NET has its own classes for working with XML and doing WebDAV requests, so its better to user these for WebDAV. What is the XML DOM? http://msdn.microsoft.com/library/en-us/xmlsdk/html/DOM_What_Is_XML_DOM.asp?frame=true A Beginner's Guide to the XML DOM http://msdn.microsoft.com/library/en-us/dnxml/html/beginner.asp?frame=true Communicating XML Data over the Web with WebDAV http://msdn.microsoft.com/library/en-us/dnxmlweb/html/xmlandwebdav.asp?frame=true Using .NET languages: For .NET applications, you should use system.net and system.xml. system.xml http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemxml.asp system.net - HttpWebRequest http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemnethttpwebrequestclasstopic.asp?frame=true Server Versus WinInet With the XML DOM you can use Server or WinInet http requests for webdav calls. MSDN recommends using the server object for the call in re of WinInet on a server. Server: MSXML2.ServerXMLHTTP30 WinInet: Msxml2.XMLHTTP30 B. A Basic WebDAV Call Below is a sample showing how to do a GET against an email an exchange server (a GET returns the stream of an item). While this call is very basic, it should give you an idea of how a call is done. Dim sHREF Dim sResponse Dim HttpWebRequest WebDAV 101. Last Revised 6/28/06. Version 1.6 3 EXCHANGE WebDAV 101 sHREF = "http://myserver/exchange/Administrator/Inbox/MyEmail.EML" set HttpWebRequest = CreateObject("microsoft.xmlhttp") HttpWebRequest.Open "GET", sHREF, False HttpWebRequest.setRequestHeader "Content-type:", "text/xml" HttpWebRequest.setRequestHeader "Translate:", "f" ' TODO: Uncomment for Exchange access HttpWebRequest.Send sResponse = HttpWebRequest.ResponseText ' Returns as text Set HttpWebRequest = Nothing wscript.echo sResponse sHREF is set to the URL of a mail item in the Administrator’s Inbox. “myserver” is the name of the exchange server and “exchange” is the IIS virtual directory which is mapped into Exchange. Before the request can be done, a connection needs to be opened. When this is done, authentication credentials are passed. If no credentials are sent, then an access attempt using windows authentication will ultimately be done by default. Different types of WebDAV verbs require different headers to be set in different situations – in this case, a header of “Translate” is set to “f” in order properly get back the stream of the item. When the request is sent, the send may or may not need to be passed additional information – such as XML to process or string containing a stream of information to use. After the request is done, the request text (ResponseText) can then be used to get the result of the call. C. Synchronous vs Asynchronous Processing There are two ways requests can be processed - asynchronous and synchronously. Synchronous calls will cause the code to halt until a response is returned. Asynchronous calls allow the code to execute and the response to be processed later. Asynchronous will have higher performance and will help avoid lockups when the DAV request is taking a long time. However, synchronous is easier to write and debug. With Asynchronous calls, setting waitForResponse will cause the code to wait for the specified time period for the HTTP response. While this is going on, it will pump messages so that the application will not hang. With the XML DOM, Synchronous calls are specified by setting the third parameter of the open method for the http request to false. A setting of True will cause the call to be asynchronously. Below are examples of these calls: VB Example – Synchronous: sXMLReq = “…..” oXMLHTTP.open "PROPFIND", sUrl, False, sMyUser, sMyPassword oXMLHTTP.setRequestHeader "Content-Type", "text/xml" oXMLHTTP.send sXMLReq Debug.Print oXMLHTTP.responseText VB Example - Asynchronous: VB Example - Asynchronous: oXMLHTTP.open "PROPFIND", sUrl, True, sMyUser, sMyPassword oXMLHTTP.setRequestHeader "Content-Type", "text/xml" oXMLHTTP.send sXMLReq While oXMLHTTP.readyState <> 4 oXMLHTTP.waitForResponse 1000 Wend Debug.Print oXMLHTTP.responseText C++ Example - Asynchronous: pIXMLHTTPRequest.CreateInstance(__uuidof(ServerXMLHTTP30)); WebDAV 101. Last Revised 6/28/06. Version 1.6 4 EXCHANGE WebDAV 101 … string strUrl = "http://myexserver/exchweb/bin/auth/owaauth.dll"; hr=pIXMLHTTPRequest->open("PROPFIND", _bstr_t((char *)strUrl.c_str()), false); string strXML = “…………”; … hr=pIXMLHTTPRequest->send(_bstr_t((char *)strXML.c_str())); // waitForResponse will have code execution wait until the code response is aquired AND // it will also pump messages so that it won't cause a lockup while its waiting. VARIANT Timeout; VariantInit(&Timeout); Timeout.vt = VT_I4; Timeout.lVal = 60; // Timeout value of 60 seconds. long readyState = READYSTATE_UNINITIALIZED; readyState = pIXMLHTTPRequest->GetreadyState(); while (readyState != READYSTATE_COMPLETE) { //Passing vtMissing as the first parameter sets the timeout value to infinite. // waitForResponse works as a message pump while waiting for the response, // this way the app won't lock up the system. hr = pIXMLHTTPRequest->waitForResponse(Timeout); readyState = pIXMLHTTPRequest->GetreadyState(); } long status = pIXMLHTTPRequest->status; printf("Status of the request is: %d\n",status); _bstr_t t = pIXMLHTTPRequest->getAllResponseHeaders(); printf("Response headers are: %s\n",(char *)t); D. Authentication WebDAV supports several types of authentication including Windows, NTLM, Basic and FBA(forms based). Each has it benefits and limitations. Due to NTLM being outdated, it will not be covered here. The authentication methods supported are largely controlled by the virtual directory permissions. “exchange” and “public” are the most often used folders – you should set permissions carefully. The authentication method of the virtual directory being accessed must match that of the WebDAV code or the call will not work. If you have OWA or another application which relies on these settings, you may want to create different directory which maps to the exact same settings as these. By doing this, you can have a directory with permissions specific to your application. If Anonymous is turned on, the WebDAV calls will fail since Anonymous will be used instead of any other specified protocol. Please note that you should make modifications to virtual directory settings using ESM and not IIS directly. WebDAV 101. Last Revised 6/28/06. Version 1.6 5 EXCHANGE WebDAV 101 F 1 . Basic Authentication A Basic Authentication call will pass credentials in clear text. Because of this, its not a good idea to be used in unsecured networks to remote machines or if SSL is not being used. With the XML DOM, you would pass the credentials in the open statement: HttpWebRequest.Open "GET", sHREF, False, sUserName, sPassword For .NET, you would create a credential cache and add credential s to the HttpWebRequestsimilar to the following: myCred = New NetworkCredential(m_Connection.UserName, m_Connection.Password) MyCredentialCache = New CredentialCache MyCredentialCache.Add(myUri, "Basic", myCred) HttpWRequest.Credentials = MyCredentialCache 2. Windows Authentication: With the XMLDOM, you do not need to pass the user and password. In VB: HttpWebRequest.Open "GET", sHREF, False WebDAV 101. Last Revised 6/28/06. Version 1.6 6 EXCHANGE WebDAV 101 Or in C++: hr=pIXMLHTTPRequest->open("PROPFIND", _bstr_t((char *)strUrl.c_str()), false); For .NET, you would create a credential cache and add credential similar to the following: HttpWRequest.Credentials = CredentialCache.DefaultCredentials Note that besides the network using Kerberos and all machines involved being under the same domain, you must have “Enable Integrated Windows Authentication” checked under Internet Options/Advanced tab in Internet Explorer in addition to the IIS virtual directory settings. The reason for this is that WebDAV will use the settings of IE in its call. If this code is running in an ASPX page and you wish to have the following in the web.config file: <authentication mode="Windows" /> <identity impersonate="true"/> Further, if the web page is neither on the Exchange server nor the client machine, the Exchange server will need to be setup to be trusted for authentication by the Exchange server’s DC. This is required in order to get around issues with passing credentials. This is known as the double-hop credential problem. This can be done though AD on the DC. 3. FBA: If FBA is enabled in the Exchange System Manager (ESM), then WebDAV will need to authenticate using FBA authentication. In order to use FBA, SSL should be to configured and enabled in addition to turning on WebDAV 101. Last Revised 6/28/06. Version 1.6 7 EXCHANGE WebDAV 101 FBA in ESM. Please note that the machine running the WebDAV code with an SSL URL will need to have the certificate installed on it. Enabling FBA is controlled by checking the “Enable Forms Based Authentication” found under the properties of the HTTP protocol for the Exchange server in the Exchange System Manager. You may be prompted to setup SSL if it’s not already. If you don’t want to setup SSL, there is a work-around. Even though it’s not advised, you can use FBA without SSL. This is not advised because credentials will be passed in clear text – which could be sniffed. To configure FBA to work without SSL for your development environment follow these steps: 1. Open the registry editor (run regedit.exe) 2. If it doesn’t exist already add an OWA key under: HKLM\System\CurrentControlSet\Services\MSExchangeWeb 3. Under the OWA key add a DWord value named “AllowRetailHTTPAuth” 4. Set the value of this DWord to “1” The following article is a sample of using FBA with WebDAV: 891748 How to programmatically access your Exchange Server 2003 Inbox using http://support.microsoft.com/?id=891748 This is generally how it works: 1 An HTTP POST is done to /exchweb/bin/auth/owaauth.dll with an authentication string. 2) The authentication string looks like this: Dim strServerName as string = “Myserver” Dim strDomain as string = “myserverdomain.something.com” Dim strUserName as string = “myuser” Dim strPassword as string = “mypassword” 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" 3) WebReq.KeepAlive and AllowAutoRedirect should be set to True on the request. 4) Note: If you are doing an asynchronous call, you need to wait for the response – or the code will fail. For .NET you could setup a callback. WebDAV 101. Last Revised 6/28/06. Version 1.6 8 EXCHANGE WebDAV 101 5) In the response from the POST, you will get back cookie strings in the headers. These strings need to be extracted and placed into one string. This will hold your credentials for future WebDAV calls. These credentials will be good for a period of time (most often 20 minutes depending upon settings). 6) Now that you have the credentials, a header of “Cookie" with the data consisting of the combined cookie strings in each WebDAV call you make. WebDAVRequest.Headers.Add("Cookie", strReusableCookies) 7) If you get a response from the WebDAV call saying "The operation has timed-out.", then the credentials have expired. You will need to get new credentials (start with step 1) and do the WebDAV call again. 4. In Closing: If you use a network monitoring tool such as Netmon, you will see that each time a WebDAV call is done, there is an initial check to see if Anonymous is valid – this is normal and will happen even when you have specified the authentication protocol. Anonymous overrides other protocols, so it really should never be enabled on the exchange virtual. If Anonymous is enabled, authenticating with the protocols will not work. So, the WebDAV call will likely fail. The reason for this is that connecting to stores such as mailboxes requires that you access using a domain account with permissions to the store (ex: mailbox). If you run into problems, it’s a good idea to try using OWA to see if the problem reproduces. If Basic is only selected on the virtual directory, you should get prompted for credentials with a windows login box. Windows authentication should never prompt you. FBA authentication should direct you to a logon form. E. XML and Verbs XML is a structured storage data description language. It uses tags similar to HTML. WebDAV uses XML to specify data to process and returns XML data from most of its responses. In order to use WebDAV in most situations, you will need to understand basic XML. Below are some links to help you get started if you are not familiar with XML. Understanding XML Technologies http://msdn.microsoft.com/XML/Understanding/ XML Developer Center http://msdn.microsoft.com/xml/default.aspx The example below is used in a PROPFIND in order to get a list of all properties for an item. Here you will see “<D:propfind xmlns:D="DAV:">”. The “propfind” indicates the command parameters will be passed. The “xmlns” indicates the namespace being used – you could think of it as a way of specifying an alias for part of a property name. In this case, D will be synonymous to “DAV:”. Each WebDAV command will require specific formatting to match what the WebDAV verb being used requires. <?xml version="1.0" ?> <D:propfind xmlns:D="DAV:"> <D:allprop/> </D:propfind> From this, it should be apparent that the XML used in calls must match-up to the WebDAV Verb being used. Because of this, you will want to be careful with how the XML is formed. A lot of errors programmers encounter revolve around bad XML. Verbs: WebDAV 101. Last Revised 6/28/06. Version 1.6 9 EXCHANGE WebDAV 101 WebDAV has many different verbs. Each performs a specific task. Some work on single items, while others work with batches of items. Below are some of the most common verbs used by WebDAV against Exchange: GET PUT DELETE MKCOL DELCOL PROPFIND PROPPATCH COPY MOVE SEARCH X-MS-ENUMATTS Retrieves the stream of an item. This is often used for extracting the text of item or the MIME of things such as a message. Writes stream content to a URI. IT can be used to write text to a file or MIME content. Deletes an item. Used to create folders. . Use DELETE. There is some false documentation with this verb on the web. This retrieves properties on an item as XML. This uses an XML list of properties to return from a specified item. Sets properties on an item. This uses an XML list of properties to set on an item. Copies items within a store. Note that copying between stores is not supported. Moves items within a store. Note that moving between stores is not supported. Searches for item based-upon SQL search. Note that the only SQL verb supported with WebDav is SEARCH. The list of properties to search for is contained in XML. This can be used in retrieving items based-upon ranges (a piece at a time). Searches can be for the immediate folder or on child folders (DEEP). Note that DEEP searches are not supported on public folders (KB 320071demonstrates how to work around this limitation). This enumerates attachments. Its used to get a listing of attachments on an item. The results are returned as XML. In order to get at the attachments themselves, you will need to do a WebDAV GET using the URI of the item attachment. X-MS-ENUMATTS gets you the URI to the attachment. Here is a more complete list and information for the WebDAV verbs: WebDAV Methods http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_methods.asp?frame=true WebDAV Batch Methods http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_esdk_arch_webdav_bmethods.asp WebDAV 101. Last Revised 6/28/06. Version 1.6 10 EXCHANGE WebDAV 101 III. Specifics To Watch Out For A. Searching Appointments: If you want to search for appointments & recurring within a period of time, you should use a WebDAV SEARCH - this will show all appointments. A PROPFIND should only be used when you know that the URI being used points to an appointment EML which you know to be valid. B. Recurring Appointments: For non-recurring appointments, you can use PROPFIND to read the specific appointment's information. You should use a SEARCH for reading recurring appointments. PROPFIND works against existing EML files. Recurring appointments have the recurrence patterns stored in the master appointment (original appointment). Several things can cause expansion of this appointment information into separate EML files. While it may look like a good idea to use a PROPFIND against these EML, it is not – if the expansion has not happened for the dates you are wanting recurring appointment information on, you will not get back any information for these days. Since a SEARCH will return the information reliably, it’s best to use the SEARCH statement for appointments within a specified date/time period. C. Recurring Appointment Exceptions: Recurrence patterns and the exceptions to recurring appointments are stored in the master appointment. If you want to read the exceptions list, you will need to use a WebDAV GET in order to read back the mime text. After doing this, the mime will need to be programmatically parsed. You will see the exception information as VCALENDAR data from the Master Appointments stream. Look for the sections marked BEGIN:EVENT and END:EVENT. The reason for this is that the exceptions are stored within the master appointment. How To Retrieve Exception Information of a Recurring Appointment using WebDAV http://support.microsoft.com/?id=309699 RFC 2447 (RFC2447) http://www.faqs.org/rfcs/rfc2447.html D. Recurring Appointment Pattern: Just like exceptions to recurring appointments, the recurrence pattern is stored in the master appointment. You will need to do a WebDAV GET in order to read back the mime text. After doing this, the mime will need to be programmatically parse the MIME stream and extract the pattern. How To Retrieve Exception Information of a Recurring Appointment using WebDAV http://support.microsoft.com/?id=309699 RFC 2447 (RFC2447) http://www.faqs.org/rfcs/rfc2447.html E. Searching for Recurring Appointments: If you modify an Outlook recurring appointment to have an exception, all instances will appear when performing a WebDAV search. However, if you do not make changes to a recurring appointment, only the master appointment item will appear in the WebDAV search. Then, how do you programmatically retrieve a recurring appointment's individual instances via WebDAV even if the instances are not exceptions to the appointment recurrence? You can programmatically retrieve the individual instances of a recurring appointment by performing a time framed WebDAV search. The following code demonstrates how to perform a time framed search via WebDAV. Note that the following will code will return n+1 items for a recurring appointment with n instances. The additional result is the master item. Sub GetApptsInTimeFrame() Const SERVERNAME = "server" Const MAILBOXNAME = "mbx" Const UserName = "domain\user" Const Password = "password" WebDAV 101. Last Revised 6/28/06. Version 1.6 11 EXCHANGE WebDAV 101 Const folder = "Calendar" sUrl = "http://" & SERVERNAME & "/exchange/" & MAILBOXNAME & "/" & folder sStartTime = "2004-06-06T00:00:00.000Z" ‘ Note: Watch the format of the dates. sEndTime = "2004-06-11T00:00:00.000Z" ‘ Note: Watch the format of the dates. Debug.Print sUrl Dim strPropReq As String strPropReq = "<?xml version='1.0'?>" & _ "<d:searchrequest" & _ " xmlns:d=""DAV:""" & _ " xmlns:cal=""urn:schemas:calendar:"" >" strPropReq = strPropReq & "<d:sql> SELECT ""DAV:href"", ""urn:schemas:calendar:dtstart"", ""urn:schemas:calendar:dtend"" " & _ "FROM Scope('SHALLOW TRAVERSAL OF """ & sUrl & """ ')" & _ "WHERE ""DAV:contentclass"" = 'urn:content-classes:appointment'" & _ "AND ""urn:schemas:calendar:dtstart"" &lt;= CAST(""" & sEndTime & """ AS ""dateTime.tz"")" & _ "AND ""urn:schemas:calendar:dtend"" &gt;= CAST(""" & sStartTime & """ AS ""dateTime.tz"")" strPropReq = strPropReq & "</></>" Dim oXMLHttp As XMLHTTPRequest Set oXMLHttp = CreateObject("Microsoft.XMLHTTP") With oXMLHttp .Open "SEARCH", sUrl, False, UserName, Password .setRequestHeader "Content-type:", "text/xml" .setRequestHeader "Depth", "1,noroot" .setRequestHeader "Translate", "f" .setRequestHeader "Content-Length", "" & Len(strPropReq) .Send (strPropReq) Debug.Print .Status strOutPutFile = Environ("USERPROFILE") & "\Desktop\XMLOutput.xml" Open strOutPutFile For Output As #1 Print #1, .responseText Close #1 End With Debug.Print "Done processing" End Sub F. Use ESM for Virtual Directory Settings: The security settings of IIS and those found under ESM should always tie together – if the settings are changed via ESM. The docs say changes to the virtual directory settings for Exchange should be done through ESM and not IIS. These setting should always tie together… so use ESM to make the proper settings. For Exchange 2003: ESM authentication settings will update IIS authentication settings. IIS authentication settings will not update ESM authentication settings. The IIS authentication settings will be used over ESM authentication settings. As a rule, don’t have IIS and ESM up at the same time, or you may not see ESM changes reflected in IIS… also, it can be confusing. For Exchange 2000: The same rules apply as for Exchange 2003, however you may need to refresh IIS settings after changing them in ESM. G. Headers: Headers make a great difference for most WebDAV calls. Its important to be sure that you are using the proper headers for each verb, so its best to review the documentation for the verb related to the call you are doing. GET or PUT may fail if the “Translate” header is not set. MOVE or GET may fail if “Overwrite” is not set and the item already exists in the destination. Different verbs require different settings for the “Content-type” header. WebDAV 101. Last Revised 6/28/06. Version 1.6 12 EXCHANGE WebDAV 101 These headers can also change how much will be affected or returned in a call with headers such as “Depth”. Its important to understand how different headers will affect the call you are doing. If you don’t pay attention to these headers, the code may fail or even worse make mass changes which you did not want to happen. WebDAV Headers http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_headers.asp?frame=true WebDAV Methods http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_methods.asp?frame=true WebDAV Batch Methods http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_esdk_arch_webdav_bmethods.asp H. URLScan: URLScan is used to help secure an Exchange Server. However, attention needs to be paid when using URL Scan. URLScan by default will lock-out several of the WebDAV verbs (such as BPROPFIND). URLscan uses a config files which sets the allowed verbs to use. So, you may need to add the needed verbs to the AllowVerbs section of the appropriate config file. 309508 IIS lockdown and URLscan configurations in an Exchange environment http://support.microsoft.com/default.aspx?scid=kb;en-us;309508 Fine-tuning and known issues when you use the Urlscan utility in an Exchange 2003 environment http://support.microsoft.com/default.aspx?scid=kb;en-us;823175 How to configure the URLScan Tool http://support.microsoft.com/default.aspx?scid=kb;en-us;326444 WebDAV 101. Last Revised 6/28/06. Version 1.6 13 EXCHANGE WebDAV 101 IV. WebDAV No-No’s OK, WebDAV can do quite a bit, however there are some things WebDAV cannot do. There are some workarounds supported and unsupported. One method is to use CDOEX make available via a web service or COM+ service. Optionally, CDO 1.21 or MAPI may be used to perform some of these tasks - however this also not suite you. A. Unsupported OWA Commands: If these will not work for you, there are OWA commands which can be called via WebDAV... the problem here is that they are not supported (except for getting Free/Busy information). Customizing Microsoft Outlook Web Access http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=6532E454-073E-4974-A800-1490A7CB358F B. Topics: 1. Reading The GAL. You will need ADSI, CDO 1.21 or Extended MAPI for this. Also, you may use an OWA command to get this information. Format of the OWA call: sServerURL = "http://"+ sServerURL + "/public/?Cmd=galfind Information on the unsupported call is covered in the following article: Customizing Microsoft Outlook Web Access http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=6532E454-073E-4974-A800-1490A7CB358F Here are the supported methods: CDO 1.21: How To Work with Distribution Lists Using CDO (1.x) from Visual Basic http://support.microsoft.com/?id=178787 ADSI: 241474 HOWTO: Render the Global Address List with ADSI http://support.microsoft.com/?id=241474 Extended MAPI: 166106 HOWTO: Getting the Contents of the Exchange Global Address List http://support.microsoft.com/?id=166106 2. Read The Table: The Mailbox Table in Exchange holds a list of Mailboxes and related mailbox information. Reading this table can only be done with Extended MAPI or WMI can be used on an Exchange 2003 server. Nothing else can do this. Extended MAPI can be used with Exchange 5.5 and later. XCLN: How to Retrieve Last Logon Time of Exchange Users Using Extended MAPI http://support.microsoft.com/default.aspx?scid=kb;en-us;259570 IExchangeManageStore::GetMailboxTable http://msdn.microsoft.com/library/default.asp?url=/library/en-us/exchserv/html/intrface_24it.asp With Exchange 2003 and later, you can use WMI: LastLogonTime Property http://msdn.microsoft.com/library/default.asp?url=/library/enus/e2k3/e2k3/_wmiref_pr_Exchange_MailboxLastLogonTime.asp?frame=true WebDAV 101. Last Revised 6/28/06. Version 1.6 14 EXCHANGE WebDAV 101 3. Deleting Attachments. – The DELETE verb only works on Exchange 2003 SP1 - it will not work on any earlier version/service pack. CDOEX, CDO 1.21, Extended MAPI, etc can do this on Exchange 2000 or 2003. One possible work-around is to read the message stream using a WebDAV GET, modify the stream to remove the attachment and then do a PUT to write it back. You will want to watch-out to be sure that you do not lose any custom properties which you have set. Also, you may use an unsupported OWA command to delete the attachment with Exchange 2000 and 2003. To do this, send a POST and "?Cmd=editattach". Again, OWA commands such as this should be avoided since they may not work in future versions of Exchange. 4. Adding Attachments. – There is no mechanism to add an attachment in WebDAV. You will need to create/recreate the item using a WebDAV PUT. The text you would be putting would be the mime of the item, which also contains the attachment. It’s useful here to use CDOSYS to create a message and add an attachment – then extract the MIME from the message and use it for the WEBDAV PUT. You will need a header of "translate" set to "f". If the message already exists, you will need to, you must do a GET on the message stream, which will give you the message + attachments in a string. Next, modify the stream to include a new attachment. After this, the string can be used in a PUT statement to write the attachment. 5. Get Free/Busy Information. CDO 1.21, CDOEX, etc can do this, however WebDAV cannot directly. You may use a GET against OWA to get this information. Here are some things to be aware of: Free/Busy information is stored in the public store under the NON_IPM_SUBTREE folder related for the user. Published Free/Busy information can range between 2 and 36 months. Outlook will publish this information based-upon its settings – this is most often set to 15 or 45 minutes; the default varies between versions of Outlook. MADFB will publish Free/Busy information for OWA – about every 15 minutes. MADFB runs under the System Attendant process. Tentative appointments do not create Schedule+ Free Busy Messages in the Schedule+ Free Busy Folder (See kb 232380). The outlook switch /cleanfreebusy can be used to reset free/busy information. The OWA call is in this format (no line breaks): http: // {server} /public/?cmd=freebusy & start= {ISO8601 start time} &end= {ISO8601 end time} &interval= {interval block in minutes} &u= {SMTP address of organizer/attendee} [&u=user2&u=user3.] In code, it might look like this: sHREF="http://myexserver/public/?Cmd=freebusy&start=2005-03-17T00:00:0007:00&end=2005-03-19T00:00:0007:00&interval=10&u=SMTP:Administrator@mydomain.extest.microsoft.com" Here is a sample from the SDK: http://msdn.microsoft.com/library/en-us/wss/wss/_esdk_checking_free_busy_status_http.asp Checking Free/Busy Status (HTTP): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_esdk_checking_free_busy_status_http.asp Checking Free/Busy Status (CDO) http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_checking_free_busy_status.asp?frame=true WebDAV 101. Last Revised 6/28/06. Version 1.6 15 EXCHANGE WebDAV 101 There is one other way to get this information with WebDAV, although it will take some work. You can do a search on a person's calendar to determine if they will be free or busy.... The problem with this is that the code will need to log-on to the person's mailbox - this will require that the code is running under a user with permission to the mailbox. Processing time will also be a factor when doing this for many users. Here are the steps: 1) Use a WebDAV SEARCH on the person’s appointments between two dates. 2) Parse and convert this information into a useful format by your application. 6. Canceling Appointments. Unfortunately, there is no facility to cancel a meeting via WebDAV. You may be able to delete an appointment directly from a calendar if there are no attendees. A meeting is pretty much an appointment with attendees. If you have an appointment with attendees (i.e. it’s a meeting), you cannot just delete it and expect the attendees to get notified – no cancellation emails are sent. However, there are two ways to work around this. a. Use CDOEX: You will need to use CDOEX on the Exchange server. The code can be called via a web service/web method. Calendars in Exchange 2000 Server http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_calendars_in_exchange.asp?frame=true The Calendar Object Model http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_understanding_the_calendar_object_model.asp?frame=true Canceling a Meeting http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_canceling_an_appointment_as_the_organizer.asp?frame=true Sending Meeting Updates http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_sending_appointment_updates.asp?frame=true b. Reverse Engineer: You can try to reverse engineer the cancellation emails by capturing network traffic when cancellation email is sent via OWA and construct emails for cancellation of the appointment item. Next send these cancellation emails and delete the original appt from the person who made it. There is no public documentation available for the format of Exchange iCalendar cancellation emails. Calendars on the Internet http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_calendars_on_the_internet.asp?frame=true Internet Calendaring and Scheduling Core Object Specification (iCalendar) http://www.ietf.org/rfc/rfc2445.txt RFC 2445 - Internet Calendaring and Scheduling Core Object Specification (iCalendar) http://www.faqs.org/rfcs/rfc2445.html 7. Tasks: WebDAV was not designed for working with outlook specific items such as Tasks. To work with tasks, you will to reverse-engineer the solution and in order to construct the proper XML to be used for a PROPPATCH. 8. Item and Folder Permissions: Permissions to folders and items can be read and changed via WebDAV using an XML descriptor. It’s also possible to use other APIs such as ADO update security settings. An XML descriptor is an XML document in a string which describes security permissions to an item or folder. A PROPFIND is used to read security information. PROPPATCH is used to update the permission. Here is what a descriptor looks like: Example Descriptor in XML http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_example_descriptor_in_xml.asp?frame=true WebDAV 101. Last Revised 6/28/06. Version 1.6 16 EXCHANGE WebDAV 101 This is the format of the descriptor: Exchange Store XML Security Descriptor Format http://msdn.microsoft.com/library/enus/e2k3/e2k3/_exch2k_web_storage_system_xml_security_descriptor_format.asp?frame=true Before starting to use the XML descriptor, it’s important to have an understanding of security… Security http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_web_storage_system_security.asp?frame=true Here are some basic examples on usage: Getting an Item's XML Security Descriptor http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_getting_an_item_s_xml_security_descriptor.asp?frame=true How to add an access control entry to a folder item in Exchange 2000 Web Storage System by coding in Exchange 2000 Server. http://support.microsoft.com/?id=317891 Note: ADO can also be used instead of WebDAV… How To Deny a User Read Permissions on a Mail Item (ADO) http://support.microsoft.com/default.aspx?kbid=289879 Here is some additional information on the subject: Web Storage System Security Roles http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmes2k/html/secroles1.asp 9. Creating Delegates: You cannot create delegates through WebDAV. It is possible to read delegates. An example is supplied at the end of this document. 10. Deep Searches DEEP searches are not supported on public folders. KB 320071 demonstrates how to work around this limitation. How to programmatically get the size of mailboxes in Exchange http://support.microsoft.com/default.aspx?scid=kb;en-us;320071 11. Changing OOF Text: This cannot be done with WebDAV. It “may” be possible to reverse-engineer the actions of OWA using a network trace; however this would be unsupported and unwise. For getting around this, consider using Extended MAPI. WebDAV 101. Last Revised 6/28/06. Version 1.6 17 EXCHANGE WebDAV 101 V. Debugging and Testing: For testing and debugging WebDAV code, there are some tools and techniques which can be used to help resolve problems. There are several tools and a lot of information in the Exchange SDK, so it’s a good idea to have it installed. Exchange 2003 SDK Documentation and Samples March 2005 http://www.microsoft.com/downloads/details.aspx?FamilyID=a865936f-50da-47a0-9dce-f24e8307f38d&displaylang=en Exchange SDK Development Tools http://www.microsoft.com/downloads/details.aspx?FamilyID=4afe3504-c209-4a73-ac5d-ff2a4a3b48b7&displaylang=en A. Check the Response: First, always check the response code and response text to see what you are getting back. The status codes can be looked-up to find an indication of the problem. You will see more specifics in the response text – so be sure to always check it. WebDAV Protocol Status Codes - So the can check for problems http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_webstore_http_webdav_protocol_errors.asp?frame=true B. Exchange Explorer: This a very useful tool used for looking at Exchange stores in an interface which looks similar to Windows Explorer. This tool is part of the Exchange SDK and uses WebDAV to do its own work. Its useful for testing things like permissions and can be used to set properties. Exchange Explorer http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/wsst_web_storage_system_schema_designer.asp C. MFC MAPI: This is an awesome tool for looking at and working with items in Exchange. One great use is for finding properties on items. The source code is available – it is written in C and uses Extended MAPI. This is useful for looking at any properties and for viewing the MIME stream of an item. WebDAV 101. Last Revised 6/28/06. Version 1.6 18 EXCHANGE WebDAV 101 SAMPLE: MFCMAPI Demonstrates MAPI Client Code http://support.microsoft.com/default.aspx?scid=kb;en-us;291794 D. Network Monitor (Netmon): Netmon can be used to sniff the traffic during a WebDAV call. It’s useful for checking what actually is going on during the WebDAV Call. You will be able to see issues like network errors show-up in it. It’s also useful for seeing the WebDAV calls done by OWA to get an idea on how to write your own WebDAV calls. WebDAV 101. Last Revised 6/28/06. Version 1.6 19 EXCHANGE WebDAV 101 About Network Monitor 2.0 http://msdn.microsoft.com/library/en-us/netmon/netmon/about_network_monitor_2_0.asp?frame=true Monitoring Network Traffic http://msdn.microsoft.com/library/en-us/dnw2kmag01/html/NetworkTraffic.asp?frame=true Here are some points to remember: Netcap is a utility which can also capture network activity – this is optional support tool found on the XP install CD. Logs captured via Netcap can be read by Netmon. When capturing traffic, its best to capture all traffic for several seconds prior and after a WebDAV call. When you review the logs, you will see in initial anonymous call. This call should fail and return a list of supported protocols. After this, you should see another call using the designated protocol (Windows, Basic, etc). The second call should work. When capturing traffic, an initial test should be done from the machine running the code. After the log is reviewed, it may be helpful capture traffic from the Exchange server. Some things to look for would be: Incorrect protocol being used, errors, excessive traffic, long delays between request and response. WebDAV 101. Last Revised 6/28/06. Version 1.6 20 EXCHANGE WebDAV 101 E. WebDAV Sample Application: The WebDAV Sample application comes with the Exchange SDK Documentation. It is an HTML file used to do WebDAV calls and can be used for testing as well as a source of sample code. WebDAV 101. Last Revised 6/28/06. Version 1.6 21 EXCHANGE WebDAV 101 F. Tests In addition to the tools, there are some basic tests which you can perform depending upon what the issue is. 1. Basic GET: For checking access and permissions. Do a basic GET against a text file in a non-Exchange virtual directory in order to verify t.hat WebDAV is functioning. This can also be used to be sure that WebDAV is working with SSL dim dim dim dim Dim sHREF sUserName sPassword sResponse HttpWebRequest 'sHREF = "http://myserver/webdav/myfile.txt" ' TODO: change - this is for non exchange. sHREF = "http:// myserver /exchange/Administrator/Inbox/MyEmail.EML" ' TODO: Change - this is for Exchange. sUserName = "domain\user" sPassword = "userpassword" ' TODO: change for Basic Authentication ' TODO: change for Basic Authentication set HttpWebRequest = CreateObject("microsoft.xmlhttp") 'Set HttpWebRequest = New Msxml2.XMLHTTP30 'HttpWebRequest.ContentType = "text/xml" HttpWebRequest.Open "GET", sHREF, False, sUserName, sPassword ' TODO: Use for Basic Authentication ' HttpWebRequest.Open "GET", sHREF, False ' TODO: Use for Windows authentication ‘HttpWebRequest.setRequestHeader "Content-type:", "text/xml" ' TODO: Uncomment for Exchange access ‘HttpWebRequest.setRequestHeader "Translate:", "f" ' TODO: Uncomment for Exchange access HttpWebRequest.Send sResponse = HttpWebRequest.ResponseText ' Returns as text 'ReadAnAttatchment = HttpWebRequest.responseBody ' Returns as encoded Set HttpWebRequest = Nothing wscript.echo sResponse 2. Verify WebDAV is Enabled: WebDAV Enabled? WebDAV can be disabled by the user, so you may want to check it if its not working. Under IIS on a Windows 2003, be sure that WebDAV is enabled, otherwise you will not be able to use WebDAV on that box. Windows 2000: 241520 How to disable WebDAV for IIS 5.0 http://support.microsoft.com/?id=241520 3. Do a PROPFIND PROPFIND with “” - Do a PROPFIND with “” for the XML. If you do a PROPFIND against an item and pass an empty string (“”) or use a PROPALL command, you will get back all of the registered properties (pretty much everything) for that item in XML. This can be useful to verify that the basic PROPFIND is working properly on that system. Use this to tell if it’s the XML being used with the PROPFIND or the actual use of the PROPFIND which is causing the problem. 4. Try it in OWA. If you think the problem you are having is related to permissions you should try to see if OWA has the same problem. If it fails in a manner similar to the code, then its probably not the code having the problem. G. Common Errors: When you get an error from a WebDAV call, you should always know the exact number and text of the error. There are variations on each error message and this information can help pinpoint the problem. WebDAV 101. Last Revised 6/28/06. Version 1.6 22 EXCHANGE WebDAV 101 1. 400 – Bad Request a. This is usually caused by one of the following: 1) Bad XML syntax - Be sure that the syntax is correct. Its usually this problem. Problems formatting dates are common. 2) Schema changes - Try accessing a different folders and different items 3) ISAPI filters - Try turning them off and test. 4) I would think folder permissions would give a permission denied, but its best to check them. 5) If you are using SSL, you will need to configure it properly. 290625 How To Configure SSL in a Windows 2000 IIS 5.0 Test Environment by Using http://support.microsoft.com/?id=290625 6) Having more than 256 connections open can cause a 400 error: PRB: Unable to Make More Than 256 Connections to Different Mailboxes Over a Short Period of Time http://support.microsoft.com/default.aspx?scid=kb;en-us;305619 7) If you have colons or other special characters in the path: http://support.microsoft.com/?id=826437 Note You may also receive this error message if the URL contains the following characters: * % & # b. Things to try: 1) Verify that the path is correct. 2) Try a simpler call like just read the HREF from an item only and see if you get the same error. This will point in a direction. 3) Verify that you can reach the folder via OWA. 4) Be sure that WEBDAV is turned on under the IIS server as well as data connectors. 5) Try using Basic Authentication. 6) Find out the exact error message returning 7) If the error message is like: 400 - Bad Request (Request Header Too Long), This would be caused by a user belonging to so many groups it bloats header. c. Also, refer to the following: HOW TO: Limit the Header Size of the HTTP Transmission That IIS Accepts from a Client in Windows 2000" <http://support.microsoft.com/?id=310156> Kerberos authentication may not work if user is a member of many groups <http://support.microsoft.com/default.aspx?kbid=280830 Unable to Negotiate Kerberos Authentication After Upgrading to Internet Explorer 6 <http://support.microsoft.com/default.aspx?kbid=299838 Internet Explorer Logon Fails Due to an Insufficient Buffer for Kerberos http://support.microsoft.com/default.aspx?kbid=277741 2. 401 – unauthorized Some of the biggest things to look for with unauthorized errors are as follows: a. The protocol which is being used by the application needs to be enabled under the IIS virtual folder being accessed. b. Anonymous should NOT be enabled - if this is turned on, credentials will NOT be passed. c. If the wrong URL is used, then the code may be pointing to something which it does not have permission. d. The DC must have the protocol enabled. For instance, if Kerberos is to be used, then it must be enabled and functional. e. Protocols use different ports. If a firewall or other application filters network traffic to these ports, then the protocol will not work. Firewalls, routers and filtering software have been known to cause problems in this area. WebDAV 101. Last Revised 6/28/06. Version 1.6 23 EXCHANGE WebDAV 101 f. The credentials must be correct. If your using Kerberos, the code must be using a user account with a valid mail box on that server. If credentials are specified (for instance with Basic authentication), then they need to be able to resolve to that user's mailbox. g. If another user's mailbox is accessed, then the account used to run the code must have permissions to that mailbox. If you get an error accessing another user's mailbox, then try having the code access the mailbox that the code is running under and verify that it can do so. If it can, then add permission to the other user's mailbox so that the account used to run the code has appropriate permission. 3. 403 – Forbidden This means you do not have permission to the item. Check permissions being passed. Perhaps SSL is required and you don’t have a certificate. Not having permission to the mailbox or store may be another cause. 4. 404 - Resource Not Found The properties or item specified are not found. If an item specified in the XML request does not exist, you will likely get this error. You can suppress this by adding an “Brief” set to “t” in a header to the request. HttpWRequest.Headers.Set("Brief", "t") 5. 409 - Conflict The URL is messed-up and/or not formatted correctly for the verb. a. If foreign characters or special characters are in the URL, the URL may need to be URL encoded in order to work properly. If you have colons or other special characters in the path: http://support.microsoft.com/?id=826437 b. The 409 errors may be coming from the parent level directories not existing. So, if the following folder does not exist… http://myserver/Public/Public%20Folders/All%20Public%20Folders/Corporate/ …when creating “MyFolder” to have a folder of… http://myserver/Public/Public%20Folders/All%20Public%20Folders/Corporate/MyFolder …you will get a 409 error. Note that a 405 error would indicate that the folder was already created (405 basically means not allowed – check the response for details). c. If the URL is not correct for the verb being used, it may fail with this error. An example of this would be doing a PUT to the URL of the folder - without specifying a file. d. For troubleshooting, I’d suggest doing a GET on the URL. (Be sure to use a header of “translate” set to “f”. If this fails, verify that the message exists by using OWA. If OWA works with that message URL, then try URL encoding the URL when doing the GET. You should also consider using Exchange Explorer for testing the URL. WebDAV 101. Last Revised 6/28/06. Version 1.6 24 EXCHANGE WebDAV 101 VI. Questions and Answers A. Mailbox Access Question: How to use WebDAV to access mailboxes across Exchange servers? Answer: If there is a front-end server setup, you can access by opening a connection using HTTP or HTTPS and to WebDAV they would seem seamless - i.e. one server. This is what I have seen used almost all of the time. Using Microsoft Exchange 2000 Front-End Servers http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=AFAD8426-572E-40F8-99DA-EB7198F374C4 You may also be able to access a server using <\\.\BackOfficeStorage>. This path only is good for the Exchange server where the code must be running from. The <\\.\BackOfficeStorage> path is not normally used with WebDAV and it is what the M: drive is mapped to on Exchange 2000. The M: drive is not mapped to this with Exchange 2003. Accessing files directly with file system access through the M: drive or <\\.\BackOfficeStorage> is not supported. I see this method used for access using CDOEX/ADO most of the time and almost never for WebDAV. XADM: How to Use \\.\ Namespace to Gain Access to the Information Store http://support.microsoft.com/?id=239743 The File: URL Scheme http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_the_file_url_scheme.asp?frame=true Accessing two mailboxes on two different servers with WebDAV should use the same path that you would enter into OWA for accessing them from the web using IE. What you would use for an HTTP/HTTPS path is a matter of Exchange and domain configuration. Getting the Host Domain Name http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_getting_the_host_domain_name.asp?frame=true The HTTP: URL Scheme http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_the_http_url_scheme.asp?frame=true B. WebDAV Across Stores Question: Why can't I COPY or MOVE items across stores - i.e. mailboxes, public folders, servers? Answer: COPY and MOVE will fail with a 502 error when trying to work across stores - not supported. You could read the MIME of messages with a GET and use PUT to write the contents to the new location - this will simulate a COPY. Custom properties and storage properties will likely not get copied. You can try using a PROPFIND and PROPPATCH to copy over the custom properties. C. Administrative Mailbox Access Question: Can we create an administrative account that has access to mailboxes on both Sites? Are these in one or two domains? Answer: Please review the article below… XADM: How to Get Service Account Access to All Mailboxes in Exchange 2000 WebDAV 101. Last Revised 6/28/06. Version 1.6 25 EXCHANGE WebDAV 101 http://support.microsoft.com/default.aspx?scid=kb;en-us;262054 D. Set Public Folder Limits Question: I'm unable to set properties such as folder limits on public folders. How do I do this? Answer: You will need to set certain properties such as folder limits using a URL containing the Administrative Virtual Root. Note that the exadmin virtual directory in the Exchange servers IIS Server will need to have the appropriate Directory Security settings for the type of access you are doing (Basic, Windows, NTLM, etc). Using the Administrative Virtual Root http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_exch2k_the_administrative_vroot.asp How To Set Public Folder Storage Limit Properties http://support.microsoft.com/default.aspx?scid=kb;en-us;294671 E. Delays in WebDAV Calls Question: I'm getting a delay when doing a WebDAV call against a server through a firewall. Answer: If both Basic and Windows authentication is turned-on for the Exchange virtual directory on the Exchange server, and WebDAV code tries to access the Exchange box through a firewall having port 88 blocked, you will get a long delay. The reason for the delay is that a Basic call will first attempt Anonymous communication first. When it fails, it uses the response it got back from the server to determine the next attempt. A failed Anonymous check will respond with the protocols supported by the virtual directory. Since the virtual directory supports Windows authentication, the client WebDAV call will try to do authentication against the DC it was told about with the response of the Anonymous check... this is the delay... After the delay, Basic Authentication is then performed - which will work... The credentials are then cached for a short period - which is why additional WebDAV calls done right after the first one will authenticate quickly. If this is the scenario, the following are the options available: 1) Open port 88 2) Have ONLY Basic turned on for the Exchange virtual directory. 3) Create a secondary virtual directory which has the same settings as the Exchange virtual directory; however you will need to be sure that the only difference is that Basic ONLY is enabled on this new virtual directory. One idea is to call this new virtual directory “ExchangeBasic” or perhaps “Exchange2”. F. SSL with WebDAV Question: How do I use SSL with WebDAV? Answer: SSL can be used with WebDAV for added security. Below is an article on setting-up SSL: Q290625 HOWTO: IIS5: How to Configure SSL in a Windows 2000 IIS 5 http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q290625 G. Increasing performance Question: WebDAV 101. Last Revised 6/28/06. Version 1.6 26 EXCHANGE WebDAV 101 How can I Increase Performance? Answer: There are many different things which can impact performance. Here are a few of them. 1) When working with lots of data, first search to get the HREFS of the items, then use the HREFS to work with the individual items. The batch processing verbs (BPROPFIND, BPROPPATCH, etc) work well with these. -this will usually give much better performance. 2 When at all possible, use of batch methods: BPROPFIND, BPROPATCH, etc. 3) Don't “SELECT * ” when doing searches. This is costly performance wise. Only retrieve back what you need. 4) Sniff OWA to see how it does its searches and the types of WebDAV calls it does. 5) Avoid searching non-indexed fields. 6) Indexed fields have urn:schemas-microsoft-com:exch-data:isindexed set to true. 7) Authentication communication: a) Firewall, exchange virtual directory and authentication method being used need to be lined-up for optimal performance. b) Have the virtual directory used in the DAV call support only the protocol you are using. If the virtual directory has both windows and basic authentication turn on and port 88 is blocked, you will run into a delay. c) If you use the XML DOM, you should use the XMLServer HTTP and not INet (client) if the DAV code is running from a server. SSL has a slight slowing effect. d) Asynchronous vs Synchronous communication: Asynchronous will have higher performance and will help avoid lockups when the DAV processing is taking a long time. Synchronous is easier to write and debug. e) Network issues can slow calls. 8) In terms of speed in doing the calls, you should get the best performance with .NET, followed by the XML DOM and then SAX 9) .NET has additional Credential Caching capabilities and has additional authentication settings - see the PreAuthenticate property of the web request for more information. 10) You may want to consider using full text index searches. Below is an article covering this. XWEB: How to Perform Full-Text Searching Using WebDAV http://support.microsoft.com/?kbid=259849 H. NTLM Double-hop Question: How to use WebDAV to access mailboxes using NTLM in a double-hop? Answer: You will need to do something else, such as: 1) Use Kerberos 2) Use Basic Authentication 3) Run the IIS site under an account with credentials to the mailbox. I. WebDAV Transactions Question: Does WebDAV handle Transactions? Answer: Yes it does. Information on this is in the Exchange SDK. WebDAV Transactions http://msdn.microsoft.com/library/en-us/wss/wss/_esdk_arch_webdav_transactions.asp?frame=true Transaction Header http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_transaction_header.asp?frame=true WebDAV 101. Last Revised 6/28/06. Version 1.6 27 EXCHANGE WebDAV 101 LOCK Method http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_lock.asp?frame=true J. Set Folder Permissions Question: Can WebDAV be used to see and/or set permissions on folders? Answer: Yes. The articles below cover this subject. A PROPFIND will get you an XML doc with the security identifier in XML. A PROPPATCH can set it. Item Access Rights http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_item_access_rights.asp?frame=true How to add an access control entry to a folder item in Exchange 2000 Web Storage System by coding in Exchange 2000 Server http://support.microsoft.com/?id=317891 How to work with items in Exchange 2000 by using WebDAV in Visual Basic .NET http://support.microsoft.com/?id=314181 How To Deny a User Read Permissions on a Mail Item http://support.microsoft.com/kb/289879 Web Storage System Security Roles http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmes2k/html/secroles1.asp K. Accessing OWA Options Question: You are wanting to get Start Of Day and End Of Day fields which show as under Options in OWA. How can WebDAV be used to extract this information? Answer: This information is stored under the root folder of the mailbox. A PROPFIND against the root folder will reveal this information. As an example, a PROPFIND against http://myexchangeserver/exchange/Administrator for the two properties would give the needed information. workdaystarttime Field http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_cdo_schema_exchange_workdaystarttime.asp workdayendtime Field http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_cdo_schema_exchange_workdayendtime.asp NOTE: A WebDAV PROPFIND with a blank string (“”) against the mailbox folder will show you many of the fields from the OWA Options window. NOTE: Not all the options settings in OWA are reachable via WebDAV. OWA uses a POST with a special command which changes these with code which runs on the server. WebDAV 101. Last Revised 6/28/06. Version 1.6 28 EXCHANGE WebDAV 101 VII. Samples Here are some basic samples: A. VBS - SEARCH dim strExchangeURL dim strApptStartDate dim strUser dim strPassword strUser = "Administrator" strPassword = "test" strExchangeURL = "http://myexserver/exchange/Administrator/Calendar/" strApptStartDate = "2004-04-09T15:00:00Z" Dim sRet strQuery = "<?xml version='1.0'?>" & _ "<g:searchrequest xmlns:g='DAV:' >" & _ "<g:sql>SELECT " & vbCrLf & _ """urn:schemas:calendar:alldayevent"", " & vbCrLf & _ """urn:schemas:calendar:duration"", " & vbCrLf & _ """urn:schemas:calendar:dtstart"", " & vbCrLf & _ """urn:schemas:calendar:dtend"", " & vbCrLf & _ """urn:schemas:httpmail:displayto"", " & vbCrLf & _ """urn:schemas:httpmail:displaycc"", " & vbCrLf & _ """urn:schemas:httpmail:textdescription"", " & vbCrLf & _ """urn:schemas:calendar:location"", " & vbCrLf & _ """urn:schemas:httpmail:subject"" " & vbCrLf & _ "FROM SCOPE('SHALLOW TRAVERSAL OF """ & strExchangeURL & """') " & vbCrLf & _ "WHERE (""urn:schemas:calendar:dtstart"" >= CAST(""" & strApptStartDate & """ as 'dateTime')) " & vbCrLf & _ "</g:sql>" & vbCrLf & _ "</g:searchrequest>" & vbCrLf Wscript.Echo "about to call ServerDav" sRet = DoServerDavRequest("SEARCH", strQuery, strExchangeURL, strUser, strPassword) Wscript.Echo sRet Function DoServerDavRequest(sType, sQuery, sHREF, sUserName, sPassword) ' Create the SQL query textnode and append it to document. Set docRequest = Createobject("MSXML2.DomDocument") Set xndQuery = docRequest.createTextNode(strQuery) ' Create the XMLHTTP object. Set davRequest = CreateObject("MSXML2.SERVERXMLHTTP") davRequest.open sType, sHREF, False, "Administrator", "test" davRequest.setRequestHeader "Content-Type", "text/xml" davRequest.setRequestHeader "Translate", "f" ' Send the SEARCH request. if sQuery = "" then davRequest.send else davRequest.send (sQuery) end if WebDAV 101. Last Revised 6/28/06. Version 1.6 29 EXCHANGE WebDAV 101 DoServerDavRequest = davRequest.responsetext End Function SEARCH Using Range Headers Public Function GetItemListXML(sHREF, sUserName, sPassword, sDepth) Dim sQuery ' As String Dim sText 'As String sQuery = "<?xml version='1.0'?>" & _ "<g:searchrequest xmlns:g='DAV:'>" & _ "<g:sql>SELECT ""DAV:displayname"", " & _ """DAV:href"" " & _ "FROM SCOPE('SHALLOW TRAVERSAL OF """ & sHREF & """')" & _ " WHERE ""DAV:isfolder"" = false AND ""DAV:ishidden"" = false" & _ "</g:sql>" & _ "</g:searchrequest>" sText = DoDavRequest("SEARCH", sQuery, sHREF, sUserName, sPassword, sDepth) GetItemListXML = sText End Function Public Function DoDavRequest(sType, sQuery, sHREF, sUserName, sPassword, sDepth) Dim HttpWebRequest 'As MSXML2.XMLHTTP30 Set HttpWebRequest = CreateObject("microsoft.xmlhttp") ' = New MSXML2.XMLHTTP30 Dim sText 'As String ' Open the folder HttpWebRequest.open sType, sHREF, False, sUserName, sPassword ' Set up request headers HttpWebRequest.setRequestHeader "Content-Type", "text/xml" HttpWebRequest.setRequestHeader "Depth", "0" HttpWebRequest.setRequestHeader "Range", sDepth 'HttpWebRequest.setRequestHeader "Range", "rows=10-20,40-50" ' Example of multiple ranges ' Send the query HttpWebRequest.send (sQuery) sText = HttpWebRequest.ResponseText Set HttpWebRequest = Nothing DoDavRequest = sText End Function Dim Dim Dim Dim sHREF sUserName sPassword sRet sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change sHREF = "http://myexserver/exchange/administrator/inbox" ' TODO: change sDepth = "rows=0-3" sRet = GetItemListXML(sHREF, sUserName, sPassword, sDepth) wscript.echo sRet sDepth = "rows=4-7" sRet = GetItemListXML(sHREF, sUserName, sPassword, sDepth) wscript.echo sRet WebDAV 101. Last Revised 6/28/06. Version 1.6 30 EXCHANGE WebDAV 101 B. VBS - PROPFIND dim dim dim dim Dim dim sHREF sUserName sPassword sResponse HttpWebRequest sReq ' Body Proppatch statement sHREF = "https://myexserver/exchange/Administrator/Inbox/testabcd.EML" ' TODO: change ‘ If only the folder is specified, all items will have a PROPFIND done on them ‘sHREF = "http://myexserver/exchange/administrator/Inbox/" ' TODO: change sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change set HttpWebRequest = CreateObject("microsoft.xmlhttp") 'Set HttpWebRequest = New Msxml2.XMLHTTP30 HttpWebRequest.Open "PROPFIND", sHREF, False, sUserName, sPassword HttpWebRequest.setRequestHeader "Content-Type", "text/xml" 'HttpWebRequest.setRequestHeader "Depth:","0" HttpWebRequest.setRequestHeader "Depth:","1" sReq sReq sReq sReq sReq sReq = = = = = = "" "<?xml sReq & sReq & sReq & sReq & version='1.0'?>" "<d:propertyupdate xmlns:d='DAV:' xmlns:m='urn:schemas:mailheader:'>" "<d:set><d:prop>" "<m:subject>" & "test1" & "</m:subject>" "</d:prop></d:set></d:propertyupdate>" sReq = "<?xml version='1.0'?>" & _ "<a:propfind xmlns:a='DAV:' xmlns:m='urn:schemas:mailheader:' xmlns:n='urn:schemas:httpmail:'>" & _ "<a:prop>" & _ "<m:subject/>" & _ "<m:to/>" & _ "<m:from/>" & _ "<m:cc/>" & _ "<m:bcc/>" & _ "<n:date/>" & _ "<n:datereceived/>" & _ "<n:importance/>" & _ "<n:textdescription/>" & _ "<n:htmldescription/>" & _ "<a:isfolder/>" & _ "<a:displayname/>" & _ "<a:href/>" & _ "</a:prop>" & _ "</a:propfind>" HttpWebRequest.Send sReq sResponse = HttpWebRequest.ResponseText ' Returns as text 'ReadAnAttatchment = HttpWebRequest.responseBody ' Returns as encoded wscript.echo sResponse Set HttpWebRequest = Nothing C. VBS - PROPPATCH dim sHREF dim sUserName WebDAV 101. Last Revised 6/28/06. Version 1.6 31 EXCHANGE WebDAV 101 dim dim Dim dim sPassword sResponse HttpWebRequest sReq ' Body Proppatch statement sHREF = "https://myexserver/exchange/Administrator/Inbox/testabcd.EML" sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change ' TODO: change set HttpWebRequest = CreateObject("microsoft.xmlhttp") 'Set HttpWebRequest = New Msxml2.XMLHTTP30 HttpWebRequest.Open "PROPPATCH", sHREF, False, sUserName, sPassword HttpWebRequest.setRequestHeader "Content-Type", "text/xml" HttpWebRequest.setRequestHeader "Depth:","0" sReq sReq sReq sReq sReq = = = = = "<?xml sReq & sReq & sReq & sReq & version='1.0'?>" "<d:propertyupdate xmlns:d='DAV:' xmlns:m='urn:schemas:mailheader:'>" "<d:set><d:prop>" "<m:subject>" & "test1" & "</m:subject>" "</d:prop></d:set></d:propertyupdate>" wscript.echo sReq HttpWebRequest.Send sReq sResponse = HttpWebRequest.ResponseText ' Returns as text 'ReadAnAttatchment = HttpWebRequest.responseBody ' Returns as encoded Set HttpWebRequest = Nothing D. VBS - DELETE dim dim dim dim Dim sHREF sUserName sPassword sResponse HttpWebRequest sHREF = "http://myexserver/exchange/Administrator/Inbox/testabcd.EML" sUserName = "Administrator" sPassword = "test" set HttpWebRequest = CreateObject("microsoft.xmlhttp") HttpWebRequest.Open "DELETE", sHREF, False, sUserName , sPassword HttpWebRequest.Send sResponse = HttpWebRequest.ResponseText ' Returns as text Set HttpWebRequest = Nothing wscript.echo sResponse E. VBS - GET dim sHREF dim sUserName dim sPassword dim sResponse Dim HttpWebRequest sHREF = "http://myexserver/exchange/Administrator/Inbox/testabcd.EML" change sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change WebDAV 101. Last Revised 6/28/06. Version 1.6 ' TODO: 32 EXCHANGE WebDAV 101 set HttpWebRequest = CreateObject("microsoft.xmlhttp") HttpWebRequest.Open "GET", sHREF, False, sUserName, sPassword HttpWebRequest.setRequestHeader "Content-type:", "text/xml" HttpWebRequest.setRequestHeader "Translate:", "f" HttpWebRequest.Send sResponse = HttpWebRequest.ResponseText ' Returns as text Set HttpWebRequest = Nothing wscript.echo sResponse F. VBS - PUT ' This example shows how to do a PUT of a message to a folder. ' Use Outlook Express to create a message and save it as c:\MyTestEmail.eml ' Do the TODO Sections '----------------------------------------------------------------------------------' ReadFileText - Used to PUT (write) an item to a file in a folder. ' Parameters: ' sFile - The file to read ' ' Returns: ' A string containing the content of the file. '----------------------------------------------------------------------------------Function ReadFileText (sFile) Dim objFSO 'As FileSystemObject dim oTS dim sText Set objFSO = CreateObject("Scripting.FileSystemObject") Set oTS = objFSO.OpenTextFile(sFile) sText = oTS.ReadAll oTS.close set oTS = nothing Set objFSO = nothing ReadFileText = sText end Function '----------------------------------------------------------------------------------' DoWebdavPut- Used to PUT (write) an item to a file in a folder.' Parameters: ' sFolder - The complete URI to PUT the item (includes item name). ' sText - The contents to write in the file. ' sUser - User ID for logging in. Set to "" if using windows authentication ' sPassword - Password for logging in. Set to "" if using windows authentication ' Returns: ' Status response text '-------------------------------------------------------------------------------Private Function DoWebdavPut(sFolder, sText, sUser, sPassword) Dim oXMLHttp 'As New MSXML2.XMLHTTP30 Dim bSucess 'As Boolean Dim iStatus 'As Integer Dim sStatus 'As String Dim sResponse 'As String set oXMLHttp = CreateObject("microsoft.xmlhttp") If sUser <> "" Then oXMLHttp.Open "PUT", sFolder, False, sUser, sPassword WebDAV 101. Last Revised 6/28/06. Version 1.6 33 EXCHANGE WebDAV 101 Else oXMLHttp.Open "PUT", sFolder, False ', sUser, sPassword End If oXMLHttp.setRequestHeader "translate", "f" ' Set this to prevent stream problems oXMLHttp.Send sText ' Send the stream across bSucess = False iStatus = oXMLHttp.Status sStatus = oXMLHttp.statusText If (iStatus >= 200 And iStatus < 300) Then wscript.echo "PUT: Success! " & "Results = " & iStatus & ": " & sStatus bSucess = True ElseIf iStatus = 401 Then wscript.echo "PUT: You don't have permission to do the job! Please check your permissions on this item." Else wscript.echo "PUT: Request Failed. Results = " & iStatus & ": " & sStatus End If Set oXMLHttp = Nothing DoWebdavPut = sStatus End Function Dim Dim Dim Dim Dim sHREF 'As String sUserName 'As String sPassword 'As String sFile 'As String sRet 'As String sHREF = "http://myexserver/exchange/Administrator/Inbox/testabcdxx.EML" sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change sFile = "c:\MyTestEmail.eml" ' TODO: change sRet = "" ' TODO: change sString = ReadFileText(sFile) sRet = DoWebdavPut(sHREF, sString, sUserName, sPassword) wscript.echo sRet G. VBS - MOVE Some things to note: Copying or Moving items across stores is not supported You will get a 404 (Resource Not Found) if the source item does not exist. A status204 (No Content) will be returned if the destination item already exists To force an overwrite of an existing item, add a header of “Overwrite” set to “T”. Be careful specifying the destination – Example: Using a message as the source and a folder as a destination may mess-up the folder. '--------------------------------------------------------------------------------' DoCopyMove - Used to move an item from one folder to another in the same store. ' sSourceURL - item being moved/copied ' sDestinationURL - the URL it is going to ' bCopy - TRUE if copying or FALSE if moving ' sUser - User ID for logging in. Set to "" if using windows authentication ' sPassword - Password for logging in. Set to "" if using windows authentication ' NOTE: ' Copying or Moving items across stores is not supported ' You will get a 404 (Resource Not Found) if the source item does not exist. ' A status204 (No Content) will be returned if the destination item already exists '-------------------------------------------------------------------------------- WebDAV 101. Last Revised 6/28/06. Version 1.6 34 EXCHANGE WebDAV 101 Function DoCopyMove(sSourceURL, sDestinationURL, bCopy, sUser, sPassword ) Set oXMLHttp = CreateObject("microsoft.xmlhttp") ' = New MSXML2.XMLHTTP30 Dim sVerb If bCopy = True Then sVerb = "COPY" Else sVerb = "MOVE" End If If sUser <> "" Then oXMLHttp.Open sVerb, sSourceURL, False, sUser, sPassword Else oXMLHttp.Open sVerb, sSourceURL, False ', sUser, sPassword End If oXMLHttp.setRequestHeader "Destination", sDestinationURL ' Send the stream across oXMLHttp.Send If (oXMLHttp.Status >= 200 And oXMLHttp.Status < 300) Then wscript.echo "Success! " & "Results = " & oXMLHttp.Status & ": " & oXMLHttp.statusText ElseIf oXMLHttp.Status = 401 Then wscript.echo "You don't have permission to do the job! Please check your permissions on this item." Else wscript.echo "Request Failed. Results = " & oXMLHttp.Status & ": " & oXMLHttp.statusText End If DoCopyMove = oXMLHttp.statusText Set oXMLHttp = Nothing End Function Dim Dim Dim Dim Dim sSourceURL sDestinationURL sUserName sPassword sRet sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change sSourceURL= "http://myexserver/exchange/Administrator/Inbox/testabcd.EML" ' TODO: change sDestinationURL = "http://myexserver/exchange/Administrator/Inbox/test/testabcd.EML" ' TODO: change sRet = DoCopyMove(sSourceURL, sDestinationURL, False, sUserName, sPassword) wscript.echo sRet H. VBS - COPY Some things to note: Copying or Moving items across stores is not supported You will get a 404 (Resource Not Found) if the source item does not exist. A status204 (No Content) will be returned if the destination item already exists To force an overwrite of an existing item, add a header of “Overwrite” set to “T”. Be careful specifying the destination – Example: Using a message as the source and a folder as a destination may mess-up the folder. '--------------------------------------------------------------------------------' DoCopyMove - Used to move an item from one folder to another in the same store. WebDAV 101. Last Revised 6/28/06. Version 1.6 35 EXCHANGE WebDAV 101 ' sSourceURL - item being moved/copied ' sDestinationURL - the URL it is going to ' bCopy - TRUE if copying or FALSE if moving ' sUser - User ID for logging in. Set to "" if using windows authentication ' sPassword - Password for logging in. Set to "" if using windows authentication '--------------------------------------------------------------------------------Function DoCopyMove(sSourceURL, sDestinationURL, bCopy, sUser, sPassword ) Set oXMLHttp = CreateObject("microsoft.xmlhttp") ' = New MSXML2.XMLHTTP30 Dim sVerb If bCopy = True Then sVerb = "COPY" Else sVerb = "MOVE" End If If sUser <> "" Then oXMLHttp.Open sVerb, sSourceURL, False, sUser, Else oXMLHttp.Open sVerb, sSourceURL, False ', sUser, sPassword End If oXMLHttp.setRequestHeader "Destination", sDestinationURL ' Send the stream across oXMLHttp.Send If (oXMLHttp.Status >= 200 And oXMLHttp.Status < 300) Then wscript.echo "Success! " & "Results = " & oXMLHttp.Status & ": " & oXMLHttp.statusText ElseIf oXMLHttp.Status = 401 Then wscript.echo "You don't have permission to do the job! Please check your permissions on this item." Else wscript.echo "Request Failed. Results = " & oXMLHttp.Status & ": " & oXMLHttp.statusText End If DoCopyMove = oXMLHttp.statusText Set oXMLHttp = Nothing End Function Dim Dim Dim Dim Dim sSourceURL sDestinationURL sUserName sPassword sRet sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change sSourceURL= "http://myexserver/exchange/Administrator/Inbox/testabcd.EML" ' TODO: change sDestinationURL = "http://myexserver/exchange/Administrator/Inbox/test/testabcd.EML" ' TODO: change sRet = DoCopyMove(sSourceURL, sDestinationURL, True, sUserName, sPassword) wscript.echo sRet I. VBS - X-MS-ENUMATTS For listing and reading an attachment, you will first need to get a list of attachments using X-MS_ENUMATTS. After getting the list of attachments you will need to parse out then the URL from the returned information, you can then do a GET to read the attachments. WebDAV 101. Last Revised 6/28/06. Version 1.6 36 EXCHANGE WebDAV 101 First get a list of attachments… Function GetAttachmentsListXML(ByVal sHREF As String, ByVal sUserName As String, ByVal sPassword As String) As String Dim HttpWebRequest As MSXML2.XMLHTTP30 Dim strPropReq As String Dim strOutPutFile As String Set HttpWebRequest = New MSXML2.XMLHTTP30 With HttpWebRequest .Open "X-MS-ENUMATTS", sHREF, False, sUserName, sPassword .setRequestHeader "Content-type:", "text/xml" .setRequestHeader "Depth", "1,noroot" .Send GetAttachmentsListXML = HttpWebRequest.ResponseText End With Set HttpWebRequest = Nothing End Function Now read the attachment… Private Function ReadAnAttatchment(ByVal sHREF As String, ByVal sUserName As String, ByVal sPassword As String) As Variant Dim HttpWebRequest As MSXML2.XMLHTTP30 Dim vReturn As Variant Set HttpWebRequest = New MSXML2.XMLHTTP30 HttpWebRequest.Open "GET", sHREF, False, sUserName, sPassword HttpWebRequest.Send ReadAnAttatchment = HttpWebRequest.ResponseText ' Returns as text 'ReadAnAttatchment = HttpWebRequest.responseBody ' Returns as encoded Set HttpWebRequest = Nothing End Function J. VB.NET PROPFIND ‘ ‘ ‘ ‘ ‘ VB.NET PROPFIND TODO: Create a VB.NET winform with a button and a big multiline text box TODO: Add reverences to System.Web, System.XML and System.IO TODO: Add the code to the form. TODO: Do the TODO sections in the code. Imports System.Net Imports System.Web Imports System.IO Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 'Dim sUri As String = "http://myexserver/exchange/User1/Inbox/" 'Dim sUserName As String = "Administrator" 'Dim sPassword As String = "test" Dim sUserName As String = "" Dim sPassword As String = "" Dim strBody As String WebDAV 101. Last Revised 6/28/06. Version 1.6 37 EXCHANGE WebDAV 101 strBody = "<?xml version='1.0'?>" & _ "<a:propfind xmlns:a='DAV:' " & _ " xmlns:m='urn:schemas:mailheader:' " & _ " xmlns:n='urn:schemas:httpmail:'>" & _ "<a:prop>" & _ " <m:subject/>" & _ " <a:isfolder/>" & _ " <a:displayname/>" & _ " <a:href/>" & _ "</a:prop>" & _ "</a:propfind>" Dim myUri As System.Uri = New System.Uri(sUri) Dim HttpWRequest As HttpWebRequest = WebRequest.Create(myUri) '----------------- Set Credentials -------------------------------------Dim myCred As NetworkCredential Dim MyCredentialCache As CredentialCache If sUserName <> "" Then ' Use Basic Authentication myCred = New NetworkCredential(sUserName, sPassword) MyCredentialCache = New CredentialCache MyCredentialCache.Add(myUri, "Basic", myCred) HttpWRequest.Credentials = MyCredentialCache HttpWRequest.UnsafeAuthenticatedConnectionSharing = True Else ' Use Windows Authentication HttpWRequest.Credentials = CredentialCache.DefaultCredentials 'May need this so you dont get an error on HttpWRequest.GetRequestStream() ‘or double-hop 'HttpWRequest.UnsafeAuthenticatedConnectionSharing = True End If ' Set Headers HttpWRequest.KeepAlive = False HttpWRequest.Headers.Set("Pragma", "no-cache") HttpWRequest.Headers.Set("Translate", "f") HttpWRequest.ContentType = "text/xml" HttpWRequest.ContentLength = strBody.Length 'set the request timeout to 5 min. HttpWRequest.Timeout = 300000 ' set the request method HttpWRequest.Method = "PROPFIND" ' we need to store the data into a byte array Dim ByteQuery() As Byte = System.Text.Encoding.ASCII.GetBytes(strBody) HttpWRequest.ContentLength = ByteQuery.Length Dim QueryStream As Stream = HttpWRequest.GetRequestStream() ' write the data to be posted to the Request Stream QueryStream.Write(ByteQuery, 0, ByteQuery.Length) QueryStream.Close() ' Send Request and Get Response Dim HttpWResponse As HttpWebResponse = HttpWRequest.GetResponse() ' Get Status and Headers Dim iStatCode As Integer = HttpWResponse.StatusCode Dim sStatus As String = iStatCode.ToString() WebDAV 101. Last Revised 6/28/06. Version 1.6 38 EXCHANGE WebDAV 101 'Console.WriteLine("Status: {0} {1}", sStatus, HttpWResponse.StatusDescription.ToString()) 'Console.WriteLine("Request Headers:") 'Console.WriteLine(HttpWRequest.Headers.ToString()) 'Console.WriteLine("Response Headers:") 'Console.WriteLine(HttpWResponse.Headers.ToString()) ' Get Response Stream Dim strm As Stream = HttpWResponse.GetResponseStream() ' Read the Response Steam Dim sr As StreamReader = New StreamReader(strm) Dim sText As String = sr.ReadToEnd() 'Console.WriteLine("Response: {0}", sText) ' Close Stream strm.Close() ' Clean Up HttpWRequest = Nothing HttpWResponse = Nothing MyCredentialCache = Nothing myCred = Nothing strm = Nothing sr = Nothing TextBox1.Text = sText End Sub K. C# Winform - SEARCH // C# Example to SEARCH a mailbox. // TODO: // Add a button and double click on it // Add a multi-line text box and make it big. // Add a project reference to System.Xml, an System.Net // Paste-in the code below // Do the TODO sections in the code. using System.Xml; using System.Net; using System.IO; private void button1_Click(object sender, System.EventArgs e) { string sUri = "http://myemailserver/exchange/auser/inbox/test"; string sUserName = ""; // TODO: Set only for Basic Authentication string sPassword = ""; // TODO: Set only if Basic string sResponse = ""; sResponse = GetMessageListXML(sUri, sUserName, sPassword); textBox1.Text = sResponse; } private string GetMessageListXML(string sUri, string sUserName, string sPassword) { System.Uri myUri = new System.Uri(sUri); WebDAV 101. Last Revised 6/28/06. Version 1.6 39 EXCHANGE WebDAV 101 HttpWebRequest HttpWRequest = (HttpWebRequest)WebRequest.Create(myUri); string sQuery; sQuery = "<?xml version='1.0'?>" + "<g:searchrequest xmlns:g='DAV:'>" + "<g:sql>SELECT \"DAV:displayname\" " + "FROM SCOPE('SHALLOW TRAVERSAL OF \"" + sUri + "\"') " + "WHERE \"DAV:isfolder\" = false" + "</g:sql>" + "</g:searchrequest>"; NetworkCredential myCred; CredentialCache myCredentialCache; myCred = new NetworkCredential(sUserName, sPassword); myCredentialCache = new CredentialCache(); if (sUserName.Length != 0) { myCredentialCache.Add(myUri, "Basic", myCred); HttpWRequest.Credentials = myCredentialCache; } else { HttpWRequest.Credentials = System.Net.CredentialCache.DefaultCredentials; // Next line is for double-hop. This is a winform, so we don’t need it. //HttpWRequest.UnsafeAuthenticatedConnectionSharing = true; } // Set some headers HttpWRequest.KeepAlive = false; HttpWRequest.Headers.Set("Pragma", "no-cache"); HttpWRequest.Headers.Set("Translate", "f"); HttpWRequest.Headers.Set("Depth", "0"); HttpWRequest.ContentType = "text/xml"; HttpWRequest.ContentLength = sQuery.Length; // set the request timeout to 5 min. HttpWRequest.Timeout = 300000; //set the request method HttpWRequest.Method = "SEARCH"; // we need to store the data into a byte array Byte[] ByteQuery = System.Text.Encoding.ASCII.GetBytes(sQuery); //HttpWRequest.ContentLength = ByteQuery.Length; HttpWRequest.ContentLength = ByteQuery.Length; Stream QueryStream = HttpWRequest.GetRequestStream(); // write the data to be posted to the Request Stream QueryStream.Write(ByteQuery, 0, ByteQuery.Length); QueryStream.Close(); //Send Request and Get Response HttpWebResponse HttpWResponse = (HttpWebResponse)HttpWRequest.GetResponse(); // Get Response Stream Stream strm = HttpWResponse.GetResponseStream(); //Read the Response Steam; StreamReader sr = new StreamReader(strm); WebDAV 101. Last Revised 6/28/06. Version 1.6 40 EXCHANGE WebDAV 101 String sText = sr.ReadToEnd(); //Close Stream strm.Close(); // Clean Up HttpWRequest = null; HttpWResponse = null; myCredentialCache = null; myCred = null; QueryStream = null; strm = null; sr = null; return sText; } L. C# Webform – SEARCH – Double-Hop Windows authentication credentials are not forwarded between a web server and Exchange server. This is by design and is referred to as the double-hop credential problem. However, there is a way to get the credentials forwarded. In order for Kerberos credential to flow between an IE client, a web server and the Exchange server, several settings are needed: The network must use Kerberos. The code must be running on a web server which is in the same domain as both the IE client machine and the Exchange server. IE client must have the setting for use Windows Authentication checked. This is set under in IE under Tools/Internet Options/Advanced Tab/Security by checking the “Enable Integrated Windows Authentication” box. The web server running the code must be trusted for authentication delegation by the Exchange server’s DC. This is done through AD. NOTE: There is no getting around doing this – it’s a requirement. o Add the IIS server as a trusted server. o Be sure to check the box to trust the IIS server for delegation. Both the Exchange server and web server running the code will need to have Windows Authentication enabled. Anonymous is turned off on to the Exchange server and web server. The virtual directory used must have Windows Authentication enabled If Visual Studio 2002 was used to build the code, Framework 1.0 would be used. Visual Studio 2003 uses Framework 1.1 by default. If framework 1.1 is not being used/installed on all three machines, the following will apply… You will need to have the current .net service packs installed on your IIS and development box so you can access the “UnsafeAuthenticatedConnectionSharing” property of the HttpWebRequest object (this is new for Framework 1.1). The Framework 1.0 can be updated using hot fix for q323683 if SP2 has not been installed. If SP2 for Framework 1.0 has been installed, you can install q328541 to get the property. Windows 2003 will have Framework 1.1 installed on it already. There must be nothing which will block traffic between the machines. Port 80 and 88 will be used at a minimal. Routers, firewalls and similar hardware/software can block needed traffic – so be aware of any which may sit or run on the machines involved. Note that if you have problems: Verify that the requirements (above) have been covered. Do a simple test by trying to access OWA from the user’s machine; if they cannot access it using IE then the IE settings probably need to be changed. WebDAV 101. Last Revised 6/28/06. Version 1.6 41 EXCHANGE WebDAV 101 Try using Basic Authentication from the Web Server while logged-in as a domain user with a mailbox on the Exchange Server. Try accessing that user’s mailbox. Try using Basic Authentication from the Web Server while logged-in as a domain user with a mailbox on the Exchange Server. Try accessing that user’s mailbox. Try to repro using OWA from the IE client and web server. If OWA works and WEBDAV does not: Recheck your Exchange IIS and trust settings. Recheck the code. If OWA does not work, then the problem is probably not with the code:\ Try getting OWA to work first. Use Netmon on the machine running the code and look for errors and correct communication. As far as code differences between Winform and Webform calls, there are two significant differences: First, the following setting must be made in addition to using default credentials: HttpWRequest.UnsafeAuthenticatedConnectionSharing = true; { HttpWRequest.Credentials = System.Net.CredentialCache.DefaultCredentials; // Need this so you don’t get an error with double-hop auth HttpWRequest.UnsafeAuthenticatedConnectionSharing = true; } Second, the web.config file needs to have the correct settings – as follows: <authentication mode="Windows" /> <identity impersonate="true"/> Here is what part of a web.config may look like: //Be sure that Windows authentication is turned on for the virtual directory //The DC must trust the web server for authentication. //The IE Browser must be set to use Windows authentication. //Be sure that the web.config file reflects the following: <authentication mode="Windows" /> <!-- AUTHORIZATION This section sets the authorization policies of the application. You can allow or deny access to application resources by user or role. Wildcards: "*" mean everyone, "?" means anonymous (unauthenticated) users. --> <authorization> <allow users="*" /> <!-- Allow all users --> <!-- <allow <deny users="[comma roles="[comma users="[comma roles="[comma separated separated separated separated list list list list of of of of users]" roles]"/> users]" roles]"/> --> WebDAV 101. Last Revised 6/28/06. Version 1.6 42 EXCHANGE WebDAV 101 </authorization> <identity impersonate="true"/> M. VBS - GET FREE/BUSY (OWA Call) In order to read Free/Busy information, a GET needs to be done against the public folder for the user’s Mailbox. This request will be processed by OWA. Note that this is currently the only OWA call supported. It’s important to have the URL corrected, so be careful with the date formatting and SMTP address. If your wondering why the public folder is being accessed, it’s because that’s where it is stored – not on the mailbox. M.1 dim dim dim dim Dim VBS - GET FREE/BUSY (OWA Call) sHREF sUserName sPassword sResponse HttpWebRequest sHREF="http://myexserver/public/?Cmd=freebusy&start=2005-03-17T00:00:00-07:00&end=2005-0319T00:00:00-07:00&interval=10&u=SMTP:Administrator@mydomain.extest.microsoft.com" ' TODO: change sUserName = "Administrator" ' TODO: change sPassword = "test" ' TODO: change set HttpWebRequest = CreateObject("microsoft.xmlhttp") HttpWebRequest.Open "GET", sHREF , False, sUserName, sPassword HttpWebRequest.Send sResponse = HttpWebRequest.ResponseText ' Returns as text Set HttpWebRequest = Nothing wscript.echo sResponse M.2 VB.NET - GET FREE/BUSY (OWA Call) The .NET way is similar, however you need to be sure to set these headers: HttpWRequest.Headers.Set("Pragma", "no-cache") HttpWRequest.KeepAlive = True HttpWRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)" N. VB - Send Email With Attachment: To send an email with WebDAV, you will you will need to create/recreate the item with a WEBDAV PUT using the MIME of the message. It gets tricky when working with attachments. To get around the complexity of sending an email with an attachment, you may want to look at using CDOSYS to build the message to send, then extract the MIME stream (MIME of the message in a string) of the resulting message. For sending the message, you would use a PUT statement to write the stream to a file in the Drafts folder of the sending person’s mail box. If you need to set specific properties not set by the MIME, you should do a PROPPATCH against the message in the Drafts folder. Next, the code should use a WebDAV MOVE in order WebDAV 101. Last Revised 6/28/06. Version 1.6 43 EXCHANGE WebDAV 101 to place the message into the mailbox’s submission URL. The Submission URL is a special url used for sending messages. “/##DavMailSubmissionURI##" off of the root of the mailbox is the Submission URL. ' TODO: ' Create a VB Windows program. ' Add a button to the form ' Add references to: ' Active X Data Objectes ' Microsoft CDO for Windows 2000 Library ' Microsoft XML, 3.0 ' Paste-in the code below. ' Do the TODO sections in the code. Option Explicit Private Sub Command1_Click() CreateMessageAndWebDAVSubmit End Sub '----------------------------------------------------------------------------------' CreateMessageAndWebDAVSubmit - Main method for generating message and using WEBDAV ' to send the message. '----------------------------------------------------------------------------------Private Sub CreateMessageAndWebDAVSubmit() Dim sDraftsFolder As String Dim sSubmissionURL As String Dim strAttendeeItem As String Dim dateNow As Date Dim strMIMEStream As String Dim bRet As Boolean Dim sUser As String Dim sPassword As String ' TODO: Change username and password or set to "" if using windows authentication sUser = "Administrator" ' TODO: Change sPassword = "testpassword" ' TODO: Change ' TODO: Change the Drafts folder and submission URLs sDraftsFolder = "http://myexserver/exchange/Administrator/Drafts/SubmittedMail" & GetUniqueString & ".EML" ' TODO: Change this sSubmissionURL = "http://myexserver/exchange/Administrator/##DavMailSubmissionURI##" ' TODO: Change this ' Use CDOSYS to generate the message body parts and such strMIMEStream = BuildMessageAndGenerateMIMEStream() bRet = DoWebdavPut(sDraftsFolder, strMIMEStream, sUser, sPassword) If (bRet = True) Then ' NOTE: ' At this point, the email is in the drafts folder. If you don't want it sent ' automatically, you can comment out the line below. If the line below does not ' execute, you can load the message from Outlook or OWA and send it from there. DoWebdavCopyMove sDraftsFolder, sSubmissionURL, False, sUser, sPassword ' MOVE IT TO SUBMISSION !!! End If End Sub '----------------------------------------------------------------------------------' BuildMessageAndGenerateMIMEStream - This will create a CDOSYS message, attach a file ' and return the Mime stream for use with webdav. '----------------------------------------------------------------------------------Private Function BuildMessageAndGenerateMIMEStream() As String Dim oBodyPart As CDO.IBodyPart Dim oMessage As CDO.Message Dim oConfig As CDO.Configuration Dim oFields As ADODB.Fields Dim sFile As String Dim strMIMEStream As String Dim oAttachStream As ADODB.Stream Dim oMIMEStream As ADODB.Stream WebDAV 101. Last Revised 6/28/06. Version 1.6 44 EXCHANGE WebDAV 101 Set oMessage = New CDO.Message Set oConfig = New CDO.Configuration Set oFields = oConfig.Fields With oMessage Set .Configuration = oConfig .To = "Administrator@mydomain.extest.microsoft.com" sender .From = "Administrator@mydomain.extest.microsoft.com" the mail is going to .Subject = "Test" of the message. .TextBody = "Test adding icon" the message. ' TODO: Change to the name of the ' TODO: Change to the name the person ' TODO: Change to the subject ' TODO: Change to the body of .Fields.Update End With ' The File I'm attaching sFile = "C:\output.txt" being sent. Set oBodyPart = oMessage.AddAttachment(sFile, "", "") ' TODO: Change to the name of the file ' Do Attatchment ' NOTE: For your reference... 'With oBodyPart ' ' Set the content class appropriately ' '.ContentMediaType = "mage/x-icon" '"text/html" ' ' Get the decoded content stream so we can use it ' Set oAttachStream = .GetDecodedContentStream() 'End With ' Now get the entire message stream Set oMIMEStream = oMessage.GetStream() ' Read the text out of it strMIMEStream = oMIMEStream.ReadText() Set Set Set Set oMIMEStream = Nothing oAttachStream = Nothing oBodyPart = Nothing oMessage = Nothing ' And return it BuildMessageAndGenerateMIMEStream = strMIMEStream End Function '----------------------------------------------------------------------------------' GetUniqueString - Used to generate a fairly unique string... used in making a ' Unique file name. This is: Datetime + random + serial value '----------------------------------------------------------------------------------Private Function GetUniqueString() As String ' I'm in EST, which is GMT - 5, but it's Daylight Savings, to it becomes GMT - 4 Const TimeZoneOffset As Long = 4 Dim sString As String Dim dateNow As Date Dim iRnd As Single Dim lNum As Long Static lVal As Long lVal = lVal + 1 If lVal > 50000 Then lVal = 1 iRnd = Rnd(CLng(Format(Now, "mmhhmmss"))) lNum = CLng(iRnd * 10000000) dateNow = DateAdd("h", TimeZoneOffset, Now()) sString = Format(dateNow, "yyyyMMdd") & "T" & Format(dateNow, "HHmmss") & "Z" GetUniqueString = sString & CStr(lNum) & lVal ' Datetime + random + serial value End Function '----------------------------------------------------------------------------------' DoCopyMove - Used to PUT (write) an item to a file in a folder. WebDAV 101. Last Revised 6/28/06. Version 1.6 45 EXCHANGE WebDAV 101 ' sFolder - The complete URI to PUT the item (includes item name). ' sText - The contents to write in the file. ' sUser - User ID for logging in. Set to "" if using windows authentication ' sPassword - Password for logging in. Set to "" if using windows authentication '----------------------------------------------------------------------------------Private Function DoWebdavPut(sFolder As String, sText As String, sUser As String, sPassword As String) As Boolean Dim oXMLHttp As New MSXML2.XMLHTTP30 Dim bSucess As Boolean Dim iStatus As Integer Dim sStatus As String Dim sResponse As String If sUser <> "" Then oXMLHttp.Open "PUT", sFolder, False, sUser, sPassword ' TODO: Change username and password Else oXMLHttp.Open "PUT", sFolder, False ', sUser, sPassword ' TODO: Change username and password End If oXMLHttp.setRequestHeader "translate", "f" ' Set this header to prevent DAV from trying to munge our stream oXMLHttp.Send sText ' Send the stream across bSucess = False iStatus = oXMLHttp.Status sStatus = oXMLHttp.statusText If (iStatus >= 200 And iStatus < 300) Then Debug.Print "PUT: Success! " & "Results = " & iStatus & ": " & sStatus bSucess = True ElseIf iStatus = 401 Then Debug.Print "PUT: You don't have permission to do the job! Please check your permissions on this item." Else Debug.Print "PUT: Request Failed. Results = " & iStatus & ": " & sStatus End If Set oXMLHttp = Nothing DoWebdavPut = bSucess End Function '----------------------------------------------------------------------------------' DoCopyMove - Used to move an item from one folder to another in the same store. ' sSourceURL - item being moved/copied ' sDestinationURL - the URL it is going to ' bCopy - TRUE if copying or FALSE if moving ' sUser - User ID for logging in. Set to "" if using windows authentication ' sPassword - Password for logging in. Set to "" if using windows authentication '----------------------------------------------------------------------------------Private Sub DoWebdavCopyMove(ByVal sSourceURL As String, ByVal sDestinationURL As String, ByVal bCopy As Boolean, sUser As String, sPassword As String) Dim oXMLHttp As New MSXML2.XMLHTTP30 Dim sVerb As String If bCopy Then sVerb = "COPY" Else sVerb = "MOVE" End If If sUser <> "" Then oXMLHttp.Open sVerb, sSourceURL, False, sUser, sPassword ' TODO: Change username and password Else oXMLHttp.Open sVerb, sSourceURL, False ', sUser, sPassword ' TODO: Change username and password End If oXMLHttp.setRequestHeader "Destination", sDestinationURL ' Send the stream across oXMLHttp.Send If (oXMLHttp.Status >= 200 And oXMLHttp.Status < 300) Then Debug.Print "Success! " & "Results = " & oXMLHttp.Status & ": " & oXMLHttp.statusText WebDAV 101. Last Revised 6/28/06. Version 1.6 46 EXCHANGE WebDAV 101 ElseIf oXMLHttp.Status = 401 Then Debug.Print "You don't have permission to do the job! Else Debug.Print "Request Failed. Results = " & oXMLHttp.Status & ": " & oXMLHttp.statusText End If Set oXMLHttp = Nothing End Sub O. VBS - Reformatting XML This can be used to make returned XML more easily readable. ' ReformXML - reformats the XML to be more easily readable Private Function ReformXML(sOriginalXML) Dim sXML As String sXML = sOriginalXML sXML = Replace(sXML, "<", (vbCrLf & "<")) sXML = Replace(sXML, "/>", ("/>" & vbCrLf)) sXML = Replace(sXML, (vbCrLf & "</"), ("</")) sXML = Replace(sXML, ("></"), (">" & vbCrLf & "</")) sXML = Replace(sXML, (">" & vbCrLf & vbCrLf & "</"), (">" & vbCrLf & "</")) ReformXML = sXML End Function P. VBS - ReadFileText This example will load a text file and return a string. '----------------------------------------------------------------------------------' ReadFileText - Used to PUT (write) an item to a file in a folder. ' Parameters: ' sFile - The file to read ' ' Returns: ' A string containing the content of the file. '----------------------------------------------------------------------------------Function ReadFileText (sFile) Dim objFSO 'As FileSystemObject dim oTS dim sText Set objFSO = CreateObject("Scripting.FileSystemObject") Set oTS = objFSO.OpenTextFile(sFile) sText = oTS.ReadAll oTS.close set oTS = nothing Set objFSO = nothing ReadFileText = sText end Function Q. VBS - WriteFileText This example will save a string to a file. '------------------------------------------------------------------------------' WriteFileText - Used to PUT (write) an item to a file in a folder. ' Parameters: ' sFile - The file to read ' ' Returns: WebDAV 101. Last Revised 6/28/06. Version 1.6 47 EXCHANGE WebDAV 101 ' A string containing the content of the file. '------------------------------------------------------------------------------Function WriteFileText(sFilePath, sText) Dim objFSO 'As FileSystemObject Dim objTextFile 'As Object Const ForReading = 1 Const ForWriting = 2 Const ForAppending = 8 Set objFSO = CreateObject("Scripting.FileSystemObject") Set objTextFile = objFSO.CreateTextFile(sFilePath, True) ' Write a line. objTextFile.Write (sText) objTextFile.Close 'objTextFile.Close End Function R. MIME The follow is an example message saved from Outlook. To: "someuser@somecompany.com" Subject: This is a test Date: Fri, 17 Jun 2005 13:20:43 -0400 MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_NextPart_000_0006_01C5733F.65DD8F40" X-Priority: 3 X-MSMail-Priority: Normal X-Unsent: 1 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2180 This is a multi-part message in MIME format. ------=_NextPart_000_0006_01C5733F.65DD8F40 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable My Test Email ------=_NextPart_000_0006_01C5733F.65DD8F40 Content-Type: text/html; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML><HEAD> <META http-equiv=3DContent-Type content=3D"text/html; = charset=3Diso-8859-1"> <META content=3D"MSHTML 6.00.2900.2668" name=3DGENERATOR> <STYLE></STYLE> </HEAD> <BODY bgColor=3D#ffffff> <DIV><FONT face=3DArial size=3D2>My Test Email</FONT></DIV> <DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV> <DIV>&nbsp;</DIV></BODY></HTML> WebDAV 101. Last Revised 6/28/06. Version 1.6 48 EXCHANGE WebDAV 101 ------=_NextPart_000_0006_01C5733F.65DD8F40-- S. VB - Reading Delegates Private Sub Command1_Click() '===================================================== 'DoXML takes the href to a document 'and returns the MAPI PR_ENTRYID property expressed in 'a hexadecimal string format such as is used by CDO 1.21 'Function DoXML(strHref) Dim objX Dim objXMLdoc Dim objNode Dim strR As String Dim retXML As String Dim parseStringtemp As String Dim parseString As String strHref = "<<Error! Hyperlink reference not valid.> folders/public folder/subject.eml>" '<<http://servername/exchange/mailboxname/>> Set objX = CreateObject("MSXML2.ServerXMLHTTP") strR = "<?xml version='1.0'?><d:propfind xmlns:d='DAV:' xmlns:m='http://schemas.microsoft.com/mapi/'>" strR = strR & "<d:prop><m:dlmembers/></d:prop></d:propfind>" retXML = DoPropFind(strHref, "<Domain\Username>", "<password>", strR) ' This won't work since we can load "Datatype 'mv.bin.base64'" into the DOM. 'objXMLdoc.setProperty "SelectionNamespaces", "xmlns:d='http://schemas.microsoft.com/mapi/'" 'Set objNode = objXMLdoc.selectSingleNode("/d:dlmembers") 'MsgBox objNode.Text parseStringtemp = Right(retXML, InStr(1, retXML, "<c:v>")) parseString = Left(parseStringtemp, (Len(parseStringtemp) - (InStrRev(parseStringtemp, "<c:v>")))) ' Insert your generic decoding code here: 'DoXML = BinToHex(Decode64(parseString)) DoXML = Decode64(parseString) MsgBox DoXML 'End Function End Sub '-------------------------------------------------------------' DoPropFind ' Searches an HREF for content. ' Input ' sType - "SEARCH", "PROPFIND", etc ' sQuery - Search to perform (XML query document) ' sHREF - Http reference to item(s)/folder ' sUserName - Domain/Username for server ' sPassword - Password for the account above ' Returns: An XML document resulting from the search '-------------------------------------------------------------Public Function DoPropFind(ByVal sHREF As String, ByVal sUserName As String, ByVal sPassword As String, sQuery As String) As String Dim HttpWebRequest As MSXML2.XMLHTTP30 Set HttpWebRequest = New MSXML2.XMLHTTP30 WebDAV 101. Last Revised 6/28/06. Version 1.6 49 EXCHANGE WebDAV 101 'TO use MSXML 2.0 use the following DIM/SET statements 'Dim HttpWebRequest As XMLHTTP 'Set HttpWebRequest = CreateObject("Microsoft.xmlhttp") 'To use MSXML 4.0 use the folloiwing DIM/SET statements 'Dim HttpWebRequest As MSXML2.XMLHTTP40 'Set HttpWebRequest = CreateObject("Msxml2.XMLHTTP.4.0") Dim sText As String ' Open the folder HttpWebRequest.Open "PROPFIND", sHREF, False, sUserName, sPassword ' Set up request headers HttpWebRequest.setRequestHeader "Content-Type", "text/xml" ' Send the query HttpWebRequest.send (sQuery) Debug.Print HttpWebRequest.Status Debug.Print HttpWebRequest.statusText Debug.Print HttpWebRequest.responseText sText = HttpWebRequest.responseText Set HttpWebRequest = Nothing DoPropFind = sText End Function T. VB - An example to create a public folder with storage limit settings. In this example, the following properties are set during the folder creation. outlookfolderclass contentclass The warning limit in KB Prohibit Post at (KB). Maximum item Size (KB) addressbookdisplayname isreadonly ishidden When reading and setting certain properties, it’s necessary to use the exchange admin path. This path provides special admin privileges. An Exchange Admin login must be used when using this path. Private Dim Dim Dim Dim Sub cmdMakeFolder_Click() XMLreq As New MSXML2.XMLHTTP40 sReq As String parsePhone As String sSourceURL As String Set XMLreq = New MSXML2.XMLHTTP40 sSourceURL = "http:// myexserver /Exadmin/admin/MYDOM.EXTEST.MYCOMP.COM/PUBLIC%20FOLDERS/myfolder" ' Note: This URL is broken down as: ' myexserver is the Exchange box name ' MYDOM.EXTEST.MYCOMP.COM is the full domain name the Exchange box is in. ' Exadmin/admin is a special designation giving the login user higher level privs. ' Exchange explorer may/may not need the %20 in PUBLIC%20FOLDERS ' The account you use to log in with Must have full blown Exchange admin privs and be ' a domain acct. 'XMLreq.open "MKCOL", sSourceURL, False, "Administrator", "Pxxxx" ' If the Exchange is the DC, you probably dont have to specify the DC to login XMLreq.open "MKCOL", sSourceURL, False, "mydom\myexserver ", "Pxxxxxxx" ' Here Exchange box is not the DC WebDAV 101. Last Revised 6/28/06. Version 1.6 50 EXCHANGE WebDAV 101 XMLreq.setRequestHeader "Content-Type", "text/xml" sReq = "<?xml version='1.0'?>" sReq = sReq & "<a:propertyupdate xmlns:a='DAV:' xmlns:e='http://schemas.microsoft.com/exchange/' " & _ "xmlns:p='http://schemas.microsoft.com/mapi/proptag/'>" sReq = sReq & "<a:set><a:prop>" & vbCrLf sReq = sReq & "<e:outlookfolderclass>IPF.Folder</e:outlookfolderclass>" & vbCrLf ' Folder class for outlook sReq = sReq & "<a:contentclass>urn:content-classes:folder</a:contentclass>" & vbCrLf ' Folder content class sReq = sReq & "<a:isreadonly>1</a:isreadonly>" & vbCrLf ' Read only sReq = sReq & "<a:ishidden>1</a:ishidden>" & vbCrLf ' Hidden sReq = sReq & "<p:x67790003>1</p:x67790003>" & vbCrLf 'Use the quotas specified by other properties. sReq = sReq & "<e:storagequotaissuewarninglimit>200</e:storagequotaissuewarninglimit>" & vbCrLf 'Issue warning at (Kb). sReq = sReq & "<p:x67210003>1</p:x67210003>" & vbCrLf 'Prohibit post at (Kb). sReq = sReq & "<p:x67220003>1</p:x67220003>" & vbCrLf 'Maximum item size (Kb). sReq = sReq & "<e:addressbookdisplayname>Something</e:addressbookdisplayname>" & vbCrLf sReq = sReq & "</a:prop></a:set></a:propertyupdate>" XMLreq.send sReq Debug.Print "xmlReq.Status = " & XMLreq.Status If XMLreq.Status = "201" Or XMLreq.Status = "207" Then MsgBox "The folder has been created. Status is " & XMLreq.statusText, vbCritical, "Folder Created!!" Else ' Note: Error 405 can mean permissions problem on item already exists. MsgBox "The folder has not been created. Status is " & XMLreq.statusText, vbCritical, " Folder not Created!!" End If End Sub WebDAV 101. Last Revised 6/28/06. Version 1.6 51 EXCHANGE WebDAV 101 VIII. REFERENCE A. Basics. WebDAV Methods http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_methods.asp?frame=true WebDAV Batch Methods http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_esdk_arch_webdav_bmethods.asp Constructing Exchange Store HTTP URLs http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_constructing_web_storage_system_http_urls.asp?frame=true XADM: How to Use \\.\ Namespace to Gain Access to the Information Store http://support.microsoft.com/?id=239743 The File: URL Scheme http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_the_file_url_scheme.asp?frame=true Getting the Host Domain Name http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_getting_the_host_domain_name.asp?frame=true The HTTP: URL Scheme http://msdn.microsoft.com/library/en-us/wss/wss/_exch2k_the_http_url_scheme.asp?frame=true WebDAV Headers http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_headers.asp?frame=true INFO: Outlook Named Properties Are Not Supported by MAPI/CDO http://support.microsoft.com/?id=266353 Default Exchange Store Namespaces http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_default_web_storage_system_namespaces.asp?frame=true Properties by Namespace http://msdn.microsoft.com/library/en-us/e2k3/e2k3/wss_references_nsproperties.asp?frame=true Fields http://msdn.microsoft.com/library/en-us/cdosys/html/_cdosys_fields.asp?frame=true Contacts fields http://msdn.microsoft.com/library/en-us/wss/wss/_cdo_schema_contacts.asp?frame=true Property Data Types http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_property_data_types.asp?frame=true Property Names and WebDAV http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_property_names_and_http_webdav.asp?frame=true Exchange Store WebDAV Protocol - WebDAV Reference http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_webdav_web_store_http_webdav_protocol_reference.asp?frame=true WebDAV Protocol Status Codes - WebDAV Reference http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_webstore_http_webdav_protocol_errors.asp?frame=true B. Security: HTTP Security and ASP.NET Web Services http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_property_names_and_http_webdav.asp?frame=true Authentication and Security Using WebDAV http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_esdk_arch_webdav_security.asp WebDAV 101. Last Revised 6/28/06. Version 1.6 52 EXCHANGE WebDAV 101 C. Related Topics: Customizing Microsoft Outlook Web Access http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=6532E454-073E-4974-A800-1490A7CB358F Customizing Microsoft Outlook Web Access White Paper http://www.microsoft.com/technet/treeview/default.asp?url=/technet/prodtechnol/exchange/exchange2000/proddocs/articles/custowa/custow a.asp HTTP 403 (Forbidden)" error message when Exchange 2003 users try to use Outlook Web Access to access a freedoc that is located in a public folder http://support.microsoft.com/default.aspx?scid=kb;en-us;834743 How to use the System.DirectoryServices namespace in ASP.NET http://support.microsoft.com/?id=329986 PRB: Unable to Make More Than 256 Connections to Different Mailboxes Over a Short Period of Time http://support.microsoft.com/default.aspx?scid=kb;en-us;305619 INFO: Data Types Supported by the MSXML Parser http://support.microsoft.com/default.aspx?kbid=289842 D. Further Reading Background articles: There is no one ultimate article or book on WebDAV for Exchange. However, there are several very good articles on the subject. Below are some links to information which will cover the basic nuts and bolts of this technology. HTTP/Web Distributed Authoring and Versioning (WebDAV) http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_techsel_tech_9.asp?frame=true WebDAV http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_e2k3_http_webdav_access.asp?frame=true WebDAV Methods http://msdn.microsoft.com/library/en-us/wss/wss/_webdav_methods.asp?frame=true Communicating XML Data over the Web with WebDAV http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnxmlweb/html/xmlandwebdav.asp Designing Knowledge Management Solutions with a Web Storage System http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/designkmsols.asp Develop Web Applications with XML and Exchange 2000 http://msdn.microsoft.com/library/en-us/dnmes2k/html/devwebapps.asp?frame=true Building Solutions with Microsoft Exchange 2000 Server http://msdn.microsoft.com/library/en-us/dnmes2k/html/buildingsolutions.asp?frame=true New Development Features in Microsoft Exchange 2000 http://msdn.microsoft.com/library/en-us/dnmes2k/html/NewDevFeaturesE2K.asp?frame=true Building XML Web Services for Microsoft Exchange 2000 Contacts http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmes2k/html/cwswp_0001.asp Developing Applications for the Web Storage System and Outlook Web Access http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmes2k/html/wssdevaccess.asp Exchange Server RFC and standards compliance http://support.microsoft.com/?id=262986 WebDAV 101. Last Revised 6/28/06. Version 1.6 53 EXCHANGE WebDAV 101 E. Some things you can do with WebDAV: There are a many things you can do with WebDAV. Below are articles going over many of the different things you may wish to do. 320071 HOWTO: Programmatically Get the Size of Mailboxes on Exchange Server http://support.microsoft.com/?id=320071 Searching Folders (WebDAV) http://msdn.microsoft.com/library/default.asp?url=/library/en-us/e2k3/e2k3/_exch2k_searching_calendar_folders_webdav.asp Searching the Exchange Store http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_search_tasks.asp?frame=true Searching Calendar Folders with WebDAV http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_searching_calendar_folders_webdav.asp?frame=true Creating a Contact in the Exchange Store (WebDAV) http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_creating_a_contact_webdav.asp?frame=true Deleting a Contact from the Exchange Store (WebDAV) http://msdn.microsoft.com/library/en-us/e2k3/e2k3/_exch2k_deleting_a_contact_webdav.asp?frame=true How to delete objects by using WebDAV in Visual C# .NET on a computer that is running Exchange 2000 http://support.microsoft.com/default.aspx?scid=kb;en-us;313122 HOWTO: Move or Copy Folder Items with WebDAV http://support.microsoft.com/default.aspx?scid=kb;en-us;290111 How to copy or to move a message from one folder to another folder on a computer that is running Exchange 2000 by using Visual C# .NET http://support.microsoft.com/default.aspx?scid=kb;en-us;310289 296713 HOWTO: Send a Message from Visual Basic by Using WebDAV http://support.microsoft.com/?id=296713 321832 How to Change the Outlook Web Access Logon Page http://support.microsoft.com/?id=321832 308373 HOWTO: Send a Meeting Request Using WebDAV http://support.microsoft.com/?id=308373 296126 HOW TO: Create, Modify and Delete Contact Items via WebDAV (PROPPATCH) http://support.microsoft.com/default.aspx?scid=KB;EN-US;296126 WebDAV 101. Last Revised 6/28/06. Version 1.6 54