Recursive AI

Read an OLM file in C#

All onemail recipes

Open the archive with Mail.Open and enumerate it. An .olm file is what Outlook for Mac exports, and it holds mail, calendar items, contacts, tasks and notes. Each record comes back as an IMailItem with its folder, so mail reads exactly like a PST. The program below reads the example archive of the OLMReader project (BSD-2-Clause).

Terminal
dotnet new console -o ReadOlm && cd ReadOlm
dotnet add package RecursiveAI.OneMail --version 0.3.0-preview.2
curl -LO https://raw.githubusercontent.com/teverett/OLMReader/c3f14c3e49d181f180750a2125984fb67a82fd58/src/test/resources/Outlook16/outlook_example.olm

Put this in Program.cs and run dotnet run:

C#
using RecursiveAI.OneMail;
 
// Mail.Open reads the format from the bytes: an .olm is a zip of XML records
using MailContainer olm = Mail.Open("outlook_example.olm");
Console.WriteLine($"Format: {olm.Format}");
 
// Records are read one at a time, in the order they sit in the archive
List<IMailItem> items = olm.Enumerate().ToList();
foreach (var kind in items.GroupBy(i => i.Kind))
    Console.WriteLine($"{kind.Key}: {kind.Count()}");
 
foreach (IMailItem msg in items.Where(i => i.Kind == MailItemKind.Message))
{
    Console.WriteLine();
    Console.WriteLine($"{msg.Provenance.Folder}: {msg.Subject}");
    foreach (IMailAttachment a in msg.Attachments)
        Console.WriteLine($"  {a.FileName}  {a.Size:N0} bytes  {a.ContentType}");
}
Text
Format: Olm
Other: 10
Contact: 5
DistributionList: 2
Appointment: 8
Task: 5
Note: 1
Message: 7
 
Outlook PST/Inbox: [ubuntu-ko] 우분투 시작 안내서의 10. Tips & Trick 의 번역이 일단락되었습니다.
 
Outlook PST/Drafts: パーティーは何時ですか?
  017091.docx  37,440 bytes  application/vnd.openxmlformats-officedocument.wordprocessingml.document
  037025.docx  95,167 bytes  application/vnd.openxmlformats-officedocument.wordprocessingml.document
  000038.xls  71,680 bytes  application/vnd.ms-excel
 
Outlook PST/Drafts: What time is party?
  000046.xls  74,240 bytes  application/vnd.ms-excel
  018375.pptx  111,596 bytes  application/vnd.openxmlformats-officedocument.presentationml.presentation
  000006.doc  67,584 bytes  application/msword
 
Outlook PST/Drafts: באיזה שעה המסיבה?
  000100.doc  58,368 bytes  application/msword
  005227.pdf  147,455 bytes  application/pdf
  008708.pdf  148,328 bytes  application/pdf
 
Outlook PST/Archive: Email Test
 
Drafts: Draft with low priority
 
Drafts: Mail with followup

Kind says what each record is (Other here is the archive’s list of categories), and Provenance.Folder is its folder in the archive. Two of the attachment types weren’t stored and come from the file extension, so ContentTypeInferred is true for them. Messages have From, ToRecipients, Sent, TextBody, HtmlBody and Attachments, like every other format. An attachment’s Open() streams it from the archive.

Calendar items and contacts

Appointments, tasks and notes have a subject and a body in the read view. For their times, attendees and recurrence, convert them: Mail.Convert(item, ConvertFormat.Ics) gives the .ics bytes and ConvertFormat.VCard the .vcf bytes of a contact, each with a loss report. To turn the whole archive into mbox files plus .ics and .vcf files, see Convert a PST file to mbox: the same call takes an .olm.

Limits

  • A preview. 0.3.0-preview.2: the API can change before 1.0.
  • Reading only. OneMail never writes OLM files.
  • Checked on few archives. In the project’s words: “no Outlook 2011 layout sample; no archive with a raw MIME source, attendees or exceptions seen; a damaged zip is refused (recovery comes later)”.
  • Dates. OLM stores times in UTC with no time zone, so Sent is UTC.
  • Memory. The zip directory stays in memory, about 1 KB per entry in the archive.

Everything about the format: OLM (Outlook for Mac). Everything checked, and every known gap: Fidelity and known gaps.