EnumerateMessages Interruption When Encountering Corrupted Emails

Hello,

We’re working with Aspose.Email for C++ and encountered an issue when using EnumerateMessages to retrieve email lists:

When EnumerateMessages encounters a corrupted or unparsable email during enumeration, it throws an exception that immediately interrupts the entire process. This leads to three key problems:

1.The enumeration stops entirely and cannot skip the problematic email to continue processing subsequent valid ones.
2.We lose access to all successfully parsed emails that were processed before the corrupted one.
3.There’s no way to capture information about the corrupted email (such as its position or identifier) to inform users about the specific problematic item.

This behavior has impacted our ability to reliably process email folders, as even a single corrupted email blocks access to all other valid content in the folder.

We would like to ask: Do you have plans to address this behavior of EnumerateMessages in future versions? Specifically, will there be improvements to allow the enumeration to continue past corrupted emails and enable capturing information about such problematic items?

Any guidance or code examples on implementing this would be greatly appreciated.

Thank you for your support.

@liangyongwen

Overview

MailMessage::EnumerateMessages iterates through the items in a folder (PST/OST, IMAP, POP3, etc.).
When the parser meets a message that cannot be parsed, an exception is thrown and the enumeration stops.

At present this is the designed behaviour of the API – the enumeration stops as soon as a parsing error occurs.
There are no announced changes in upcoming releases that will automatically skip the offending item and continue the enumeration.

What can be done today

Even though the enumeration itself cannot be forced to “ignore” a bad message, you can still achieve the three goals you mentioned by using one of the following approaches:

Goal How to achieve it today
Continue processing after a corrupted item Enumerate the message IDs / MessageInfo objects first (these do not require full parsing). Then load each message individually inside a try / catch block. If a particular message throws, log the error and move on to the next ID.
Retain already‑processed messages Keep the successfully loaded MailMessage objects in a collection before you try to load the next one. When an exception occurs, the collection still holds all the messages that were loaded earlier.
Identify the problematic item The MessageInfo (or the MessageId returned by EnumerateMessages) gives you a stable identifier (subject, entry‑id, etc.). When loading fails, you can log that identifier together with the exception details.

Step‑by‑step example (C++)

#include <Aspose.Email.Cpp/Mapi/PersonalStorage.h>
#include <Aspose.Email.Cpp/Mapi/MessageInfoCollection.h>
#include <Aspose.Email.Cpp/MailMessage.h>
#include <Aspose.Email.Cpp/MailMessageLoadOptions.h>
#include <iostream>
#include <vector>

using namespace Aspose::Email::Mapi;
using namespace Aspose::Email;
using namespace System;

int main()
{
    // Open the PST/OST file
    auto pst = PersonalStorage::FromFile(u"myArchive.pst");

    // Get the folder you want to process
    auto folder = pst->RootFolder->GetSubFolder(u"Inbox");

    // 1️⃣  Enumerate *MessageInfo* objects – no parsing is performed yet
    MessageInfoCollectionPtr infos = folder->EnumerateMessages();

    // Store successfully loaded messages
    std::vector<SharedPtr<MailMessage>> goodMessages;

    // Load options – enabling relaxed parsing can help with partially broken items
    auto loadOptions = MakeObject<MailMessageLoadOptions>();
    loadOptions->set_RelaxedParserEnabled(true);   // <‑‑ optional, see note below

    for (auto&& info : infos)
    {
        try
        {
            // 2️⃣  Load the full message using its entry ID
            auto msg = MailMessage::Load(info->get_EntryId(), loadOptions);
            goodMessages.push_back(msg);

            // Your normal processing goes here
            std::wcout << L"Processed: " << msg->get_Subject() << std::endl;
        }
        catch (const System::Exception& ex)
        {
            // 3️⃣  Log the problematic message and continue
            std::wcerr << L"Failed to load message with EntryId = "
                       << info->get_EntryId() << L". Reason: " << ex->get_Message()
                       << std::endl;
            // continue with next message
        }
    }

    // At this point `goodMessages` contains all successfully parsed items
    // and you already have a log of the failures.
}

Key points in the code

  • EnumerateMessages() returns a MessageInfoCollection. These objects contain metadata (Subject, EntryId, Sender, ReceivedDate, …) and can be retrieved without parsing the whole MIME content.
  • MailMessageLoadOptions::set_RelaxedParserEnabled(true) tells the parser to be more tolerant (it will try to recover from many malformed parts). It does not guarantee that every broken message will be loaded, but it reduces the number of hard failures.
  • The try / catch around each MailMessage::Load guarantees that a single corrupted message does not abort the whole loop.

Alternative: IMAP / POP3 scenario

If you are enumerating a remote mailbox (IMAP/POP3), the same pattern applies:

auto client = MakeObject<ImapClient>(u"imap.example.com", 993, u"user", u"pwd");
client->SelectFolder(u"INBOX");

// Get only the message UIDs (no body download)
ArrayPtr<int32_t> uids = client->ListMessages();

for (int32_t uid : uids)
{
    try
    {
        auto msg = client->FetchMessage(uid, loadOptions);   // loads full message
        // process msg …
    }
    catch (const System::Exception& ex)
    {
        std::wcerr << L"UID " << uid << L" could not be parsed: " << ex->get_Message() << std::endl;
    }
}

The principle is identical: first obtain identifiers, then load each message individually with proper exception handling.

Road‑map note

We have logged the request for a “skip‑on‑error” enumeration mode internally. At the moment there is no concrete release target for such a feature. In the meantime, the pattern described above is the recommended way to achieve robust processing of large mail stores that may contain corrupted items.

Helpful links


If you need further assistance—e.g., adapting the pattern to a specific mailbox type (Exchange, MBOX, .eml directory) or troubleshooting a particular corrupt file—please let us know the exact source (PST, IMAP, POP3, etc.) and any sample message identifiers you have. We’ll be happy to provide a more tailored code snippet.