Install OneMail 0.2.0-preview.2 for .NET 10, parse an email, and open an mbox, an Outlook MSG file and a PST store with the same call. Pure C#, with no Outlook, COM or native library.
Install
OneMail is a preview: the API can change before 1.0. The packages target net10.0, so you need the .NET 10 SDK, and dotnet add package needs --prerelease or the exact version.
dotnet new console -o OneMailStart cd OneMailStart dotnet add package RecursiveAI.OneMail --version 0.2.0-preview.2
Three packages are on NuGet at 0.2.0-preview.2:
RecursiveAI.OneMail: the mail formats, the read view and conversion. It brings inRecursiveAI.OneMail.Calendar,RecursiveAI.OneArchiveandRecursiveAI.OneHtml.RecursiveAI.OneMail.Calendar: ICS and vCard (and jCal, jCard, xCal, xCard), recurrence and time zones. It depends only on .NET.RecursiveAI.OneMail.Cli: theonemailcommand-line tool. Install it withdotnet tool install -g RecursiveAI.OneMail.Cli --prerelease.
A first program
Download four public test files: an .eml and an mbox from Apache Tika, an Outlook message from Apache POI, and Tika’s PST store.
curl -LO https://raw.githubusercontent.com/apache/tika/4.2.0/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-mail-module/src/test/resources/test-documents/testRFC822_multipart_attachments.eml curl -LO https://raw.githubusercontent.com/apache/tika/4.2.0/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-mail-module/src/test/resources/test-documents/complex.mbox curl -LO https://raw.githubusercontent.com/apache/poi/REL_5_4_1/test-data/hsmf/attachment_test_msg.msg 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; // One message from bytes IMailItem eml = Mail.Parse(File.ReadAllBytes("testRFC822_multipart_attachments.eml")); Console.WriteLine($"{eml.Subject} from {eml.From[0].Address}"); Console.WriteLine($"{eml.Attachments.Count} attachments"); // Any file: the content decides the format, not the extension string[] files = ["complex.mbox", "attachment_test_msg.msg", "testPST.pst"]; foreach (string path in files) { using MailContainer mail = Mail.Open(path); Console.WriteLine($"{path}: {mail.Format}"); foreach (IMailItem item in mail.Enumerate().Take(3)) Console.WriteLine($" {item.Sent?.Value:yyyy-MM-dd} {item.Subject}"); }
EML 1 from [email protected] 2 attachments complex.mbox: Mbox 2009-06-01 Re: question about when shuffle/sort start working 2009-05-31 Re: question about when shuffle/sort start working 2009-06-01 Re: question about when shuffle/sort start working attachment_test_msg.msg: Msg 2009-04-22 test pièce jointe 1 testPST.pst: Pst 2014-02-26 Re: Feature Generators 2014-02-25 Re: init tokenizer fails: "Bad type in putfield/putstatic" 2014-02-25 Feature Generators
The second mbox date reads May 31 because the line prints each date in the sender’s own time zone; {item.Sent?.Value:u} prints UTC.
The two entry points
Mail.Parse(bytes)parses one MIME message (.eml) and returns anIMailItem.Mail.Open(path)reads the first bytes to decide the format, then returns aMailContainer. A single message (.eml,.msg,winmail.dat) holds one item. A store (mbox, Maildir, PST, OST,.dbx) holds many, read as you enumerate.
Every item has the same read view, IMailItem: Subject, From, ToRecipients, Cc, Sent, TextBody, HtmlBody, RtfBody, Attachments, Defects and Provenance. Accessors never throw on malformed input: each repair is a typed defect with its byte offset.
Under the view, every layer is public: the MIME reader and writer, the mailbox stores, the PST layers, MSG, TNEF and the MAPI property model.
Next
- Task by task: the cookbook, with recipes for MSG, PST, MSG to EML, attachments and calendars.
- What is checked, and every known gap: Fidelity and known gaps.
- Not in this preview: writing MSG or PST, SMTP, IMAP and POP3, DKIM, S/MIME and OpenPGP, OLM, and Outlook calendar and task items.