Pass the bytes to Mail.Parse. Headers come back decoded (encoded words, charsets) and the bodies as .NET strings, with base64 and quoted-printable undone. The program below parses a public test message from Apache Tika with two attachments.
dotnet new console -o ParseEml && cd ParseEml dotnet add package RecursiveAI.OneMail --version 0.2.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-mail-module/src/test/resources/test-documents/testRFC822_multipart_attachments.eml
Put this in Program.cs and run dotnet run:
using RecursiveAI.OneMail; IMailItem msg = Mail.Parse(File.ReadAllBytes("testRFC822_multipart_attachments.eml")); Console.WriteLine($"Subject: {msg.Subject}"); Console.WriteLine($"From: {msg.From.FirstOrDefault()}"); Console.WriteLine($"To: {string.Join(", ", msg.ToRecipients)}"); Console.WriteLine($"Date: {(msg.Sent is { } d ? d.Value.ToString("u") : "none")}"); // Bodies come decoded (base64, quoted-printable, charset) as .NET strings string? text = msg.TextBody?.ReadText(); string? html = msg.HtmlBody?.ReadText(); Console.WriteLine($"Text: {text?.ReplaceLineEndings(" ").Trim()}"); Console.WriteLine($"HTML: {html?.Length} characters"); foreach (IMailAttachment a in msg.Attachments) Console.WriteLine($"Attachment: {a.FileName}, {a.ContentType}, {a.Size} bytes"); // Malformed input is repaired, never thrown; each repair is listed Console.WriteLine($"Defects: {msg.Defects.Count()}");
Subject: EML 1 From: Bugs Bunny <[email protected]> To: Bugs Bunny <[email protected]> Date: none Text: Hi, This is test email for EML1 Thanks, Chetan HTML: 151 characters Attachment: Test TxtA.txt, text/plain, 33 bytes Attachment: Test TxtB.txt, text/plain, 33 bytes Defects: 0
This message has no Date header, so Sent is null. For a file that might be an .eml, an .msg or a mailbox, use Mail.Open(path) instead: it decides from the content.
What you get
- Addresses as
MailAddressvalues (Name,Address), with groups flattened:From,ToRecipients,Cc,Bcc,ReplyTo,Sender. - Ids and threading:
MessageId,InReplyTo,References, without angle brackets. - Bodies:
TextBodyandHtmlBodyare the candidates the message carries; neither is converted into the other. - Repairs, not exceptions. Accessors never throw on malformed content. Every repair is a
MailDefectwith its byte offset. - Lossless. Parsing doesn’t copy the bodies, and an untouched message writes back byte for byte. The lower layer,
MimeEntity.Parse, gives the full part tree and every header.
Limits
- A preview. 0.2.0-preview.2: the API can change before 1.0.
- Ambiguous mail. Where mail clients disagree on how to read broken input, OneMail picks one reading and marks the defect as an ambiguity. The project calls these choices “provisional until mail clients are observed”.
- No signatures or encryption. S/MIME and OpenPGP parts are read as parts; checking or decrypting them isn’t in this preview.
Everything checked, and every known gap: Fidelity and known gaps. The reader: Reading and writing MIME.