win32com + Outlook only capturing 50% of messages in inbox per execution

Question:

I’ve created a little code with win32com and Python 3.x which simply goes through an Outlook folder and does stuff to the messages inside (move them, read them, etc.).

It works flawlessly, except for one strange little problem… Only 50% of the items in the folder are being processed! 500 items in inbox? 250 are analyzed. 30? 15 remain in the inbox. 1? Processed without issue.

If I use "messages.Count" I can see how many emails are in the mailbox – this number matches what I see in outlook. Regardless, the program ends when half of the items have been seen. The program will count down 30, 29, 28… stopping at 15 without throwing any errors.

If I play with the loop a bit, doing while messages:, the program will count down to 15 and then give me a "NoneType" exception, indicating to me that outlook isn’t "giving" any more messages to python despite some being present in the mailbox.

Running the program again in either of these cases will simply process the remaining 50% of the messages.

What is going on here? Is this an Outlook thing? I don’t even know where to begin… Here’s a super stripped version of the code. The bug persists even at this level. 50% of an inbox is moved, 50% remains. Of the remaining 50%, half of that is processed upon next execution.

    import win32com.client

    outlook = win32com.client.Dispatch("Outlook.Application")
    namespace = outlook.GetNamespace("MAPI")
    root_folder = namespace.Folders.Item(1) # Choose account
    subfolder = root_folder.Folders['Inbox'] # Choose folder, subfolder
    subfolderO = root_folder.Folders['Inbox'].Folders['Closed'] # Choose folder, subfolder
    messages = subfolder.Items
    message = messages.GetFirst()

    for message in messages:
        print("n", message.Sender, "n", message.To, "n ", message.Subject',"n", message.CreationTime, "n_________")
        message.Move(subfolderO)
        message = messages.GetNext()
Asked By: S. Aldaris

||

Answers:

The main problem is that you modify messages whilst iterating over it:

message.Move(subfolderO)

It isn’t obvious but this will modify messages. The loop will get shrunk by one but your iterator won’t move backwards so you miss the next item in the container.

This is a common problem in many languages and implementations of containers.

So don’t do it.

One way is to make a copy of the container and iterate over that, modifying the original container as you go.

for message in list(messages):
    ...
    message.Move(subfolderO)

Also, you don’t need to do:

    message = messages.GetNext()
Answered By: Peter Wood

I battled with the exact same problem. Iterating ‘.Move’ only gets through half of the mail items. The explanation from Peter Wood helped, though it took a while to figure out the issue.. 🙂 I believe the below modified code would work:

import win32com.client

outlook = win32com.client.Dispatch("Outlook.Application")
namespace = outlook.GetNamespace("MAPI")
root_folder = namespace.Folders.Item(1) #choose account
subfolder = root_folder.Folders['Inbox'] #choose folder, subfolder
subfolderO = root_folder.Folders['Inbox'].Folders['Closed'] #choose                                                folder, subfolder
messages = subfolder.Items
message = messages.GetFirst()

for message in list(messages):
    print("n", message.Sender,"n", message.To, "n ", message.Subject',"n", message.CreationTime, "n_________")
    message.Move(subfolderO)
    messages = subfolder.Items
    message = messages.GetFirst()

Iterate such that it moves only the first item, and modify the original messages class through each iteration.

Answered By: Jay J