October, 2008

  • Akash Blogging......

    HOW TO:Iterating through Exchange Mailboxes using CDO 1.21

    • 2 Comments

    I have seen many developers wanting to loop through multiple mailboxes either to get the mailbox size or get the number of emails in different folders. Here is a sample that loops through multiple mailboxes recursively.

    The following sample is a simple VBScript code sample that iterates through all folders in multiple mailboxes. To use this sample, paste the following code in a new text file, and then name the file Iteratemailboxes.vbs:

    'This script logs on to a server that is running Exchange Server and
    'iterates through all the mailboxes recursively.
    
    ' USAGE: cscript Iteratemailboxes.vbs SERVERNAME DATAFILE
    ' This requires that CDO 1.21 is installed on the computer.
    
    Dim obArgs
    Dim cArgs
    Dim objSession
    Dim objInfoStores
    
    ' Get command line arguments.
    Set obArgs = WScript.Arguments
    cArgs = obArgs.Count
    
    Const CdoMsg = 3,ForReading = 1, ForWriting = 2, ForAppending = 8, TristateFalse = 0
    
    Main
    
    Sub Main()
    Dim FileSysObj
    Dim DataFileName
    Dim DataFile
    Dim alias
    
        If cArgs <> 2 Then
            WScript.Echo "Usage: cscript IterateMailboxes.vbs SERVERNAME DATAFILE(Name and Path)"
            Exit Sub
        End If
    
        Set FileSysObj = CreateObject("Scripting.FileSystemObject")
    
        DataFileName = obArgs.Item(1)
    
        Set DataFile = FileSysObj.OpenTextFile(DataFileName, ForReading, False,0)
        
        'Read line by line
        Do While Not DataFile.AtEndOfStream
             alias = DataFile.ReadLine
        
            'Loop through the mailboxes
            Call IterateInfoStores(obArgs.Item(0), alias)
        Loop
       
        DataFile.Close
    
        'Clean Up    
        Set DataFile = Nothing
        Set FileSysObj = Nothing
    
    End Sub
    
    
    Sub IterateInfoStores(ServerName,UserName)
    
    Dim objFolder
    Dim intCounter
    Dim objInfoStore
    Dim sMsg
    
        On Error Resume Next
        
        'Create the new Session Object
        Set objSession = CreateObject("MAPI.Session")
    
        If Err.Number <> 0 Then
          sMsg = "Error creating MAPI.Session."
          sMsg = sMsg & "Make sure CDO 1.21 is installed. "
          sMsg = sMsg & Err.Number & " " & Err.Description
          WScript.Echo sMsg
          Exit Sub
        End If
    
        'Logon to the Mailbox
        objSession.Logon "", "", False, True, 0, False, ServerName & vbLf & UserName
        
        If Err.Number <> 0 Then
          sMsg = "Error logging on: "
          sMsg = sMsg & Err.Number & " " & Err.Description
          WScript.Echo sMsg
          WScript.Echo "Server: " & ServerName
          WScript.Echo "Mailbox: " & UserName
          Set objSession = Nothing
          Exit Sub
        End If
    
        WScript.Echo "Logged On to:" & objSession.CurrentUser
    
        'Loop through the Infostores
        For intCounter = 1 To objSession.InfoStores.Count
            Set objInfoStore = objSession.InfoStores(intCounter)
    
            If Err.Number <> 0 Then
              sMsg = "Error retrieving InfoStore Object: "
              sMsg = sMsg & Err.Number & " " & Err.Description
              WScript.Echo sMsg
              WScript.Echo "Server: " & ServerName
              WScript.Echo "Mailbox: " & UserName
              Set objInfoStore = Nothing
              Set objSession = Nothing
              Exit Sub
            End If
        
            If objInfoStore.Name = "Mailbox - " & objSession.CurrentUser Then
                Exit For
            End If
        Next
        
        Set objFolder = objInfoStore.RootFolder
        
        If Err.Number <> 0 Then
            sMsg = "Error retrieving RootFolder Object: "
            sMsg = sMsg & Err.Number & " " & Err.Description
            WScript.Echo sMsg
            WScript.Echo "Server: " & ServerName
            WScript.Echo "Mailbox: " & UserName
            Set objInfoStore = Nothing
            Set objFolder = Nothing
            Set objSession = Nothing
            Exit Sub
        End If
    
        'Recurse through the sub-folders
        NavigateFolders objFolder
        
        'Logoff from the session
        objSession.Logoff
    
        'Clean Up
        Set objFolder = Nothing
        Set objInfoStore = Nothing
        Set objSession = Nothing
    End Sub
    
    Sub NavigateFolders(MAPIFolder)
    Dim intCounter
    Dim intMessageCounter
    Dim objMessage
    
        On Error Resume Next
    
        WScript.Echo "Folder Name:" & MAPIFolder.Name
    
        For intMessageCounter = 1 To MAPIFolder.Messages.Count
    
            'Implement you own logic here
            Set objMessage = MAPIFolder.Messages(intMessageCounter)
          
            Select Case objMessage.Class
                Case CdoMsg
                     Select Case objMessage.Type
                        Case "IPM.Note"
                            WScript.Echo "Message:" & objMessage.Subject
                        Case "IPM.Appointment"
                            WScript.Echo "Appointment:" & objMessage.Subject
                    End Select
            End Select
        Next
        
        If MAPIFolder.Folders.Count > 0 Then
            For intCounter = 1 To MAPIFolder.Folders.Count
                NavigateFolders MAPIFolder.Folders(intCounter)
            Next
        End If
    
        Set objMessage = Nothing
    End Sub

    The list of mailboxes can be provided via a text file(Datafile). The Datafile contains the aliases of the users(one on each line). So assuming your Datafile is called "Aliases.txt" and is on the C:\, you would run the script as follows:

    C:\>Cscript iteratemailboxes.vbs Exchange2003 C:\Aliases.txt

    The account that you are logged on the computer with must have permissions on the mailboxes that you are trying to iterate through. You can give the permissions by following the steps in the article below:

    How to assign service account access to all mailboxes in Exchange Server 2003
    http://support.microsoft.com/kb/821897/

    Enjoy!

  • Akash Blogging......

    HOW TO:Alter the "SetSecurity" and "Setup" project to support deployment of a VSTO Add-In for All Users

    • 0 Comments

    Why do we need to alter the "SetSecurity" and the "Setup" project? I sincerely suggest you read the following Blog posts and article first, otherwise you will not be able to make sense out of this post.

    Deploying your VSTO Add-In to All Users (Part I)

    Deploying your VSTO Add-In to All Users (Part II)

    Automating the Deployment of Outlook Add-ins by Using Visual Studio Tools for Office Second Edition

    Assuming you have gone through the articles above I will now walk you through the changes that need to be made in the "Setup" and the "SetSecurity" project. I am only targeting Office 2007 as of now.

    Changes to the "Setup" project:

    1) Set InstallAllUsers to TRUE.
    2) Set the Version Number to the product’s version number.
    3) Type your company name in the Manufacturer property.
    4) The completed Registry on Target Machine setting for Office 2007 should look like below:

    Registry Settings

    Note: The name of the add-in will differ.

    Changes to the "SetSecurity" project:

    1) Alter the "Install" method to make sure the CAS policy is configured at the Machine level and not at the User Level. Replace the following line:

    bool allUsers = String.Equals(allUsersString, "1");

    with

    bool allUsers = true;


    Setting the "allUsers" variable to true makes sure that the CAS policy is created at the Machine level and NOT at the User level.

    2) Add the following code to the CaspolSecurityPolicyCreator class in the CaspolSecurityPolicyCreator.cs

    //Change the name of the Add-in to suit your needs
    private const string userAppLocation = @"Software\Microsoft\Office\12.0\User Settings\OutlookAddIn1";
    
    internal static void IncrementCounter()
    {
        RegistryKey instructionKey = null;
        int count = 1;
    
        try
        {
            instructionKey = Registry.LocalMachine.OpenSubKey(userAppLocation, true);
            object value = instructionKey.GetValue("Count");
    
            if (value != null)
            {
                if ((int)value != Int32.MaxValue)
                    count = (int)value + 1;
            }
            instructionKey.SetValue("Count", count);
        }
        finally
        {
            if (instructionKey != null)
                instructionKey.Close();
        }
    }
    
    internal static void RegisterDeleteInstruction()
    {
        RegistryKey instructionKey = null;
        try
        {
            instructionKey = Registry.LocalMachine.OpenSubKey(userAppLocation, true);
    
            if (instructionKey != null)
            {
                //Change the name of the Add-in to suit your needs
                instructionKey.CreateSubKey(@"Delete\Software\Microsoft\Office\Outlook\AddIns\OutlookAddIn1");
            }
        }
        finally
        {
            if (instructionKey != null)
                instructionKey.Close();
        }
    }

    3) Call the "IncrementCounter" method from the Install method.
    4) Call the "IncrementCounter" and the "RegisterDeleteInstruction" methods from the Uninstall method.

    That's all the changes that are needed. I have tried the setup on a Windows XP(Office 2007) machine and it WORKS!

  • Akash Blogging......

    HOW TO: Alter the "SetSecurity" project to grant full trust to the add-in installation folder instead of the add-in assembly

    • 5 Comments

    Its better late than never, I have been wanting to write this post for a long time now and looks like the time has finally come! This is about adapting the "SetSecurity" project to grant Full Trust to the add-in installation folder instead of just the add-in assembly.

    What is "SetSecurity"? This is a sample project that comes with the Deploying Office Solutions Using Windows Installer Version 3 Sample. This project is used to Grant trust to the customization assembly using a custom action. Want to know more? Read the following articles about Deploying Visual Studio 2005 Tools for Office Second Edition Solutions and Granting Permissions.

    Deploying Visual Studio 2005 Tools for Office Second Edition Solutions Using Windows Installer (Part 1 of 2)
    http://msdn.microsoft.com/en-us/library/bb332051.aspx

    Deploying Visual Studio 2005 Tools for Office Second Edition Solutions Using Windows Installer: Walkthroughs (Part 2 of 2)
    http://msdn.microsoft.com/en-us/library/bb332052.aspx

    How to: Grant Permissions to Folders and Assemblies
    http://msdn.microsoft.com/en-us/library/zdc263t0(VS.80).aspx

    Why do I need to grant full trust to an add-in installation folder instead of the assembly? If you add-in is simple and contains only one assembly then this is not required. You will need to do this in case you have other assemblies that are referenced in you project and they are deployed in the Installation folder along with your add-in assembly.

    If only the add-in assembly is trusted you add-in with throw a security exception when it tries to load the other assemblies because they are not trusted. if we trust the installation folder all the assemblies in that folder are trusted and the add-in works fine.

    There is very small change we that we need to make and it need to made to the AddSecurityPolicy method in the "CaspolSecurityPoliceCreator.cs" file.

    Below are the changes:

    1)Replace the following line:


    string arguments = policyLevel + " -q -ag " + parentCodeGroup + " -url \"" + solutionInstallationUrl + "\" Nothing -n \"" + solutionCodeGroupName + "\" -d \"" + solutionCodeGroupDescription + "\"";

    With
    string arguments = policyLevel + " -q -ag " + parentCodeGroup + " -url \"" + solutionInstallationUrl + "\" FullTrust -n \"" + solutionCodeGroupName + "\" -d \"" + solutionCodeGroupDescription + "\"";

    2) Comment out or delete the following try..catch block:

     
    // Add the assembly code group. Grant FullTrust permissions to the main assembly.
    try
    {
        // Use the assembly strong name as the membership condition.
        // Ensure that the assembly is strong-named to give it full trust.
        AssemblyName assemblyName = Assembly.LoadFile(assemblyPath).GetName();
        arguments = policyLevel + " -q -ag \"" + solutionCodeGroupName + "\" -strong -file \"" + assemblyPath + "\" \"" 
               + assemblyName.Name + "\" \"" + assemblyName.Version.ToString(4) + "\" FullTrust -n \"" 
               + assemblyCodeGroupName + "\" -d \"" + assemblyCodeGroupDescription + "\"";
    
        RunCaspolCommand(frameworkFolder, arguments);
    }
    catch (Exception ex)
    {
        try
        {
            // Clean the solutionCodeGroupName.
            RemoveSecurityPolicy(machinePolicyLevel, solutionCodeGroupName);
        }
        catch { }
    
        string error = String.Format("Cannot create the security code group '{0}'.", assemblyCodeGroupName);
        throw new Exception(error, ex);
    }

    These are the only two changes we need to make. The first change grants the solutioninstallationUrl "FullTrust" instead of "Nothing" and the second change deletes the code that grants trust to the add-in assembly.

    The rest is covered in the Deploying Visual Studio 2005 Tools for Office Second Edition Solutions Using Windows Installer: Walkthroughs (Part 2 of 2) article mentioned above.

  • Akash Blogging......

    Issue with updating a PT_BINARY property using WebDAV

    • 0 Comments

    I ran into a strange issue yesterday when I was trying to update a Named property of type PT_BINARY using WebDAV. When I did the PROPPATCH it went through fine and did not fail. When I checked the Named property using MFC MAPI, it was there but the type had changed to PT_STRING8.

    Below is the WebDAV request that I initially sent to update the PT_BINARY Named Property:

    <?xml version="1.0"?>
    <a:propertyupdate xmlns:a="DAV:" xmlns:cal="http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/" 
                       xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882">
        <a:set>
            <a:prop>
                <cal:0x8216 b:dt="bin.base64">D4AAAAiIAAACgAAAAAAAAAAAAAAAAAAAOCVyAzA08gMBjAAAAkwAAAcAgAAWAIAAAAAAAAAAAAAAAA=</cal:0x8216>
            </a:prop>
        </a:set>
    </a:propertyupdate>

    In the request above, notice that I am specifying the data type also and the data is a byte array which is Base64 encoded. What could the problem be? Could this be a BUG?

    The issue was happening because I was missing a "/". Below is the updated request that fixed the problem.

    <?xml version="1.0"?>
    <a:propertyupdate xmlns:a="DAV:" xmlns:cal="http://schemas.microsoft.com/mapi/id/{00062002-0000-0000-C000-000000000046}/" 
                       xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
        <a:set>
            <a:prop>
                <cal:0x8216 b:dt="bin.base64">D4AAAAiIAAACgAAAAAAAAAAAAAAAAAAAOCVyAzA08gMBjAAAAkwAAAcAgAAWAIAAAAAAAAAAAAAAAA=</cal:0x8216>
            </a:prop>
        </a:set>
    </a:propertyupdate>

    I leave it for you to figure out where I was missing out the "/".

  • Akash Blogging......

    HOW TO: Using WebDAV from PowerShell 1.0

    • 0 Comments

    I was just trying my hands on PowerShell and wanted to try using WebDAV from it. I wrote a small sample that searches the inbox of a user for unread mails and lists out the Href and the Subject of the email.

    Create a .PS1 file as below:

    #Change the Server name and Credentials
    [System.String]$serverName ="EX200701"
    [System.String]$UserName="Administrator"
    [System.String]$Password = "TestLab!"
    [System.String]$UserDomain ="mycompany"
    
    [System.Net.HttpWebRequest]$Request
    [System.Net.WebResponse]$Response
    [System.Net.CredentialCache]$MyCredentialCache
    [System.IO.Stream]$RequestStream
    [System.IO.Stream]$ResponseStream
    [System.Xml.XmlDocument]$ResponseXmlDoc
    [System.Xml.XmlNodeList]$SubjectNodeList
    [System.Xml.XmlNodeList]$HrefNodeList
    [System.String]$strQuery
    [byte[]]$bytes
    
    write-host("Accessing Inbox for User:" + $UserName + " using URI " + $URI +"..") -ForeGroundColor Yellow
    $URI = "http://" + $serverName + "/exchange/" + $UserName + "/Inbox/"
    $Request = [System.Net.HttpWebRequest]::Create($URI)
    
    #Set the Credentials
    write-host("Setting the Credentials now..") -ForeGroundColor Yellow
    [System.Net.NetworkCredential]$NetworkCredential = New-Object System.Net.NetworkCredential($UserName, $Password, $UserDomain)
    $MyCredentialCache = New-Object System.Net.CredentialCache
    $MyCredentialCache.Add($URI, "Basic", $NetworkCredential)
    $Request.Credentials = $MyCredentialCache
    
    #Set the headers.    
    write-host("Setting the Headers now..") -ForeGroundColor Yellow
    $Request.ContentType = "text/xml"
    $Request.Method = "SEARCH"
    $Request.Timeout = 300000
        
    $strQuery = "<?xml version=""1.0""?><g:searchrequest xmlns:g=""DAV:"">"
    $strQuery = $strQuery +    "<g:sql>SELECT ""urn:schemas:httpmail:subject"" FROM Scope('SHALLOW TRAVERSAL OF """ + $URI + """') WHERE"
    $strQuery = $strQuery +    " ""urn:schemas:httpmail:read"" = false</g:sql></g:searchrequest>"
    
    $bytes = [System.Text.Encoding]::UTF8.GetBytes($strQuery)
    $Request.ContentLength = $bytes.Length
    $RequestStream = $Request.GetRequestStream()
    $RequestStream.Write($bytes, 0, $bytes.Length)
    $RequestStream.Close()
    $Response = $Request.GetResponse()
    
    #Check the Status
    [System.int32]$intStatusCode = $Response.StatusCode
    
    if ($intStatusCode -ge 200 -and $intStatusCode -lt 300)
    {
        $ResponseStream = $Response.GetResponseStream()
        [System.IO.StreamReader]$streamReader = New-Object System.IO.StreamReader $ResponseStream
        [System.String]$strResponse = $streamReader.ReadToEnd()
        $ResponseStream.Close()
        $ResponseXmlDoc = New-Object System.Xml.XmlDocument
        $ResponseXmlDoc.LoadXml($strResponse)
        $HrefNodeList = $ResponseXmlDoc.GetElementsByTagName("a:href")
        $SubjectNodeList = $ResponseXmlDoc.GetElementsByTagName("d:subject")
            
        if($HrefNodeList.Count -gt 0)
        {
            for($i = 0; $i -lt $HrefNodeList.Count; $i++)
            {
                #Write Out the Href and the Subject of the mail
                write-host("HREF:" + $HrefNodeList.Item($i).psbase.InnerText) -ForeGroundColor Yellow
                write-host("Subject: " + $SubjectNodeList.Item($i).psbase.InnerText) -ForeGroundColor Yellow
                write-host("")
            }
        }
        
    }
    
    $Response.Close()

    To Run the script:
    1)Open the Windows PowerShell Console
    2)Navigate to the location where you have stored the script file.
    3)Type in .\ScriptName.PS1 and hit enter to execute the script.

  • Akash Blogging......

    Saving an email as "Draft" in the Drafts folder

    • 1 Comments

    Have you ever tried to save a email into the Drafts folder using WebDAV? I followed the KB 313128 and altered the code to just save the email to the drafts folder. When I tried to open the email from the Drafts folder using Outlook Web Access(2003) or Outlook it appeared as a "Sent" email although I had not sent it by moving it to the DavMailSubmissionURI. Digging down deeper when I compared the properties of the mail that I saved as a Draft from Outlook and the one I created using WebDAV, here is what I found:

    Message that I had created with WebDAV had the value of the PR_MESSAGE_FLAGS set to MSGFLAG_READ and the message that was created using Outlook or Outlook Web Access had MSGFLAG_READ | MSGFLAG_UNSENT. Unfortunately the PR_MESSAGE_FLAGS is a property that is initialized by the client or message store provider when a message is created and saved for the first time and then updated periodically by the message store provider, a transport provider, and the MAPI spooler as the message is processed and its state changes. There is no way we can change the value of the property after it is saved. More details can be found at the link below.

    PR_MESSAGE_FLAGS
    http://msdn.microsoft.com/en-us/library/ms527629(EXCHG.10).aspx

    My objective was to be able to save the message as a "Draft" in the "Drafts" folder. Not wasting any more time, I started to try various options to fix the problem and get my code to work as expected. My findings:

    The KB 313128 has a variable name "sQuery" which is initialized with the MIME and email body for the "Put" request. This is how is looks like in the article:

    string sQuery;
    DateTime mySentTime = new DateTime();
    sQuery = "From: " + strFrom + "\n" +
    "To: " + strTo + "\n" +
    "Subject: " + strSubject + "\n" +
    "Date: " + DateTime.Now.ToString() + "\n" +
    "X-Mailer: My DAV mailer" + "\n" +
    "MIME-Version: 1.0" + "\n" +
    "Content-Type: text/plain;" + "\n" +
    "Charset = \"iso-8859-1\"" + "\n" +
    "Content-Transfer-Encoding: 7bit" + "\n" + "\n" +
    strBody;

    The only way I could get the code to work was to set the sQuery variable to ""(Blank) and then do a PROPPATCH to set the To, Subject and Body.

    private void SaveToDrafts()
    {
    try
       {
           // TODO: Replace with the name of the computer that is running Exchange 2000.
           string strServer = "ExchServe";
           // TODO: Replace with the sender's alias.
           string strSenderAlias = "sender";
           // TODO: Replace with the recipient's e-mail address.
           string strTo = "recipient@example.com";
           
           string strSubject = "Save to Drafts using HttpWebRequest";
           string strBody = "Hello World";
    
           string sUri;
           sUri = "http://" + strServer + "/Exchange/" + strSenderAlias;
           sUri = sUri + "/Drafts/Testxxxxxxxxx.eml";
    
           System.Uri myUri = new System.Uri(sUri);
           HttpWebRequest HttpWRequest = (HttpWebRequest)WebRequest.Create(myUri);
    
           string sQuery="";
        
           // Set the credentials.
           NetworkCredential myCred = new NetworkCredential(@"DomainName\User", "Password");
           CredentialCache MyCredentialCache = new CredentialCache();
           MyCredentialCache.Add(myUri, "Basic", myCred);
    
           HttpWRequest.Credentials = MyCredentialCache;
    
           // Set the headers.
           HttpWRequest.Headers.Add("Translate", "f");
           HttpWRequest.ContentType = "message/rfc822";
           HttpWRequest.ContentLength = sQuery.Length;
    
           //Set the request timeout to 5 minutes.
           HttpWRequest.Timeout = 300000;
           // Set the request method.
           HttpWRequest.Method = "PUT";
    
           // Store the data in a byte array.
           byte[] ByteQuery = System.Text.Encoding.ASCII.GetBytes(sQuery);
           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 the request and get the response.
           HttpWebResponse HttpWResponse = (HttpWebResponse)HttpWRequest.GetResponse();
    
           // Get the Status code.
           int iStatCode = (int)HttpWResponse.StatusCode;
           
           // Get the request headers.
           string sReqHeaders = HttpWRequest.Headers.ToString();
           
           // Read the response stream.
           Stream strm = HttpWResponse.GetResponseStream();
           StreamReader sr = new StreamReader(strm);
           string sText = sr.ReadToEnd();
           MessageBox.Show("Response:"+ sText);
    
           // Close the stream.
           strm.Close();
    
           // Clean up.
           myCred = null;
           MyCredentialCache = null;
           HttpWRequest = null;
           HttpWResponse = null;
           QueryStream = null;
           strm = null;
           sr = null;
    
           SetToSubjectBody(sUri);
       }
       catch (Exception ex)
       {
           MessageBox.Show(ex.Message);
       } 
    }
    
    private void SetToSubjectBody(string itemURL)
    {
        HttpWebRequest request;
        HttpWebResponse response;
        byte[] bytes;
    
        string format = "<?xml version=\"1.0\"?><g:propertyupdate xmlns:g=\"DAV:\" xmlns:m=\"urn:schemas:httpmail:\" xmlns:z=\"urn:schemas:mailheader:\">"
                + "<g:set>"
                + "<g:prop>"
                + "<z:to>a@a.com</z:to>"
                + "<m:subject>This is a test mail</m:subject>"
                + "<m:textdescription>This is a test mail</m:textdescription>"
                + "</g:prop>"
                + "</g:set>"
                + "<g:remove>" 
                + "<g:prop><m:date/></g:prop>"
                + "</g:remove>" 
                + "</g:propertyupdate>";
    
        request = (HttpWebRequest)HttpWebRequest.Create(itemURL);
    
        // Set the credentials.
        NetworkCredential myCred = new NetworkCredential(@"DomainName\User", "Password");
        CredentialCache MyCredentialCache = new CredentialCache();
        MyCredentialCache.Add(new System.Uri(itemURL), "Basic", myCred);
        
        request.Credentials = MyCredentialCache;
    
        // Set the headers.
        request.ContentType = "text/xml";
        request.Method = "PROPPATCH";
    
        // Store the data in a byte array.
        bytes = Encoding.UTF8.GetBytes(format);
        request.ContentLength = bytes.Length;
    
        // Get the Request Stream
        using (Stream requestStream = request.GetRequestStream())
        {
            // write the data to be posted to the Request Stream
            requestStream.Write(bytes, 0, bytes.Length);
            requestStream.Close();
        }
    
        // Send the request and get the response.
        response = (HttpWebResponse)request.GetResponse();
    
        // Get the Status code.
        int intStatus = (int)response.StatusCode;
        if (intStatus >= 200 && intStatus < 300)
        {
            MessageBox.Show("Success!");
        }
        else
        {
            MessageBox.Show("Failure Code:" + intStatus.ToString());
        }
    
        response.Close();
    
        // Clean up.
        myCred = null;
        MyCredentialCache = null;
        response = null;
        request = null;
    }


    To me it looks like a change in the Exchange 2003 transport that broke this, but now that I have a workaround I am GOOD!

Page 1 of 1 (6 items)