Build the message from MimeMultipart and MimePart, add the headers, and call WriteTo. The program below writes an email with plain text and HTML bodies and a CSV attachment, then reads it back.
dotnet new console -o CreateEml && cd CreateEml dotnet add package RecursiveAI.OneMail --version 0.2.0-preview.2
Put this in Program.cs and run dotnet run:
using System.Globalization; using System.Text; using RecursiveAI.OneMail; using RecursiveAI.OneMail.Mime; using RecursiveAI.OneMail.Mime.Transfer; using RecursiveAI.OneMail.Text; var message = new MimeMultipart("mixed"); // Address headers are written as given: encode a non-ASCII display name yourself message.Headers.Add("From", $"{Rfc2047.Encode("Zoë Martín")} <[email protected]>"); message.Headers.Add("To", "Sam Lee <[email protected]>"); // Free text such as the subject is encoded for you message.Headers.Add("Subject", "Q3 report – final"); string date = DateTime.UtcNow.ToString("ddd, dd MMM yyyy HH:mm:ss +0000", CultureInfo.InvariantCulture); message.Headers.Add("Date", date); message.Headers.Add("Message-ID", $"<{Guid.NewGuid():N}@example.com>"); message.Headers.Add("MIME-Version", "1.0"); // Plain text and HTML versions of the same body var body = new MimeMultipart("alternative"); var text = new MimePart("text/plain; charset=utf-8"); text.SetDecodedContent(Utf8("Hi Sam,\r\n\r\nThe report is attached.\r\n"), ContentTransferEncoding.QuotedPrintable); var html = new MimePart("text/html; charset=utf-8"); html.SetDecodedContent(Utf8("<p>Hi Sam,</p><p>The report is attached.</p>"), ContentTransferEncoding.QuotedPrintable); body.Add(text); body.Add(html); message.Add(body); // An attachment, base64-encoded (the default) var csv = new MimePart("text/csv; name=\"q3.csv\""); csv.Headers.Add("Content-Disposition", "attachment; filename=\"q3.csv\""); csv.SetDecodedContent(Utf8("month,revenue\r\nJul,1200\r\nAug,1350\r\n")); message.Add(csv); using (FileStream file = File.Create("report.eml")) message.WriteTo(file); Console.WriteLine($"report.eml: {new FileInfo("report.eml").Length:N0} bytes"); // Read it back IMailItem check = Mail.Parse(File.ReadAllBytes("report.eml")); Console.WriteLine($"{check.From[0]} -> {check.ToRecipients[0]}: {check.Subject}"); string plain = check.TextBody!.ReadText(); Console.WriteLine($"text: {plain.ReplaceLineEndings(" ").Trim()}"); IMailAttachment attached = check.Attachments[0]; Console.WriteLine($"attachment: {attached.FileName}, {attached.Size} bytes"); Console.WriteLine($"defects: {check.Defects.Count()}"); static byte[] Utf8(string s) => Encoding.UTF8.GetBytes(s);
report.eml: 1,019 bytes Zoë Martín <[email protected]> -> Sam Lee <[email protected]>: Q3 report – final text: Hi Sam, The report is attached. attachment: q3.csv, 35 bytes defects: 0
report.eml opens in any mail program; Python’s email package also reads it with no defects. A boundary for each multipart is generated for you, and lines end in CRLF as MIME requires.
How the parts fit
multipart/mixedholds the body and the attachments.multipart/alternativeinside it holds versions of the same body, plainest first. Mail programs show the last one they support.SetDecodedContenttakes the raw bytes and encodes them: base64 by default, or quoted-printable for text people may read in the source.- Header values must be one line. A line break throws, so user input can’t inject headers.
Limits
- A preview. 0.2.0-preview.2: the API can change before 1.0.
- A low-level API. There is no message builder yet. You set each header yourself, and you encode non-ASCII display names in address headers with
Rfc2047.Encode, as above. Subjects and other free text are encoded for you. - No sending. SMTP isn’t in this preview. The file is ready to hand to any SMTP client.
- No Outlook formats. OneMail can’t write MSG or PST files yet.
Reading messages back: Parse an EML file. The writer: Reading and writing MIME.