none
Closing mailitems, some help needed RRS feed

  • Question

  •  

    Hi,

     

    I'm using VSTO for Outlook 2007 and Visual Studio 2008 and coding in C#.

     

    Basically I'm using a foreach loop to iterate through each mailItem in the inbox, where if it meets certain criteria i will move it to a different folder. After i move it I wanted to close the mailItem so i don't have many MailItems open at once, however the method confuses me. In the MSDN libraries it's stated as MailItem.Close(OlInspectorClose saveMode)

     

    I've tried to implement it in a few different ways but been unsuccsesful so far, so if anyone could give me a hint on how to implement this Close() i would be thankful.

     

    Thanks a lot

    Tuesday, July 22, 2008 11:07 AM

Answers

  • Hi Taz,

     

    From my understanding, MailItem.Close(SaveMode) is used to close the UI mail item with specified SaveMode, like olDiscard, olPromptForSave, olSave. More detailed, if user open a mail item in an Outlook Inspector with UI, we can call MailItem.Close() to close that inspector. http://msdn.microsoft.com/en-us/library/bb175257.aspx

     

    From your description, you are automating Outlook mail item in a loop without UI. Then, we do not need to call MailItem.Close() method. If you declare the mailitem variable in loop, when the .NET variable goes out of its scope, it will be collected when GC.Collected performs in background. But we are working on COM Interop, the managed object will not be collected unless the underlying COM object is released. We can call Marshal.ReleaseCOMObject function for this objective. http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx

    Codes will look like: (I write the following by hand, not executable codes in IDE)

    foreach(MailItem mail in items)

    {

                If(condition is true)

    {

                mail.Move(…)

    }

    mail = null;

    System.Runtime.InteropServices.Marshal.ReleaseComObject(mail);

    }

     

    Thanks,

    Ji

     

    Monday, July 28, 2008 7:07 AM
    Moderator

All replies

  • I am also having the same issue.  I have too many items open on the server.  I am trying to find the best combination of:

    1) closing the MailItem

    2) setting object to null

    3) agressive garbage collection

     

    I will be watching this post.

     

    Tuesday, July 22, 2008 8:23 PM
  • lol we're both watching the post but i fear we're not going to get any help, if i figure out the solution though i'll let you know

     

    Friday, July 25, 2008 1:41 PM
  • Hi Taz,

     

    From my understanding, MailItem.Close(SaveMode) is used to close the UI mail item with specified SaveMode, like olDiscard, olPromptForSave, olSave. More detailed, if user open a mail item in an Outlook Inspector with UI, we can call MailItem.Close() to close that inspector. http://msdn.microsoft.com/en-us/library/bb175257.aspx

     

    From your description, you are automating Outlook mail item in a loop without UI. Then, we do not need to call MailItem.Close() method. If you declare the mailitem variable in loop, when the .NET variable goes out of its scope, it will be collected when GC.Collected performs in background. But we are working on COM Interop, the managed object will not be collected unless the underlying COM object is released. We can call Marshal.ReleaseCOMObject function for this objective. http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.releasecomobject.aspx

    Codes will look like: (I write the following by hand, not executable codes in IDE)

    foreach(MailItem mail in items)

    {

                If(condition is true)

    {

                mail.Move(…)

    }

    mail = null;

    System.Runtime.InteropServices.Marshal.ReleaseComObject(mail);

    }

     

    Thanks,

    Ji

     

    Monday, July 28, 2008 7:07 AM
    Moderator
  • Thank you this posting was helpful.

     

    I have a question with the garbage collection statements made in your answer.  We have a situation where we essentially run the same code as you have above and are getting an Exchange error.

    • Exchange error Event ID:          9646 (too many messages open at once)
    • Must be running Outlook in non-cache mode
    • Process over say 250 messages, which is default for open messages on the server

    We have used both methods of GC:

    1) System.Runtime.InteropServices.Marshal.ReleaseComObject(mail);  along with

         System.Runtime.InteropServices.Marshal.FinalReleaseComObject(mail);

    AND

    2) GC.Collect() along with GC.WaitForPendingFinalizers();

     

    Neither of these is decrementing the open messages count on the server, and we get above error.  It is almost like the foreach loop is holding onto all items.  A "for loop" seems to alleviate this issue, but for several reasons we are needing to get the foreach loop to work.

     

    code:

    //loop through selected emails
    foreach (object selectedItem in ActiveExplorer().Selection)
    {

    Outlook.MailItem _mailItem = selectedItem as Outlook.MailItem;

     

    //Get To's from mailItem
    string _toDisplay = _mailItem.To;

     

    System.Runtime.InteropServices.Marshal.ReleaseComObject(_mailItem);  //cannot set to null before this call


    System.Runtime.InteropServices.Marshal.FinalReleaseComObject(_mailItem);

     

    //second method below also does not work

    GC.Collect(); //force garbage collection and see if that decrements open message counter on server
    GC.WaitForPendingFinalizers();

    }

     

     

    Wednesday, July 30, 2008 1:32 PM
  • Hi David,

     

    If we want to reclaim the RCW memory right now, we need call GC.Collect() for a second time after we call GC.WaitForPendingFinalizers()

    Code Snippet

    GC.Collect();

    GC.WaitForPendingFinalizers();

    // Only call if you care about reclaiming RCW memory right now.

    GC.Collect();

     

     

    See the following article in msdn blog:

    http://blogs.msdn.com/geoffda/archive/2007/08/31/the-designer-process-that-would-not-terminate.aspx

     

     

    Thanks,

    Ji

     

    Thursday, July 31, 2008 4:41 AM
    Moderator
  • Thank you again, that was some excellent discusion on GC.  However, our problem still remains.  We are considering submitting a case to Microsoft shortly, but I'd rather just figure it out.  Tell me if you have suggestions.

     

    Summary: Outlook 2007/Exchange 2003, VSTO 2005 Outlook add-in.  We loop through over 250 emails, get one property of the email (say 'To' field), and we get the Exchange error above 9646 (too many open messages).  One key item is that the Outlook is in non-cache mode; 2) secondly we are using foreach loop.  Simplified code below, including your suggestion.

     

    Code Snippet

    Outlook.Application _olApp = null;

    Outlook.Explorer _olExp = null;

    int _selectionCount = 0;

    int rpcCount = 0;

    _olApp = new Microsoft.Office.Interop.Outlook.Application();

    _olExp = _olApp.ActiveExplorer();

    _selectionCount = _olExp.Selection.Count;

    //loop through selected emails

    foreach (object selectedItem in _olExp.Selection)

    {

    Outlook.MailItem _mailItem = selectedItem as Outlook.MailItem;

    string _toDisplay; //for display To

    //Get To's from mailItem

    _toDisplay = _mailItem.To;

     

    _mailItem = null;

     

    rpcCount++;

     

    if (rpcCount > 50)

    {

     

    rpcCount = 0;

     

    //force garbage collection and see if that decrements open message counter on exchange server.  We have used both a countdown loop as shown here, and also during each single loop.

    GC.Collect();

    GC.WaitForPendingFinalizers();

    GC.Collect();

    GC.WaitForPendingFinalizers();  //tried a second one also based on the articles

    }

    }

    }

     

     

     

     

    Thursday, July 31, 2008 1:10 PM
  • Hi Daivd,

     

    I tried your codes with a little modified to make it run at my side. The following is my codes

    Code Snippet

            Outlook.Application _olApp = null;

            Outlook.Explorer _olExp = null;

            int _selectionCount = 0;

            int rpcCount = 0;

     

            private void Form1_Load(object sender, EventArgs e)

            {

                _olApp = new Outlook.ApplicationClass();

                _olApp.Explorers.Add(_olApp.Session.GetDefaultFolder (Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox), Microsoft.Office.Interop.Outlook.OlFolderDisplayMode.olFolderDisplayNormal);

                _olApp.Explorers[1].Activate();

                _olExp = _olApp.ActiveExplorer();

            }

     

            private void button1_Click(object sender, EventArgs e)

            {

                int count = 0;

                _selectionCount = _olExp.Selection.Count;

                //loop through selected emails

     

                foreach (object selectedItem in _olExp.Selection)

                {

                    count++;

                    Outlook.MailItem _mailItem = selectedItem as Outlook.MailItem;

                    string _toDisplay; //for display To

                    //Get To's from mailItem

                    _toDisplay = _mailItem.To;

                    Debug.Print(_toDisplay);

                    _mailItem = null;

                    rpcCount++;

                    if (rpcCount > 50)

                    {

                        rpcCount = 0;

                        //force garbage collection and see if that decrements open message counter on exchange server.  We have used both a countdown loop as shown here, and also during each single loop.

                        GC.Collect();

                        GC.WaitForPendingFinalizers();

                        GC.Collect();

                        GC.WaitForPendingFinalizers();  //tried a second one also based on the articles

                    }

                }

            }

     

    It works fine on my computer. I iterate through about more than 950 emails, did not encounter any "Open Message too many" errors.

     

     

    Thanks,

    Ji

     

    Friday, August 1, 2008 12:20 PM
    Moderator
  • Do you know if you were working via a cached or non-cached mode for your test code?  Non-cache is essential to reproduce the error.  Thank you again

    David

     

    Friday, August 1, 2008 8:04 PM
  • I did try your code: 1)Inside the Outlook add-in; 2) when running Outlook in non-cached mode; and the error still occurs.

     

    {"Your server administrator has limited the number of items you can open simultaneously. Try closing messages you have opened or removing attachments and images from unsent messages you are composing."}

     

    But we're still hoping for an answer.  Thanks for testing.

    David

    Monday, August 4, 2008 3:27 PM
  • Hi David,

     

    Sorry for the late responding! I tried to set Outlook using non-cache mode by setting File->Cached Exchange Mode to Download Headers. And then I sent about 300 new emails to my account for test, used above codes to iterate through these new emails, but it works fine. I did not meet error you mentioned.

    I think this may be also related to Exchange Server Side Setting.

    Have you tried the approach in the following link's discussion:

    http://www.tutorials-win.com/OutlookGen/Outlook-limited-485269/

    We can try to find the server installed Exchange and Disable the session limit by setting the following value to 1
    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MSExchangeIS\ParametersSystem
    Value: Disable Session Limit

     

     

    Thanks,

    Ji

     

    Tuesday, August 5, 2008 1:26 AM
    Moderator
  • Hi Ji,

    thank you for continued help.

     

    1.  I would appreciate it if you could test the non-cached mode using the following method; otherwise I believe you are still working in cahced mode.

     

    To do this:

    Inside Outlook: Tools>Account Settings, then click on "Change" button for the exchange account.  You will see "Change email account"  dialog.   There is a checkbox for "Use Exchange Cached mode", uncheck this box and restart Outlook.

     

    2. I've seen the article you referenced but will pursue this setting with the Exchange Server people.  Although, I see some info which makes me question this fix.  It apparently is looking at a reg key which disables (I guess) Exchange session limit, and my error is not really "too many sessions" it is "too many open items".  Althogh I would note that both of these errors return the same Exchange error code, they just give back different messages with the error.  I guess it is kind of a general "too many something" error, with a message description of exactly WHAT is too many.

     

    Thanks again.

    David

     

    Tuesday, August 5, 2008 12:27 PM
  • Hello David,

     

    Thanks for your detailed information! I have tried to your steps and reproduced the same problem in non-cached Exchange mode.

     

    Based on my opinion, since we can make sure the COM object collected in client side, this issue looks more like related to Server side settings. So, may I suggest, at the meantime, we can consult Exchange Dev Forum http://forums.microsoft.com/TechNet/ShowForum.aspx?ForumID=838&SiteID=17.

     

    And as to the error message we are facing to: "Your server administrator has limited the number of items you can open simultaneously. Try closing messages you have opened or removing attachments and images from unsent messages you are composing.". I highly recommend to have a try the solution in that link, if we can get the Exchange Server machine easily. Because the error message in that link is exactly same as this one. For my guess, maybe each mail item establishes a connect session to exchange server.

     

     

    Best Regards,

    Ji

    Wednesday, August 6, 2008 3:41 AM
    Moderator
  • I have taken your suggested and posted on Exchange forum here:

     

    http://forums.microsoft.com/TechNet/ShowPost.aspx?PostID=3713878&SiteID=17

     

    Feel free to review and comment on the post.  Thank you much for all your help and time.

    David

    Wednesday, August 6, 2008 3:53 PM
  • I have been encountering the same issue but calling the garbage collection as suggested above does seem to work although it is an odd problem in my case as it happens on one computer and not another.

    I have used
     System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
    
      GC.Collect();
      GC.WaitForPendingFinalizers();
      GC.Collect();
      GC.WaitForPendingFinalizers();

    Thursday, September 17, 2009 3:49 PM
  • I had same issue and following code worked for me, too :

     

     System.Runtime.InteropServices.Marshal.ReleaseComObject(item);
    
     GC.Collect();
     GC.WaitForPendingFinalizers();
     GC.Collect();
     GC.WaitForPendingFinalizers();
    



    Wednesday, February 16, 2011 1:38 PM
  • Hi,

    I've been experiencing the "Your server administrator has limited the number of items..." in a small add-in I wrote for Outlook 2007, however, calling System.Runtime.InteropServices.Marshal.ReleaseComObject(item) cured the problem. Do I really need to call the GC.Collect() code, as mentioned, and, if so, what is likely to happen if I don't?

    Regards,

    RobDev


    Robert Ian Ashcroft
    Thursday, February 24, 2011 1:36 PM
  • Those items will remain to be garbage collected and may not have been completely finalized. They will be garbage collected at some point but that's not under your control then.
     
    Calling the garbage collector will take a performance hit obviously.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "RobDev" <=?utf-8?B?Um9iRGV2?=> wrote in message news:73e7e3b2-a39f-489c-a2d3-eab0100e1f6b...

    Hi,

    I've been experiencing the "Your server administrator has limited the number of items..." in a small add-in I wrote for Outlook 2007, however, calling System.Runtime.InteropServices.Marshal.ReleaseComObject(item) cured the problem. Do I really need to call the GC.Collect() code, as mentioned, and, if so, what is likely to happen if I don't?

    Regards,

    RobDev


    Robert Ian Ashcroft

    Ken Slovak MVP - Outlook
    Thursday, February 24, 2011 2:37 PM
  • Hi Ken,

    many thanks for that, I understand now.

    Regards,

    RobDev


    Robert Ian Ashcroft
    Friday, February 25, 2011 11:45 AM
  • Hi Ji,

     

    It is strongly not recommend solution from microsoft to change the Registry of exchange server which hits performance badly.

    http://technet.microsoft.com/en-us/library/dd159906(EXCHG.80).aspx

    Please suggest any other alternatives?

     

    Thank you


    Thanks, Bala at chowdary.soft@gmail.com
    Tuesday, April 26, 2011 8:06 AM
  • You can't set an item to null inside a foreach loop.
    Friday, July 10, 2015 10:45 AM