none
Not All Outlook Mails Processed by Code (Visual C#) RRS feed

  • Question

  • Hi!

    I have what seems like a strange problem with my Outlook Automation.

    I am looping thru' all mails in my Inbox, looking for MailItems and then checking the subject for specific mails and processing them, parsing data in the file, loading that data to a database and then moving the mail to another folder. The problem appears to be in the moving of the mails. Some mails get moved but others do not. I cannot figure out for the life of me why not. I though it might be due to some object locking and garbage collection delay but when I added specific lines for GC it made no difference.

    I have written this code in Outlook VBA originally then converted to VC# as I thought perhaps the VBA was having some performance issue. However, the problem remained the same in both languages. Here is the main() loop of the VC# code. The other functions are peripheral and not impacting. I know this because I commented them out and it made no difference. The code still left mails in the Inbox unmoved.

    The problem is also not related to any of the specific mails. If I execute the code several times eventually all the mails get moved.

            static void Main(string[] args)
            {
                Outlook.Application olApp;
                Outlook.NameSpace olNS;
                Outlook.Folder olFld;
                Outlook.Items olMails;
                Outlook.MailItem olMailItem = null;

                string subj, body;
                const string FolderToFile = "Processed PR Messages";

                olApp = new Outlook.Application();
                olNS = olApp.GetNamespace("MAPI");
                olFld = (Outlook.Folder)olNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
                olMails = olFld.Items;

                ConnectToMySQLServer();    // This is a separate function that works fine and used in many programs already.

                for (int i = 1; i <= olMails.Count; i++)
                {
                    object olItem = olMails[i];
                    olMailItem = olItem as Outlook.MailItem;

                    if (olMailItem != null)
                    {
                        subj = olMailItem.Subject;
                        body = olMailItem.Body;

                        if (ExtractAndStoreMsgInLclDWH(subj, body))   // This function parses the subj & body of the mail then
                                                                                                  // adds the record  to the MySQL table with an insert query. Works fine.
                        {
                           // Move message to processed folder
                            Outlook.MAPIFolder mapiFld;
                            mapiFld = olNS.Folders["david.armour@st.com"].Folders[FolderToFile];  //  <-- here is the problem. Some mails
                                                                                                                                            //        remain in Inbox instead of being
                                                                                                                                            //        moved to the folder.
                            olMailItem.Move(mapiFld);
                        }
                    }
                    GC.Collect();                                            // I added these 4 lines thinking that some objects might be locked pending
                    GC.WaitForPendingFinalizers();               // garbage collection but they had no impact.
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                DisconnectFromMySQLServer();     // This is a separate function that works fine and used in many programs already.
            }

    Please help me understand what is wrong with above code to make it work only partially during each run.

    Regards.

    • Moved by Cindy Meister MVP Friday, April 27, 2012 7:47 AM outlook-specific (From:General Office Development)
    Friday, April 27, 2012 1:54 AM

Answers

  • The problem is your loop.
     
    When moving or deleting items from a collection you never should use a count up for loop. As you are changing the count of the collection your indexing will be inaccurate and will not account for all items. Use a count down loop:
     
        for (int i = olMails.Count; i >= 1; i--)
    Also, never assume that all items in Inbox are mail items. They can be posts or meeting or task invitations, etc. Always test for mail item or expect exceptions and code for the exceptions.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "BlakJak" <=?utf-8?B?Qmxha0phaw==?=> wrote in message news:76403e5e-05b4-4b8d-b3de-ae009f415e96...

    Hi!

    I have what seems like a strange problem with my Outlook Automation.

    I am looping thru' all mails in my Inbox, looking for MailItems and then checking the subject for specific mails and processing them, parsing data in the file, loading that data to a database and then moving the mail to another folder. The problem appears to be in the moving of the mails. Some mails get moved but others do not. I cannot figure out for the life of me why not. I though it might be due to some object locking and garbage collection delay but when I added specific lines for GC it made no difference.

    I have written this code in Outlook VBA originally then converted to VC# as I thought perhaps the VBA was having some performance issue. However, the problem remained the same in both languages. Here is the main() loop of the VC# code. The other functions are peripheral and not impacting. I know this because I commented them out and it made no difference. The code still left mails in the Inbox unmoved.

    The problem is also not related to any of the specific mails. If I execute the code several times eventually all the mails get moved.

            static void Main(string[] args)
            {
                Outlook.Application olApp;
                Outlook.NameSpace olNS;
                Outlook.Folder olFld;
                Outlook.Items olMails;
                Outlook.MailItem olMailItem = null;

                string subj, body;
                const string FolderToFile = "Processed PR Messages";

                olApp = new Outlook.Application();
                olNS = olApp.GetNamespace("MAPI");
                olFld = (Outlook.Folder)olNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
                olMails = olFld.Items;

                ConnectToMySQLServer();    // This is a separate function that works fine and used in many programs already.

                for (int i = 1; i <= olMails.Count; i++)
                {
                    object olItem = olMails[i];
                    olMailItem = olItem as Outlook.MailItem;

                    if (olMailItem != null)
                    {
                        subj = olMailItem.Subject;
                        body = olMailItem.Body;

                        if (ExtractAndStoreMsgInLclDWH(subj, body))   // This function parses the subj & body of the mail then
                                                                                                  // adds the record  to the MySQL table with an insert query. Works fine.
                        {
                           // Move message to processed folder
                            Outlook.MAPIFolder mapiFld;
                            mapiFld = olNS.Folders["david.armour@st.com"].Folders[FolderToFile];  //  <-- here is the problem. Some mails
                                                                                                                                            //        remain in Inbox instead of being
                                                                                                                                            //        moved to the folder.
                            olMailItem.Move(mapiFld);
                        }
                    }
                    GC.Collect();                                            // I added these 4 lines thinking that some objects might be locked pending
                    GC.WaitForPendingFinalizers();               // garbage collection but they had no impact.
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                DisconnectFromMySQLServer();     // This is a separate function that works fine and used in many programs already.
            }

    Please help me understand what is wrong with above code to make it work only partially during each run.

    Regards.


    Ken Slovak MVP - Outlook
    • Marked as answer by BlakJak Saturday, April 28, 2012 7:16 AM
    Friday, April 27, 2012 2:18 PM
    Moderator

All replies

  • are you sure that those 'some mails' are not the ones that could arrive in your inbox while your code is running? can you verify that? There is also other suggestion - please store target folder in some variable before entering the loop and do not access it using mutiple dot chain inside loop.
    Friday, April 27, 2012 8:21 AM
  • I am 100% sure this is not due to mails coming in. I ran this both offline and online.

    I also thought of the idea of not using the chain in the loop. There was no impact on the result of the code compared to the above.

    Regards

    Friday, April 27, 2012 1:33 PM
  • either mail should be moved or you should get com exception if operation failed. Could you try move to folder that is in the same store (create some subfolder for example)?
    Friday, April 27, 2012 1:36 PM
  • The problem is your loop.
     
    When moving or deleting items from a collection you never should use a count up for loop. As you are changing the count of the collection your indexing will be inaccurate and will not account for all items. Use a count down loop:
     
        for (int i = olMails.Count; i >= 1; i--)
    Also, never assume that all items in Inbox are mail items. They can be posts or meeting or task invitations, etc. Always test for mail item or expect exceptions and code for the exceptions.

    --
    Ken Slovak
    MVP - Outlook
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
     
     
    "BlakJak" <=?utf-8?B?Qmxha0phaw==?=> wrote in message news:76403e5e-05b4-4b8d-b3de-ae009f415e96...

    Hi!

    I have what seems like a strange problem with my Outlook Automation.

    I am looping thru' all mails in my Inbox, looking for MailItems and then checking the subject for specific mails and processing them, parsing data in the file, loading that data to a database and then moving the mail to another folder. The problem appears to be in the moving of the mails. Some mails get moved but others do not. I cannot figure out for the life of me why not. I though it might be due to some object locking and garbage collection delay but when I added specific lines for GC it made no difference.

    I have written this code in Outlook VBA originally then converted to VC# as I thought perhaps the VBA was having some performance issue. However, the problem remained the same in both languages. Here is the main() loop of the VC# code. The other functions are peripheral and not impacting. I know this because I commented them out and it made no difference. The code still left mails in the Inbox unmoved.

    The problem is also not related to any of the specific mails. If I execute the code several times eventually all the mails get moved.

            static void Main(string[] args)
            {
                Outlook.Application olApp;
                Outlook.NameSpace olNS;
                Outlook.Folder olFld;
                Outlook.Items olMails;
                Outlook.MailItem olMailItem = null;

                string subj, body;
                const string FolderToFile = "Processed PR Messages";

                olApp = new Outlook.Application();
                olNS = olApp.GetNamespace("MAPI");
                olFld = (Outlook.Folder)olNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
                olMails = olFld.Items;

                ConnectToMySQLServer();    // This is a separate function that works fine and used in many programs already.

                for (int i = 1; i <= olMails.Count; i++)
                {
                    object olItem = olMails[i];
                    olMailItem = olItem as Outlook.MailItem;

                    if (olMailItem != null)
                    {
                        subj = olMailItem.Subject;
                        body = olMailItem.Body;

                        if (ExtractAndStoreMsgInLclDWH(subj, body))   // This function parses the subj & body of the mail then
                                                                                                  // adds the record  to the MySQL table with an insert query. Works fine.
                        {
                           // Move message to processed folder
                            Outlook.MAPIFolder mapiFld;
                            mapiFld = olNS.Folders["david.armour@st.com"].Folders[FolderToFile];  //  <-- here is the problem. Some mails
                                                                                                                                            //        remain in Inbox instead of being
                                                                                                                                            //        moved to the folder.
                            olMailItem.Move(mapiFld);
                        }
                    }
                    GC.Collect();                                            // I added these 4 lines thinking that some objects might be locked pending
                    GC.WaitForPendingFinalizers();               // garbage collection but they had no impact.
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                DisconnectFromMySQLServer();     // This is a separate function that works fine and used in many programs already.
            }

    Please help me understand what is wrong with above code to make it work only partially during each run.

    Regards.


    Ken Slovak MVP - Outlook
    • Marked as answer by BlakJak Saturday, April 28, 2012 7:16 AM
    Friday, April 27, 2012 2:18 PM
    Moderator
  • Hi Ken!

    The counting backwards solved the issue. Most examples provided on the net (even on MSDN) do not show this approach. I am surprised this problem does nto come up more often.

    Many thanks.

    P.S. Noted the comment about type checking for MailItem.

    Saturday, April 28, 2012 7:20 AM
  • Hi Ken!

    Regarding your comment about check for MailItem, I understood that this code was doing the necessary check in line with the example in the following link:  http://msdn.microsoft.com/en-us/library/cc488006.aspx

    ...
    ...
    ...

                    olMailItem = olItem as Outlook.MailItem;

                    if (olMailItem != null)
                    {
    ...
    ...
    ...

    Basically, casting the MailItem using "as" will return null if the item is not a MailItem, else it performs the cast successfully.

    So the check is done and the code is safe.

    Regards.

    Monday, April 30, 2012 9:51 AM
  • Casting using As and then checking for the cast item being null will check for the item type without firing an exception.

    --
    Ken Slovak
    [MVP - Outlook]
    http://www.slovaktech.com
    Author: Professional Programming Outlook 2007
    Reminder Manager, Extended Reminders, Attachment Options
    http://www.slovaktech.com/products.htm
     
     
    "BlakJak" <=?utf-8?B?Qmxha0phaw==?=> wrote in message news:f5356059-babe-43e8-918d-f1278cdd4c48...

    Hi Ken!

    Regarding your comment about check for MailItem, I understood that this code was doing the necessary check in line with the example in the following link:  http://msdn.microsoft.com/en-us/library/cc488006.aspx

    ...
    ..
    ..

                    olMailItem = olItem as Outlook.MailItem;

                    if (olMailItem != null)
                    {
    ..
    ..
    ..

    Basically, casting the MailItem using "as" will return null if the item is not a MailItem, else it performs the cast successfully.

    So the check is done and the code is safe.

    Regards.


    Ken Slovak MVP - Outlook
    Monday, April 30, 2012 2:38 PM
    Moderator