none
Problem retrieving (email) items in Inbox folder using getfirst - getnext loop RRS feed

  • Question

  • Hi,

    i am trying in a VBScript to display all items in the inbox, using the getfirst - getnext methode in a do while loop. The ultimate goal is to move certain items to another folder, so a for each loop can't be used.

    I retrieve the first item by the getfirst mehode, and then start the do loop, display some information of the first item, and then retrieve the next item (within the loop). The second item is then also displayed, but then this second item keeps displaying and the loop never ends.

    Set objApplication = CreateObject("Outlook.Application")
    objApplication.GetNamespace("MAPI").Logon , , , False
    Set objMyNameSpace = objApplication.GetNameSpace("MAPI")
    Set objInboxFolder = objMyNameSpace.GetDefaultFolder(6)
    intMessageCount = objInboxFolder.Items.Count
    MsgBox("Number of items in Inbox: " & CStr(intMessageCount))
    Set objMessage = objInboxFolder.Items.GetFirst ' Get the first message
    ' Loop through the collection
    Do While Not objMessage Is Nothing
        MsgBox ("Sender = " & objMessage.SenderName & vbCRLF & "ReceivedTime = " & CStr(objMessage.ReceivedTime) & vbCRLF & _
                   "Unread = " & Cstr(objMessage.Unread) & vbCRLF & "address name = " & objMessage.SenderName & vbCRLF & _
                   "address address = " & objMessage.SenderEmailAddress & vbCRLF & "Subject = " & objMessage.Subject & vbCRLF & _
                   "EntryId = " & objMessage.EntryID)
      Set objMessage = objInboxFolder.Items.GetNext ' Get next message
    Loop

    I am using Office (Outlook) 2010. Can sombody tell me why i only get the first two items to display.






    • Edited by JanStr-nl Thursday, December 12, 2013 9:15 AM
    • Moved by Bill_Stewart Thursday, December 12, 2013 4:29 PM Move to more appropriate forum
    Wednesday, December 11, 2013 8:02 AM

Answers

  • Here is a complete example of moving items in a loop.

    Set objApplication = CreateObject("Outlook.Application")
    Set objMyNameSpace = objApplication.GetNameSpace("MAPI")
    Set objInboxFolder = objMyNameSpace.GetDefaultFolder(6)
    intMessageCount = objInboxFolder.Items.Count
    Set folder = objMyNameSpace.Folders.Item("Data Folders")
    Set f = folder.Folders.Item("Test")
    For Each objMessage in objInboxFolder.Items
        'MsgBox objMessage.EntryID
        objMessage.Move f             
    Next

    I can successfully move all itemswith no issues.

    You cannot move items in a maibox delivered through ActiveSync like outlook.com mail items.  They can be moved by EntryID but not in the loop becuse ActiveSync will trigger and the enumerator will become invalid.


    ¯\_(ツ)_/¯

    • Proposed as answer by Marvin_Guo Tuesday, December 24, 2013 8:55 AM
    • Marked as answer by Marvin_Guo Thursday, January 2, 2014 8:39 AM
    Thursday, December 12, 2013 6:07 PM
  • Hi,
    You could refer to the Official Documents in MSDN about how to use the GetNext method :
    http://msdn.microsoft.com/en-us/library/office/aa155748(v=office.10).aspx
    You should be notice here's a different place with your code:
     Set myItems = myFolder.Items
     ...
     Do While
     ...
     Set myItem = myItems.GetNext
     ...
     Loop

    But you get next mail item directly: objInboxFolder.Items.GetNext
    The reason why GetNext does not work for you is because every time you call
    It, your code retrieves a new instance of the Items object. Store the Items object in a local variable to make sure you are always using the same instance
    Here is a sample with  VSTO to proof this topic by HashCode:
    Dim objOutlook As Outlook.Application = CreateObject("Outlook.Application")
             Dim objOutlookNameSpace As Outlook.NameSpace = objOutlook.GetNamespace("MAPI")
             Dim fldInbox As Outlook.MAPIFolder = objOutlookNameSpace.GetDefaultFolder(6)
             Dim ObjItems1 As Outlook.Items
             Dim ObjItems2 As Outlook.Items
             ObjItems1 = fldInbox.Items
             ObjItems2 = fldInbox.Items
             MsgBox("ObjeItems1 :" + ObjItems1.GetHashCode().ToString() + " ObjectItems2:" + ObjItems2.GetHashCode().ToString(), MsgBoxStyle.DefaultButton1, "Msg")


    Here is a screenshot:
     
    Different hash code means different COM object.
    Regards,

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.



    • Edited by Marvin_Guo Tuesday, December 24, 2013 8:54 AM
    • Marked as answer by Marvin_Guo Thursday, January 2, 2014 8:40 AM
    Tuesday, December 24, 2013 8:51 AM

All replies

  • Because there are not too items in the two display to display.

    What are you trying to ask?

    Here is how to enumerate a list or collection.

    for each itm in objInboxFolder.Items
         msgbox itm.SenderEmailAddress
    next

    That's all.  No need to play with those odd looing methods learned where?


    ¯\_(ツ)_/¯

    Wednesday, December 11, 2013 8:26 AM
  • I agree that this works fine, until you move (or delete) an item wihtin the loop. Then the for each loop gives unpredictable results (i.e. not all items are shown)
    Wednesday, December 11, 2013 8:46 AM
  • I agree that this works fine, until you move (or delete) an item wihtin the loop. Then the for each loop gives unpredictable results (i.e. not all items are shown)

    Why would you want to do that?


    ¯\_(ツ)_/¯

    Wednesday, December 11, 2013 12:08 PM
  • Why does that matter? I want to look at all email messages in the inbox and when certain conditions are true, i want to move that message to a different folder. As i have to do this several times a day, it is good practise to make a script to do this for you.

    The problem i have is that when i use a for each loop, not all email messages are shown when items are moved. In Outlook 2003 with CDO1.2.1, I had the same problem, and the solutions was using getfirst getnext. Office 2010 does not support CDO, but it also supports the getfirst and getnext method (OOM) (http://msdn.microsoft.com/en-us/library/office/ff861538(v=office.14).aspx). The only problem is that the script i have given above only retrieves the first two mail messages, after that it keeps giving the second message and the loop never ends.

    So, my question remains, why do i only get the first two messages?

    Thursday, December 12, 2013 9:15 AM
  • Programtically it is just something that you cannot do. If you are enumerating a collection you cannot change its contents while enumerating it.

    You can get a copy of the item number (id) and use that to later move the item.

    To get an answer to your question you might contact the Outlook people in the Outlook devleopers forum.  It is not a scripting question but is a product question.


    ¯\_(ツ)_/¯



    • Edited by jrv Tuesday, December 24, 2013 4:46 PM
    Thursday, December 12, 2013 5:05 PM
  • Here - I rewrote you lop as a proper enumeration and it works as expected.

    It enumerates all messages in the inbox.

    Set objMyNameSpace = objApplication.GetNameSpace("MAPI")
    Set objInboxFolder = objMyNameSpace.GetDefaultFolder(6)
    intMessageCount = objInboxFolder.Items.Count
    MsgBox("Number of items in Inbox: " & CStr(intMessageCount))
    ' Loop through the collection
    FOr Each objMessage in objInboxFolder.Items
        MsgBox ("Sender = " & objMessage.SenderName & vbCRLF & "ReceivedTime = " & CStr(objMessage.ReceivedTime) & vbCRLF & _
                   "Unread = " & Cstr(objMessage.Unread) & vbCRLF & "address name = " & objMessage.SenderName & vbCRLF & _
                   "address address = " & objMessage.SenderEmailAddress & vbCRLF & "Subject = " & objMessage.Subject & vbCRLF & _
                   "EntryId = " & objMessage.EntryID)
    Next

    Part of your problem may have been incorrect initialization of thAMPI namespace or in failure to use the loop enumerator as intended.  It must be used in a "for" loop.

    Try it.


    ¯\_(ツ)_/¯



    • Edited by jrv Thursday, December 12, 2013 5:15 PM
    Thursday, December 12, 2013 5:11 PM
  • You should aslo note that inbox rules do what you are asking better than a script.  Just crate a rule to trigger on any of the email properties and then move the message to anywhere.  You can even call a script when a selected message arrives.


    ¯\_(ツ)_/¯


    • Edited by jrv Thursday, December 12, 2013 5:19 PM
    Thursday, December 12, 2013 5:14 PM
  • Sorry - if you copied the above script it needs to be copied again.  I pasted the wrong copy.


    ¯\_(ツ)_/¯


    • Edited by jrv Thursday, December 12, 2013 5:19 PM
    Thursday, December 12, 2013 5:16 PM
  • Here is a complete example of moving items in a loop.

    Set objApplication = CreateObject("Outlook.Application")
    Set objMyNameSpace = objApplication.GetNameSpace("MAPI")
    Set objInboxFolder = objMyNameSpace.GetDefaultFolder(6)
    intMessageCount = objInboxFolder.Items.Count
    Set folder = objMyNameSpace.Folders.Item("Data Folders")
    Set f = folder.Folders.Item("Test")
    For Each objMessage in objInboxFolder.Items
        'MsgBox objMessage.EntryID
        objMessage.Move f             
    Next

    I can successfully move all itemswith no issues.

    You cannot move items in a maibox delivered through ActiveSync like outlook.com mail items.  They can be moved by EntryID but not in the loop becuse ActiveSync will trigger and the enumerator will become invalid.


    ¯\_(ツ)_/¯

    • Proposed as answer by Marvin_Guo Tuesday, December 24, 2013 8:55 AM
    • Marked as answer by Marvin_Guo Thursday, January 2, 2014 8:39 AM
    Thursday, December 12, 2013 6:07 PM
  • Hi,
    You could refer to the Official Documents in MSDN about how to use the GetNext method :
    http://msdn.microsoft.com/en-us/library/office/aa155748(v=office.10).aspx
    You should be notice here's a different place with your code:
     Set myItems = myFolder.Items
     ...
     Do While
     ...
     Set myItem = myItems.GetNext
     ...
     Loop

    But you get next mail item directly: objInboxFolder.Items.GetNext
    The reason why GetNext does not work for you is because every time you call
    It, your code retrieves a new instance of the Items object. Store the Items object in a local variable to make sure you are always using the same instance
    Here is a sample with  VSTO to proof this topic by HashCode:
    Dim objOutlook As Outlook.Application = CreateObject("Outlook.Application")
             Dim objOutlookNameSpace As Outlook.NameSpace = objOutlook.GetNamespace("MAPI")
             Dim fldInbox As Outlook.MAPIFolder = objOutlookNameSpace.GetDefaultFolder(6)
             Dim ObjItems1 As Outlook.Items
             Dim ObjItems2 As Outlook.Items
             ObjItems1 = fldInbox.Items
             ObjItems2 = fldInbox.Items
             MsgBox("ObjeItems1 :" + ObjItems1.GetHashCode().ToString() + " ObjectItems2:" + ObjItems2.GetHashCode().ToString(), MsgBoxStyle.DefaultButton1, "Msg")


    Here is a screenshot:
     
    Different hash code means different COM object.
    Regards,

    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.



    • Edited by Marvin_Guo Tuesday, December 24, 2013 8:54 AM
    • Marked as answer by Marvin_Guo Thursday, January 2, 2014 8:40 AM
    Tuesday, December 24, 2013 8:51 AM
  • Yes and that is also why correctly enumerating the items list does not create issues.  It is the same as using a reference to the collection and then using GetNext.

    I actually ran the modified code and it can move the items as long as we only move forwards which the enumerator guarantees.

    For Each objMessage in objInboxFolder.Items
        'MsgBox objMessage.EntryID
        objMessage.Move f             
    Next

    The only issue is with ActiveSync sites.  You cannot enumerate AS sites and move items because the sync code wants to reset after every change which interferes.  In that case just get a list of ids and then get the items to move in a for loop until all are moved.

    for each entryid in itemlist
         Set m = ns.GetItemFromID(entryid)
        m.Move targetFolder
    next

    I didn't test that but it should work.


    ¯\_(ツ)_/¯



    • Edited by jrv Tuesday, December 24, 2013 4:58 PM
    Tuesday, December 24, 2013 4:56 PM