Mail.Open opens a PST (or OST) store and Enumerate() walks every message in every folder. Messages are read one at a time as you reach them, so a large store doesn’t have to fit in memory. The program below lists Apache Tika’s public test store.
dotnet new console -o ReadPst && cd ReadPst dotnet add package RecursiveAI.OneMail --version 0.3.0-preview.2 curl -LO https://raw.githubusercontent.com/apache/tika/4.2.0/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-microsoft-module/src/test/resources/test-documents/testPST.pst
Put this in Program.cs and run dotnet run:
using RecursiveAI.OneMail; // Opening reads only the store header; each message is read as you reach it using MailContainer pst = Mail.Open("testPST.pst"); int count = 0; foreach (IMailItem msg in pst.Enumerate()) { count++; MailAddress from = msg.From.FirstOrDefault(); Console.WriteLine($"{msg.Sent?.Value:yyyy-MM-dd} {from.Name}: {msg.Subject}"); Console.WriteLine($" folder: {msg.Provenance.Folder}, " + $"attachments: {msg.Attachments.Count}"); } Console.WriteLine($"{count} messages");
2014-02-26 Jörn Kottmann: Re: Feature Generators folder: Début du fichier de données Outlook, attachments: 0 2014-02-25 Barry Olddog: Re: init tokenizer fails: "Bad type in putfield/putstatic" folder: Début du fichier de données Outlook, attachments: 0 2014-02-25 Kenig Ma: Feature Generators folder: Début du fichier de données Outlook, attachments: 0 2014-02-26 Nick Burch (JIRA): [jira] [Resolved] (TIKA-1249) Vcard files detection folder: Début du fichier de données Outlook, attachments: 0 2014-02-26 Gary Murphy (JIRA): [jira] [Commented] (TIKA-1250) Process loops infintely processing a CHM file folder: Début du fichier de données Outlook, attachments: 0 2014-02-24 Couchbase: [WEBINAR] - "Introducing Couchbase Server 2.5" folder: Début du fichier de données Outlook, attachments: 0 2020-11-26 Luis Filipe da Cruz Nassif: FW: First email folder: Début du fichier de données Outlook, attachments: 1 7 messages
Each item is an IMailItem, the same view as an MSG or EML file: TextBody, HtmlBody, Attachments and the rest work as in Read an Outlook MSG file. Provenance.Folder is the folder path inside the store. The last message’s sender has only an Exchange address, so its name prints and its SMTP address is empty.
List the folders
For the folder tree itself, open the store with PstStore:
using RecursiveAI.OneMail.Pst.Messaging; if (!PstStore.TryOpen("testPST.pst", out PstStore? store, out var defects)) { Console.WriteLine($"Not a PST: {string.Join(", ", defects)}"); return; } using (store) { foreach (PstFolder folder in store!.EnumerateFolders()) { if (folder.Depth == 0) continue; // the unnamed root string indent = new(' ', 2 * (folder.Depth - 1)); int messages = folder.EnumerateMessageIds().Count(); string search = folder.IsSearchFolder ? " (search folder)" : ""; Console.WriteLine($"{indent}{folder.Name}: {messages}{search}"); } }
Début du fichier de données Outlook: 7 Éléments supprimés: 0 Racine (pour la recherche): 0 SPAM Search Folder 2: 0 (search folder) IPM_COMMON_VIEWS: 0 ItemProcSearch: 0 (search folder)
Mail.Open returns the ordinary messages of ordinary folders. Search folders only link to messages stored elsewhere, so their contents aren’t listed again. Hidden items (rules, views) come from folder.EnumerateMessages(PstMessageSet.Associated).
Limits
- A preview. 0.3.0-preview.2: the API can change before 1.0.
- Reading only. OneMail can’t write PST files yet. To export messages, convert a PST to EML files.
- Calendar and task items come through the read view with
Kindset toAppointmentorTask, a subject and a body. For their times, attendees and recurrence, convert them to ICS. - Layouts checked on generated files only. In the project’s words: “no public ANSI or 512-byte-page Unicode PST from Outlook exists; those layouts and 4 KiB multi-map stores are checked only on files we generate.”
- Exchange addresses. There is no directory lookup: a sender with no SMTP address in the store keeps only its name and X.500 address.
OST files open the same way; the project checked them on the NIST CFReDS OST. Everything checked, and every known gap: Fidelity and known gaps. The store layers: PST and OST messages.