Reading and Extracting OLM Messages
After you open an OLM file and locate a folder, you can list its messages, read short message information, filter and page through large folders, and extract individual messages as MapiMessage objects. This article covers all of these operations.
List Messages in a Folder
The OlmFolder class provides two ways to iterate over the messages it contains:
- EnumerateMessages returns an OlmMessageInfo object on each iteration. This object holds short information about the message and is the most efficient way to scan a folder.
- EnumerateMapiMessages returns a full MapiMessage object on each iteration, with all of the message’s properties loaded.
Using EnumerateMessages
using (var olm = OlmStorage.FromFile(fileName))
{
var folder = olm.GetFolder("Inbox", true);
foreach (var messageInfo in folder.EnumerateMessages())
{
Console.WriteLine(messageInfo.Subject);
}
}
Using EnumerateMapiMessages
using (var olm = OlmStorage.FromFile(fileName))
{
var folder = olm.GetFolder("Inbox", true);
foreach (var msg in folder.EnumerateMapiMessages())
{
// save the message in MSG format
msg.Save($"{msg.Subject}.msg");
}
}
Read Message Information
Each OlmMessageInfo object exposes a set of read-only properties that describe a message without loading its full contents. This is the most efficient way to build a list view or to decide which messages to extract.
| Property | Description |
|---|---|
| Subject | The message subject. |
| From | The sender address. |
| To | The collection of recipient addresses. |
| Date | The date of the message. |
| ModifiedDate | The date the message was last modified. |
| HasAttachments | Indicates whether the message has attachments. |
| MessageClass | The sender-defined message class, such as IPM.Note. |
| EntryId | The message entry identifier. |
using (var olm = OlmStorage.FromFile(fileName))
{
var folder = olm.GetFolder("Inbox", true);
foreach (OlmMessageInfo messageInfo in folder.EnumerateMessages())
{
Console.WriteLine($"Subject: {messageInfo.Subject}");
Console.WriteLine($"From: {messageInfo.From}");
Console.WriteLine($"To: {string.Join("; ", messageInfo.To)}");
Console.WriteLine($"Date: {messageInfo.Date}");
Console.WriteLine($"Modified: {messageInfo.ModifiedDate}");
Console.WriteLine($"Has attachments: {messageInfo.HasAttachments}");
Console.WriteLine($"Message class: {messageInfo.MessageClass}");
Console.WriteLine(new string('-', 30));
}
}
Get the Modified Date of a Message
The modified date represents the date and time when the OLM message was last modified. Use the OlmMessageInfo.ModifiedDate property to read it:
foreach (OlmMessageInfo messageInfo in inboxFolder.EnumerateMessages())
{
DateTime modifiedDate = messageInfo.ModifiedDate;
}
Filter Messages with a Query
For large folders, you can retrieve only the messages that match a set of criteria instead of iterating over everything. Pass a MailQuery to the EnumerateMessages(MailQuery query) overload. Build the query with a MailQueryBuilder.
The example below enumerates only the messages received during the last seven days whose subject contains the word “Invoice”:
using (var olm = OlmStorage.FromFile(fileName))
{
var folder = olm.GetFolder("Inbox", true);
var builder = new MailQueryBuilder();
builder.InternalDate.Since(DateTime.Now.AddDays(-7));
builder.Subject.Contains("Invoice");
MailQuery query = builder.GetQuery();
foreach (var messageInfo in folder.EnumerateMessages(query))
{
Console.WriteLine(messageInfo.Subject);
}
}
Page Through Messages
When a folder contains a large number of messages, you can read them in batches with the EnumerateMessages(int skip, int count) overload. The skip parameter is the number of messages to bypass, and count is the number of messages to return.
using (var olm = OlmStorage.FromFile(fileName))
{
var folder = olm.GetFolder("Inbox", true);
const int pageSize = 50;
int pageIndex = 0;
while (true)
{
var page = folder.EnumerateMessages(pageIndex * pageSize, pageSize).ToList();
if (page.Count == 0)
{
break;
}
foreach (var messageInfo in page)
{
Console.WriteLine(messageInfo.Subject);
}
pageIndex++;
}
}
Extract a Message as a MapiMessage
The OlmStorage class provides the ExtractMapiMessage method, which extracts a full MapiMessage from an OlmMessageInfo object. This is useful when you first scan a folder with EnumerateMessages and then extract only the messages you actually need.
using (var olm = OlmStorage.FromFile(fileName))
{
var folder = olm.GetFolder("Inbox", true);
foreach (var messageInfo in folder.EnumerateMessages())
{
if (messageInfo.Date.Date == DateTime.Today)
{
// extract today's messages from Inbox
var msg = olm.ExtractMapiMessage(messageInfo);
msg.Save($"{msg.Subject}.msg");
}
}
}
Extract Messages by Identifier
Sometimes you need to extract selected messages by their identifiers. For example, an application can store identifiers in a database and extract a message on demand instead of traversing the entire storage each time. The EntryId property of OlmMessageInfo provides the message entry identifier, and the overloaded ExtractMapiMessage(string id) method retrieves the message by that identifier.
using (var olm = OlmStorage.FromFile(fileName))
{
var olmFolder = olm.GetFolder("Inbox", true);
foreach (OlmMessageInfo msgInfo in olmFolder.EnumerateMessages())
{
// store msgInfo.EntryId somewhere, then later:
MapiMessage msg = olm.ExtractMapiMessage(msgInfo.EntryId);
}
}
Extract Items Using the Traversal API
You can extract every item from an OLM file - as far as possible - without throwing exceptions, even when some data in the original file is corrupted. To do this, create the OlmStorage instance with the OlmStorage(TraversalExceptionsCallback callback) constructor and load the file with the Load method. The callback exposes the loading and traversal exceptions.
The Load method returns true if the file was loaded successfully and traversal is possible, and false if the file is corrupted and no traversal is possible. Note that when traversing items folder by folder, you call the storage’s EnumerateMessages(OlmFolder folder) method, passing the folder as an argument.
The steps are:
- Create a new OlmStorage instance, passing an exception-handling callback.
- Load the OLM file by calling the Load method.
- If the file loads successfully, obtain the folder hierarchy by calling GetFolders.
- Recursively iterate over each folder. For folders that have messages, enumerate them with the storage’s
EnumerateMessagesmethod and process each one. - Recurse into any sub-folders.
using (var olm = new OlmStorage((exception, id) => { /* Exception handling code. */ }))
{
if (olm.Load(fileName))
{
var folderHierarchy = olm.GetFolders();
ExtractItems(olm, folderHierarchy);
}
}
private static void ExtractItems(OlmStorage olm, IEnumerable<OlmFolder> folders)
{
foreach (var folder in folders)
{
if (folder.HasMessages)
{
Console.WriteLine(folder);
foreach (var msg in olm.EnumerateMessages(folder))
{
Console.WriteLine(msg.Subject);
}
}
ExtractItems(olm, folder.SubFolders);
}
}