none
error getting mailbox size from Exchange Server 2003

    Question

  • Hello,

     

    I'm attempting to pull the mailbox size information from our Exchange Server 2003 for a given username.  I've looked over MSDN and got most of the authenication code working, but when I send WebDav the request for mailbox information, I get a error: (400) Bad Request.  I've went as far as cut and pasting in the code from the MSDN website and it doesn't work.  Any ideas? 

     

    here is some of my code:

     

    public string ServerName { get; set; }

     

    public void GetMailboxInfoByWebDav(string strUsername, string strMapiPropTag)
            {
                try
                {
      Int32 totalSize = 0;
                    //hack to bypass ssl certificate 
                    ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(ValidateServerCertificate);

                    //get MailboxUri to send to the web request
                    string strMailboxUri = GetMailboxUri(strUsername);
                    string strQuery = GetQueryString(strMapiPropTag, strMailboxUri);

                    // Create a new CredentialCache object and fill it with the network
                    // credentials required to access the server.
                    this.cdCache = new System.Net.CredentialCache(); 
                    this.cdCache.Add(new System.Uri(strMailboxUri), "NTLM", new System.Net.NetworkCredential(this.Username, this.Password, this.DomainName));

                    // Create the HttpWebRequest object and add the cache credentials to it
                    this.hWebRequest = (System.Net.HttpWebRequest)HttpWebRequest.Create(strMailboxUri);

                    this.hWebRequest.Credentials  = cdCache;

                    this.hWebRequest.Method = "SEARCH";
                    this.hWebRequest.CookieContainer = new CookieContainer();
                    this.hWebRequest.CookieContainer.Add(GetCookiesFormBasedAuthentication(strMailboxUri, new NetworkCredential(this.Username, this.Password, this.DomainName)));
                  
                    //Encode the body using UTF-8
                    this.bytes = Encoding.UTF8.GetBytes(strQuery);

                    //set the content header length.  This must be done before writing data to the request stream
                    this.hWebRequest.ContentLength = bytes.Length;

                    //setup the content header
                    this.hWebRequest.ContentType = "text/xml";
                    this.hWebRequest.Headers.Add("Depth", "0");
                    this.hWebRequest.Headers.Add("Translate", "f");

                    //get reference to the stream
                    this.stRequest = hWebRequest.GetRequestStream();

                    //Write the SQL Query to the request stream
                    this.stRequest.Write(bytes, 0, bytes.Length);

                    //close the stream object to release the connection for further use
                    this.stRequest.Close();
                   
                    //send the search method request and get the reponse from the server
                    this.hWebResponse = (HttpWebResponse)hWebRequest.GetResponse();
                   
                    //get the XML response stream
                    this.stReponse = this.hWebResponse.GetResponseStream();

                    //create the xml document object from the xml response
                    this.xDocResponse = new XmlDocument();
                    this.xDocResponse.Load(stReponse);

                    // Build a list of the DAV:href XML nodes, corresponding to the folders
                    // in the mailbox.  The DAV: namespace is typically assgigned the a:
                    // prefix in the XML response body.
                    this.xnlHrefNodes = xDocResponse.GetElementsByTagName("a:href");
                   
                    // Build a list of the http://schemas.microsoft.com/mapi/proptag/x0e080003
                    // XML nodes returned in the search request. The
                    // http://schemas.microsoft.com/mapi/proptag/ namespace is typically
                    // assigned the d: prefix in the XML response body.
                    this.xnlSizeNodes = xDocResponse.GetElementsByTagName("d:x0e080003");
                   
                    //loop throug the list of nodes and total up the sizes of the mailbox folders
                    for (int i=0; i < xnlHrefNodes.Count; i++)
                    {
                        //get the folder name
                        Console.WriteLine("{0}, {1}",this.xnlHrefNodesIdea.InnerText, Convert.ToInt32(this.xnlSizeNodesIdea.InnerText));
                        totalSize += Convert.ToInt32(this.xnlSizeNodesIdea.InnerText);
                    }

             Console.WriteLine("{0}", totalSize.ToString());       

                    //clean-up
                    this.stReponse.Close();
                    this.hWebResponse.Close();
                    this.stRequest.Close();

                    this.stReponse.Dispose();
                    this.stRequest.Dispose();
                  
                }
                catch (Exception ex)
                {
                   
                    throw ex;
                }
            }

     

            public static bool ValidateServerCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                return true;
            }

     

            private CookieCollection GetCookiesFormBasedAuthentication(string strUri, NetworkCredential netCredential)
            {
                string strServer = "";
                HttpWebRequest hWebRequest = null;
                HttpWebResponse hWebResponse = null;
                System.IO.Stream stRequest = null;

                byte[] bBody;

                try
                {
                    strServer = strUri.Substring(0, strUri.IndexOf("/", 8)) + "/exchweb/bin/auth/owaauth.dll";
                    hWebRequest = GetHttpWebRequestObject(strServer, "POST");
                    hWebRequest.ContentType = "application/x-www-form-urlencoded";

                    bBody = Encoding.UTF8.GetBytes(string.Format("destination={0}&username={1}\\{2}&password={3}", strUri, netCredential.Domain, netCredential.UserName, netCredential.Password));

                    hWebRequest.ContentLength = bBody.Length;
                    hWebRequest.Credentials  = cdCache;

                    //send the request to the server
                    stRequest = hWebRequest.GetRequestStream();
                    stRequest.Write(bBody, 0, bBody.Length);
                    stRequest.Close();

                    hWebResponse = (HttpWebResponse)hWebRequest.GetResponse();

                    //check if the login was successful
                    if (hWebResponse.Cookies.Count < 2) throw
                        new Exception("Failed to login to OWA.  Be sure to check your username, password, and domian name");
                    
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                return hWebResponse.Cookies;
            }

     

            private HttpWebRequest GetHttpWebRequestObject(string strUri, string strMethod)
            {
                HttpWebRequest hWebRequest = null;

                System.Uri uri;

                uri = new System.Uri(strUri);
                hWebRequest = (HttpWebRequest)System.Net.WebRequest.Create(uri);

                hWebRequest.CookieContainer = new CookieContainer();
                hWebRequest.Method = strMethod;

                return hWebRequest;
            }

     

            private string GetQueryString(string strMapiPropTag, string strMailboxUri)
            {
                StringBuilder sb = new StringBuilder(@"<?xml version=""1.0""?>");

                sb.Append(@"<gTongue Tiedearchrequest xmlns:g=""DAV:"">");
                sb.Append(@"<gTongue Tiedql>SELECT ""http://schemas.microsoft.com/");
                sb.Append(@"mapi/proptag/x0e080003"", ""DAV:hassubs"" FROM SCOPE ");
                sb.Append(@"('SHALLOW TRAVERSAL OF """);
                sb.Append(strMailboxUri);
                sb.Append(@"""'");
                sb.Append(@"WHERE ""DAV:isfolder"" = true");
                sb.Append(@"</gTongue Tiedql>");
                sb.Append("</gTongue Tiedearchrequest>");

                return sb.ToString();
            }

     

            private string GetMailboxUri(string strUsername)
            {
                StringBuilder sb = new StringBuilder(@"https://");

                sb.Append(this.ServerName);
                sb.Append(@"/exchange/");
                sb.Append(strUsername);
                sb.Append(@"/non_ipm_subtree/");

                return sb.ToString();
            }

     

     

    Thanks,

    Aaron LaBeau

    Wednesday, June 11, 2008 3:29 PM

All replies

  • Hello Aaron,

     

    I've added an article on this topic to my website: http://www.infinitec.de/post/2008/06/Retrieving-the-size-of-a-mailbox-via-WebDAV.aspx.

     

    Kind regards,

    Henning Krause

    Wednesday, June 11, 2008 5:22 PM
  • Henning,

     

    Your website blog is perfect and fixed my first problem.  Now comes the second problem.  I'm actually using System.DirectoryServices.AccountManagement to get a collection of all our users in Active Directory.  I then check to see if they have a Mailbox GUID or not.  If so, then I call this code to get the mailbox information and store that in a SQL database for reporting.  My problem comes in that I'm able to loop through 3 or 4 users but on the 5th user, it always throws a System.Net.WebException: The operation has timed out.  I'm trying to figure out why the timeout is happening?  Any ideas?  I'm starting to believe it's because I'm hitting the server so many times as the same user to get different mailbox information. 

     

    Thanks,

    Aaron LaBeau

     

    Monday, June 23, 2008 5:31 PM
  • Hello,

     

    are you executing the requests asyncronously or syncronously?

     

    If the former is true, I would guess that the requests from the first requests take to long so the latter request get aborted. Internally, the HttpWebRequest class uses a ServicePoint which executes the actual request. This servicepoint is limited to 2 paralell requests per domain by default.

     

    You can increase this value (via the ServicePointManager.DefaultConnectionLimit property) or throttle your requests to two at a time.

     

    Kind regards,

    Henning Krause

    Monday, June 23, 2008 9:06 PM