Order of emails returned by EnumerateMessages in Aspose.Email and how to get newest first

Hello,

I’m working with Aspose.Email to process PST files and have noticed something about the EnumerateMessages method that I’d like to clarify.

From my observations, the order of emails returned by EnumerateMessages doesn’t seem to follow either of the expected sequences based on the time they were added to the folder. Specifically, it’s not sorted from newest to oldest, nor from oldest to newest in terms of their addition time.
The parsed email is as follows:

  1. Subject: xxx
    sender: xxx
    date: 2023/11/25 9:22:17
    entryId: AAAAAxxxxxx

  2. Subject: xxx
    sender: xxx
    date: 2023/10/18 0:46:11
    entryId: AAAAAxxxxxx

  3. Subject: xxx
    sender: xxx
    date: 2023/11/5 2:41:39
    entryId: AAAAAxxxxxx

  4. Subject: xxx
    sender: xxx
    date: 2023/10/29 7:33:39
    entryId: AAAAAxxxxxx

  5. Subject: xxx
    sender: xxx
    date: 2023/10/27 20:12:25
    entryId: AAAAAxxxxxx

  6. Subject: xxx
    sender: xxx
    date: 2023/10/25 5:50:22
    entryId: AAAAAxxxxxx

Could you please clarify what specific order EnumerateMessages actually uses to return emails? Additionally, is there a way to make it return emails in the order from newest to oldest (based on their addition time or send/receive time)? If possible, could you provide guidance on how to achieve this?

Any insights would be much appreciated. Thank you!

@liangyongwen

The EnumerateMessages method in Aspose.Email does not guarantee a specific order for the emails it returns. The order can vary based on how the emails are stored in the PST file, which may not correspond to their send/receive times or the order they were added to the folder.

To retrieve emails in a specific order, such as from newest to oldest based on their send/receive time, follow these steps:

  1. Enumerate Messages: Use the EnumerateMessages method to get all the messages from the folder.
  2. Sort the Messages: After retrieving the messages, sort them based on the Date property of each message.

Here’s a sample code snippet to illustrate how to achieve this:

using Aspose.Email;
using Aspose.Email.Pst;
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main()
    {
        // Load the PST file
        using (PersonalStorage pst = PersonalStorage.FromFile("path_to_your_pst_file.pst"))
        {
            // Access the desired folder
            var folder = pst.RootFolder.GetSubFolder("YourFolderName");

            // Enumerate messages
            var messages = folder.EnumerateMessages().ToList();

            // Sort messages by date (newest first)
            var sortedMessages = messages.OrderByDescending(m => m.Date).ToList();

            // Display sorted messages
            foreach (var message in sortedMessages)
            {
                Console.WriteLine($"Subject: {message.Subject}, Date: {message.Date}");
            }
        }
    }
}

This code loads a PST file, accesses a specific folder, retrieves all messages, and sorts them by their date in descending order. Adjust the folder name and path as necessary.

If you have any further questions or need additional assistance, please let me know!

Thank you for your reply. However, I’m concerned about the performance implications when dealing with folders containing a large number of emails (e.g., 10,000 or more).

If we first retrieve all messages and then sort them, it would significantly slow down the rendering process due to the large data volume. Moreover, if we need to implement pagination (to load emails in batches for better user experience), this approach would require fetching the entire list of messages, sorting them, and then slicing for each page. This makes pagination lose its purpose—since we’re still loading all data upfront instead of fetching only the necessary page each time.

Is there a more efficient way to handle this? For example, is there a built-in method or best practice to retrieve emails in “newest to oldest” order directly from the PST file, allowing true pagination (i.e., fetching only the first 50, next 50, etc., without loading the entire dataset first)?

Your further guidance would be highly appreciated.

Hello @liangyongwen,

Try to use the FolderInfo.GetContents(MailQuery query, int startIndex, int count) method.

This allows you to:

  • Retrieve only a subset of messages.
  • Apply filters and queries (for example, by date).
using (var pst = PersonalStorage.FromFile(fileName))
            {
                // Access a specific subfolder
                var folder = pst.RootFolder.GetSubFolder("Inbox");

                // Build a query to filter messages by date (e.g., since yesterday)
                var queryBuilder = new PersonalStorageQueryBuilder();
                queryBuilder.SentDate.Since(DateTime.Today.AddDays(-1));
                queryBuilder.SentDate.OrderBy(true);

                // Define the page size
                int pageSize = 100;

                // Retrieve and process messages in pages
                for (int pageIndex = 0; pageIndex < numberOfPages; pageIndex++)
                {
                    int startIndex = pageIndex * pageSize;

                    // Get a page of messages
                    var messages = folder.GetContents(queryBuilder.GetQuery(), startIndex, pageSize);

                    foreach (MessageInfo messageInfo in messages)
                    {
                        // Output basic info about each message
                        Console.WriteLine($"Subject: {messageInfo.Subject}, Sender: {messageInfo.SenderRepresentativeName}");
                    }
                }
            }

Hello,

Thank you for your previous reply and the code example. After checking the Aspose.Email for C++ documentation and conducting tests, I confirm that the FolderInfo::GetContents method in the C++ version does not have an overload that simultaneously accepts a MailQuery, startIndex, and count like the .NET version. The available overloads only allow either filtering with a MailQuery alone or pagination with startIndex and count alone, which means we can’t combine filtering and pagination in a single call.
getContents.png (134.7 KB)

Our key requirement is to load the email list in pages, and the paginated results must be sorted based on the entire email list (not just the current page). This way, each page of results maintains the correct order relative to the complete dataset. If we have to load all matching emails first, sort them, and then paginate through the preloaded list, it would defeat the purpose of pagination—since it would still load all data into memory upfront, which is what we’re trying to avoid.

Additionally, I’d like to mention that we have purchased the full version of Aspose.Email for C++, so we’re looking to leverage the complete functionality of the licensed product.

Could you please advise if there’s a way to achieve both proper pagination (with results sorted against the entire list) and filtering in the C++ version? If such a method exists, a code example would be greatly appreciated.

Thank you for your assistance.

@liangyongwen,

The PST file format itself does not provide such functionality, so filtering and pagination are performed in memory on the client side.

Also, the following methods are available:

  • EnumerateMessages(SharedPtr mailQuery) — filtering only.
  • EnumerateMessages(int32_t startIndex, int32_t count) — pagination only.

The overload FolderInfo::GetContents(SharedPtr query, int startIndex, int count)was introduced in Aspose.Email for C++ 25.7. If you are using an earlier version, this method will not be available.

Hello,

Thank you very much for your prompt reply and the helpful information.

We’ve upgraded to Aspose.Email for C++ version 25.8, and now the FolderInfo::GetContents(SharedPtr<MailQuery> query, int startIndex, int count) method is available and working for us. We’ve tested the filtering functionality, and queries like searching for emails with “Test” in the subject are returning the correct results, which is great.

We’ve confirmed that time-based filtering works correctly (e.g., retrieving emails sent after a specific date using Since() or within a date range). This suggests the SentDate values are being properly recognized and processed for filtering purposes.

However, the sorting by SentDate (in descending order via OrderBy(false)) still does not function as expected. The returned results remain unsorted by SentDate, despite the filtering logic working correctly with time-based criteria.we’re wondering if this might be related to time zones?

 auto queryBuilder = System::MakeObject<Aspose::Email::Storage::Pst::PersonalStorageQueryBuilder>();
 auto sentDateField = queryBuilder->get_SentDate();
 // Time filtering is effective       
 auto dateCondition = sentDateField->Since(System::DateTime(2024, 9, 1));
  // Time sorting has no effect
 sentDateField->OrderBy(false); 
  
 auto mailQuery = queryBuilder->GetQuery();
  
 messageCollection = targetFolder->GetContents(mailQuery, startIndex, limit);

Result:

Subject: xxx
sender: xxx
date: 2024/12/10 14:57:21
entryId: AAAAAxxxxxx

Subject: xxx
sender: xxx
date: 2024/10/29 13:21:08
entryId: AAAAAxxxxxx

Subject: xxx
sender: xxx
date: 2024/12/24 14:57:09
entryId: AAAAAxxxxxx

Subject: xxx
sender: xxx
date: 2024/12/24 14:59:46
entryId: AAAAAxxxxxx

Subject: xxx
sender: xxx
date: 2024/12/19 20:58:44
entryId: AAAAAxxxxxx

Could you please advise if there’s a specific way to correctly implement sorting by SentDate (descending) with the three-parameter GetContents method in version 25.8? Any guidance or code examples would be greatly appreciated.

Thank you again for your support.

Hello @liangyongwen,

Thank you for your valuable feedback.
We will investigate this behavior and share our observations.
We’ll keep you updated on any progress.

Hello @liangyongwen,

At the moment, sorting by fields isn’t implemented when retrieving messages from PST. That’s why the order of messages remains unchanged.

We have created an internal ticket to implement sorting functionality for PST message retrieval in future releases.

Issue ID(s): EMAILNET-41636

Thank you.