<NME> MimeParserTests.cs <BEF> ﻿// // MimeParserTests.cs // // Author: Jeffrey Stedfast <jestedfa@microsoft.com> // // Copyright (c) 2013-2022 .NET Foundation and Contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // using System; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Globalization; using System.Threading.Tasks; using System.Collections.Generic; using NUnit.Framework; using Newtonsoft.Json; using MimeKit; using MimeKit.IO; using MimeKit.Utils; using MimeKit.IO.Filters; namespace UnitTests { [TestFixture] public class MimeParserTests { static readonly string MessagesDataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "messages"); static readonly string MboxDataDir = Path.Combine (TestHelper.ProjectDir, "TestData", "mbox"); static FormatOptions UnixFormatOptions; public MimeParserTests () { UnixFormatOptions = FormatOptions.Default.Clone (); UnixFormatOptions.NewLineFormat = NewLineFormat.Unix; } [Test] public void TestArgumentExceptions () { using (var stream = new MemoryStream ()) { var parser = new MimeParser (stream); Assert.Throws<ArgumentNullException> (() => new MimeParser (null)); Assert.Throws<ArgumentNullException> (() => new MimeParser (null, stream)); Assert.Throws<ArgumentNullException> (() => new MimeParser (null, MimeFormat.Default)); Assert.Throws<ArgumentNullException> (() => new MimeParser (ParserOptions.Default, null)); Assert.Throws<ArgumentNullException> (() => new MimeParser (null, stream, MimeFormat.Default)); Assert.Throws<ArgumentNullException> (() => new MimeParser (ParserOptions.Default, null, MimeFormat.Default)); Assert.Throws<ArgumentNullException> (() => parser.SetStream (null)); Assert.Throws<ArgumentNullException> (() => parser.SetStream (null, MimeFormat.Default)); #pragma warning disable CS0618 // Type or member is obsolete Assert.Throws<ArgumentNullException> (() => parser.SetStream (null, stream)); Assert.Throws<ArgumentNullException> (() => parser.SetStream (ParserOptions.Default, null)); Assert.Throws<ArgumentNullException> (() => parser.SetStream (null, stream, MimeFormat.Default)); Assert.Throws<ArgumentNullException> (() => parser.SetStream (ParserOptions.Default, null, MimeFormat.Default)); #pragma warning restore CS0618 // Type or member is obsolete Assert.Throws<ArgumentNullException> (() => parser.Options = null); } } [Test] public void TestHeaderParser () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1\r\nHeader-2: value 2\r\nHeader-3: value 3\r\n\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = HeaderList.Load (memory); string value; Assert.AreEqual (3, headers.Count, "Unexpected header count."); value = headers["Header-1"]; Assert.AreEqual ("value 1", value, "Unexpected header value."); value = headers["Header-2"]; Assert.AreEqual ("value 2", value, "Unexpected header value."); value = headers["Header-3"]; Assert.AreEqual ("value 3", value, "Unexpected header value."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public async Task TestHeaderParserAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1\r\nHeader-2: value 2\r\nHeader-3: value 3\r\n\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = await HeaderList.LoadAsync (memory); string value; Assert.AreEqual (3, headers.Count, "Unexpected header count."); value = headers["Header-1"]; Assert.AreEqual ("value 1", value, "Unexpected header value."); value = headers["Header-2"]; Assert.AreEqual ("value 2", value, "Unexpected header value."); value = headers["Header-3"]; Assert.AreEqual ("value 3", value, "Unexpected header value."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public void TestTruncatedHeaderName () { var bytes = Encoding.ASCII.GetBytes ("Header-1"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = HeaderList.Load (memory); Assert.Fail ("Parsing headers should fail."); } catch (FormatException) { } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public async Task TestTruncatedHeaderNameAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = await HeaderList.LoadAsync (memory); Assert.Fail ("Parsing headers should fail."); } catch (FormatException) { } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public void TestTruncatedHeader () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = HeaderList.Load (memory); Assert.AreEqual (1, headers.Count, "Unexpected header count."); var value = headers["Header-1"]; Assert.AreEqual ("value 1", value, "Unexpected header value."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public async Task TestTruncatedHeaderAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = await HeaderList.LoadAsync (memory); Assert.AreEqual (1, headers.Count, "Unexpected header count."); var value = headers["Header-1"]; Assert.AreEqual ("value 1", value, "Unexpected header value."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public void TestSingleHeaderNoTerminator () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = HeaderList.Load (memory); Assert.AreEqual (1, headers.Count, "Unexpected header count."); var value = headers["Header-1"]; Assert.AreEqual ("value 1", value, "Unexpected header value."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public async Task TestSingleHeaderNoTerminatorAsync () { var bytes = Encoding.ASCII.GetBytes ("Header-1: value 1\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = await HeaderList.LoadAsync (memory); Assert.AreEqual (1, headers.Count, "Unexpected header count."); var value = headers["Header-1"]; Assert.AreEqual ("value 1", value, "Unexpected header value."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public void TestEmptyHeaders () { var bytes = Encoding.ASCII.GetBytes ("\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = HeaderList.Load (memory); Assert.AreEqual (0, headers.Count, "Unexpected header count."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public async Task TestEmptyHeadersAsync () { var bytes = Encoding.ASCII.GetBytes ("\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var headers = await HeaderList.LoadAsync (memory); Assert.AreEqual (0, headers.Count, "Unexpected header count."); } catch (Exception ex) { Assert.Fail ("Failed to parse headers: {0}", ex); } } } [Test] public void TestPartialByteOrderMarkEOF () { var bom = new byte[] { 0xEF, 0xBB/*, 0xBF */ }; using (var stream = new MemoryStream (bom, false)) { var parser = new MimeParser (stream, MimeFormat.Entity); Assert.Throws<FormatException> (() => parser.ParseMessage (), "ParseMessage"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Entity); Assert.ThrowsAsync<FormatException> (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); } } [Test] public void TestPartialByteOrderMark () { var bom = new byte[] { 0xEF, 0xBB/*, 0xBF */ }; using (var stream = new MemoryStream ()) { stream.Write (bom, 0, bom.Length); using (var file = File.OpenRead (Path.Combine (MboxDataDir, "simple.mbox.txt"))) file.CopyTo (stream, 4096); stream.Position = 0; var parser = new MimeParser (stream, MimeFormat.Entity); Assert.Throws<FormatException> (() => parser.ParseMessage (), "ParseMessage"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Entity); Assert.ThrowsAsync<FormatException> (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); } } [Test] public void TestParsingGarbage () { using (var stream = new MemoryStream ()) { var line = Encoding.ASCII.GetBytes ("This is just a standard test file... nothing to see here. No MIME anywhere to be found\r\n"); for (int i = 0; i < 200; i++) stream.Write (line, 0, line.Length); stream.Position = 0; var parser = new MimeParser (stream, MimeFormat.Mbox); Assert.Throws<FormatException> (() => parser.ParseMessage (), "Mbox"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Mbox); Assert.ThrowsAsync<FormatException> (async () => await parser.ParseMessageAsync (), "MboxAsync"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Entity); Assert.Throws<FormatException> (() => parser.ParseMessage (), "ParseMessage"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Entity); Assert.ThrowsAsync<FormatException> (async () => await parser.ParseMessageAsync (), "ParseMessageAsync"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Entity); Assert.Throws<FormatException> (() => parser.ParseEntity (), "ParseEntity"); stream.Position = 0; parser.SetStream (stream, MimeFormat.Entity); Assert.ThrowsAsync<FormatException> (async () => await parser.ParseEntityAsync (), "ParseEntityAsync"); } } [Test] public void TestDoubleMboxMarker () { var content = Encoding.ASCII.GetBytes ("From - \r\nFrom -\r\nFrom: sender@example.com\r\nTo: recipient@example.com\r\nSubject: test message\r\n\r\nBody text\r\n"); using (var stream = new MemoryStream (content, false)) { var parser = new MimeParser (stream, MimeFormat.Mbox); MimeMessage message; message = parser.ParseMessage (); Assert.AreEqual (0, message.Headers.Count); message = parser.ParseMessage (); Assert.AreEqual (3, message.Headers.Count); } } [Test] public async Task TestDoubleMboxMarkerAsync () { var content = Encoding.ASCII.GetBytes ("From - \r\nFrom -\r\nFrom: sender@example.com\r\nTo: recipient@example.com\r\nSubject: test message\r\n\r\nBody text\r\n"); using (var stream = new MemoryStream (content, false)) { var parser = new MimeParser (stream, MimeFormat.Mbox); MimeMessage message; message = await parser.ParseMessageAsync (); Assert.AreEqual (0, message.Headers.Count); message = await parser.ParseMessageAsync (); Assert.AreEqual (3, message.Headers.Count); } } [Test] public void TestEmptyMessage () { var bytes = Encoding.ASCII.GetBytes ("\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var message = MimeMessage.Load (memory); Assert.AreEqual (0, message.Headers.Count, "Unexpected header count."); } catch (Exception ex) { Assert.Fail ("Failed to parse message: {0}", ex); } } } [Test] public async Task TestEmptyMessageAsync () { var bytes = Encoding.ASCII.GetBytes ("\r\n"); using (var memory = new MemoryStream (bytes, false)) { try { var message = await MimeMessage.LoadAsync (memory); Assert.AreEqual (0, message.Headers.Count, "Unexpected header count."); } catch (Exception ex) { Assert.Fail ("Failed to parse message: {0}", ex); } } } [Test] public void TestInvalidContentType () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of recovery from invalid media-type in Content-Type header Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: garbage; charset=utf-8 This is the message body. ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<MimePart> (message.Body, "Expected top-level to be a MimePart"); var part = (MimePart) message.Body; Assert.AreEqual ("application/octet-stream", part.ContentType.MimeType, "Expected application/octet-stream"); Assert.AreEqual ("utf-8", part.ContentType.Charset, "Expected to keep Content-Type parameters"); var body = new TextPart ("plain") { Content = part.Content }; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<MimePart> (message.Body, "Expected top-level to be a MimePart"); var part = (MimePart) message.Body; Assert.AreEqual ("application/octet-stream", part.ContentType.MimeType, "Expected application/octet-stream"); Assert.AreEqual ("utf-8", part.ContentType.Charset, "Expected to keep Content-Type parameters"); var body = new TextPart ("plain") { Content = part.Content }; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } [Test] public async Task TestInvalidContentTypeAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of recovery from invalid media-type in Content-Type header Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: garbage; charset=utf-8 This is the message body. ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<MimePart> (message.Body, "Expected top-level to be a MimePart"); var part = (MimePart) message.Body; Assert.AreEqual ("application/octet-stream", part.ContentType.MimeType, "Expected application/octet-stream"); Assert.AreEqual ("utf-8", part.ContentType.Charset, "Expected to keep Content-Type parameters"); var body = new TextPart ("plain") { Content = part.Content }; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<MimePart> (message.Body, "Expected top-level to be a MimePart"); var part = (MimePart) message.Body; Assert.AreEqual ("application/octet-stream", part.ContentType.MimeType, "Expected application/octet-stream"); Assert.AreEqual ("utf-8", part.ContentType.Charset, "Expected to keep Content-Type parameters"); var body = new TextPart ("plain") { Content = part.Content }; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } [Test] public void TestHeaderFieldNameBeginsWithColon () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of a header line starting with ':' Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: text/plain; charset=utf-8 : What header is this? This is the message body. ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<TextPart> (message.Body, "Expected top-level to be a TextPart"); var header = message.Headers[message.Headers.Count - 1]; // FIXME: Should this really be "valid"? Assert.IsFalse (header.IsInvalid, "IsInvalid is expected to be false"); Assert.AreEqual (string.Empty, header.Field, "Field is expected to be empty"); Assert.AreEqual ("What header is this?", header.Value); var body = (TextPart) message.Body; Assert.AreEqual ("text/plain", body.ContentType.MimeType, "Expected text/plain"); Assert.AreEqual ("utf-8", body.ContentType.Charset, "Expected to keep Content-Type parameters"); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<TextPart> (message.Body, "Expected top-level to be a TextPart"); var header = message.Headers[message.Headers.Count - 1]; // FIXME: Should this really be "valid"? Assert.IsFalse (header.IsInvalid, "IsInvalid is expected to be false"); Assert.AreEqual (string.Empty, header.Field, "Field is expected to be empty"); Assert.AreEqual ("What header is this?", header.Value); var body = (TextPart) message.Body; Assert.AreEqual ("text/plain", body.ContentType.MimeType, "Expected text/plain"); Assert.AreEqual ("utf-8", body.ContentType.Charset, "Expected to keep Content-Type parameters"); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } File.WriteAllText (path, actual); var summary = File.ReadAllText (path).Replace ("\r\n", "\n"); var original = new MemoryBlockStream (); var expected = new byte[4096]; var buffer = new byte[4096]; int nx, n; Assert.AreEqual (summary, actual, "Summaries do not match for {0}.mbox", baseName); using (var stream = File.OpenRead (Path.Combine (MboxDataDir, baseName + ".mbox.txt"))) { using (var filtered = new FilteredStream (original)) { filtered.Add (new Dos2UnixFilter ()); stream.CopyTo (filtered); filtered.Flush (); } } original.Position = 0; output.Position = 0; Assert.AreEqual (original.Length, output.Length, "The length of the mbox did not match."); do { var position = original.Position; nx = original.Read (expected, 0, expected.Length); n = output.Read (buffer, 0, buffer.Length); if (nx == 0) break; for (int i = 0; i < nx; i++) { if (buffer[i] == expected[i]) continue; var strExpected = CharsetUtils.Latin1.GetString (expected, 0, nx); var strActual = CharsetUtils.Latin1.GetString (buffer, 0, n); Assert.AreEqual (strExpected, strActual, "The mbox differs at position {0}", position + i); } } while (true); } void TestMbox (ParserOptions options, string baseName) { var format = FormatOptions.Default.Clone (); var output = new MemoryBlockStream (); var builder = new StringBuilder (); format.NewLineFormat = NewLineFormat.Unix; using (var stream = File.OpenRead (Path.Combine (MboxDataDir, baseName + ".mbox.txt"))) { var parser = options != null ? new MimeParser (options, stream, MimeFormat.Mbox) : new MimeParser (stream, MimeFormat.Mbox); int count = 0; Assert.IsFalse (header.IsInvalid, "IsInvalid is expected to be false"); Assert.AreEqual (string.Empty, header.Field, "Field is expected to be empty"); Assert.AreEqual ("What header is this?", header.Value); var body = (TextPart) message.Body; Assert.AreEqual ("text/plain", body.ContentType.MimeType, "Expected text/plain"); Assert.AreEqual ("utf-8", body.ContentType.Charset, "Expected to keep Content-Type parameters"); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } DumpMimeTree (builder, message); builder.Append ('\n'); var marker = Encoding.UTF8.GetBytes ((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n"); output.Write (marker, 0, marker.Length); message.WriteTo (format, output); count++; } } X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" async Task TestMboxAsync (ParserOptions options, string baseName) { var format = FormatOptions.Default.Clone (); var output = new MemoryBlockStream (); var builder = new StringBuilder (); format.NewLineFormat = NewLineFormat.Unix; using (var stream = File.OpenRead (Path.Combine (MboxDataDir, baseName + ".mbox.txt"))) { var parser = options != null ? new MimeParser (options, stream, MimeFormat.Mbox) : new MimeParser (stream, MimeFormat.Mbox); int count = 0; using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); DumpMimeTree (builder, message); builder.Append ('\n'); var marker = Encoding.UTF8.GetBytes ((count > 0 ? "\n" : string.Empty) + parser.MboxMarker + "\n"); await output.WriteAsync (marker, 0, marker.Length); await message.WriteToAsync (format, output); count++; } } Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } [Test] public async Task TestMultipartBoundaryWithoutTrailingNewlineAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of multipart boundary w/o trailing newline Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } [Test] public void TestTruncatedMultipartSubpartHeaders () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of truncated multipart subpart headers Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } } [Test] public async Task TestTruncatedMultipartSubpartHeadersAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of truncated multipart subpart headers Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } } [Test] public void TestTruncatedMultipartSubpartHeaderFieldName () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of truncated multipart subpart header field name Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 Content-Dis".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual (2, body.Headers.Count, "Expected 2 headers"); Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.IsTrue (body.Headers[1].IsInvalid); Assert.AreEqual ("Content-Dis", body.Headers[1].Field); Assert.AreEqual (string.Empty, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual (2, body.Headers.Count, "Expected 2 headers"); Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.IsTrue (body.Headers[1].IsInvalid); Assert.AreEqual ("Content-Dis", body.Headers[1].Field); Assert.AreEqual (string.Empty, body.Text); } } [Test] public async Task TestTruncatedMultipartSubpartHeaderFieldNameAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of truncated multipart subpart header field name Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 Content-Dis".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual (2, body.Headers.Count, "Expected 2 headers"); Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.IsTrue (body.Headers[1].IsInvalid); Assert.AreEqual ("Content-Dis", body.Headers[1].Field); Assert.AreEqual (string.Empty, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual (2, body.Headers.Count, "Expected 2 headers"); Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.IsTrue (body.Headers[1].IsInvalid); Assert.AreEqual ("Content-Dis", body.Headers[1].Field); Assert.AreEqual (string.Empty, body.Text); } } [Test] public void TestMultipartSubpartHeadersEndWithBoundary () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of multipart subpart headers ending with a boundary Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } } [Test] public async Task TestMultipartSubpartHeadersEndWithBoundaryAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of multipart subpart headers ending with a boundary Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (string.Empty, body.Text); } } [Test] public void TestMultipartSubpartHeadersLineStartsWithDashDash () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of multipart subpart headers ending with a boundary Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 --not-the-boundary-muhahaha This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (2, body.Headers.Count); Assert.IsTrue (body.Headers[1].IsInvalid, "IsInvalid"); Assert.AreEqual ("--not-the-boundary-muhahaha\n", body.Headers[1].Field); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (2, body.Headers.Count); Assert.IsTrue (body.Headers[1].IsInvalid, "IsInvalid"); Assert.AreEqual ("--not-the-boundary-muhahaha\r\n", body.Headers[1].Field); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } [Test] public async Task TestMultipartSubpartHeadersLineStartsWithDashDashyAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of multipart subpart headers ending with a boundary Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 --not-the-boundary-muhahaha This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (2, body.Headers.Count); Assert.IsTrue (body.Headers[1].IsInvalid, "IsInvalid"); Assert.AreEqual ("--not-the-boundary-muhahaha\n", body.Headers[1].Field); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (1, multipart.Count, "Expected 1 child"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual (2, body.Headers.Count); Assert.IsTrue (body.Headers[1].IsInvalid, "IsInvalid"); Assert.AreEqual ("--not-the-boundary-muhahaha\r\n", body.Headers[1].Field); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); } } [Test] public void TestMultipartBoundaryLineWithTrailingSpacesAndThenMoreCharacters () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of a multipart boundary followed by trailing whitespace and then more characters Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the first part. ------=_NextPart_000_003F_01CE98CE.6E826F90 oops, not it. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the second part. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine + Environment.NewLine + "------=_NextPart_000_003F_01CE98CE.6E826F90 oops, not it.", body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the second part." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine + Environment.NewLine + "------=_NextPart_000_003F_01CE98CE.6E826F90 oops, not it.", body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the second part." + Environment.NewLine, body.Text); } } [Test] public async Task TestMultipartBoundaryLineWithTrailingSpacesAndThenMoreCharactersAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of a multipart boundary followed by trailing whitespace and then more characters Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the first part. ------=_NextPart_000_003F_01CE98CE.6E826F90 oops, not it. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the second part. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine + Environment.NewLine + "------=_NextPart_000_003F_01CE98CE.6E826F90 oops, not it.", body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the second part." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine + Environment.NewLine + "------=_NextPart_000_003F_01CE98CE.6E826F90 oops, not it.", body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the second part." + Environment.NewLine, body.Text); } } [Test] public void TestMultipartDoubleBoundary () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of double multipart boundaries Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the first part. ------=_NextPart_000_003F_01CE98CE.6E826F90 ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is technically the third part. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine, body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is technically the third part." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine, body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is technically the third part." + Environment.NewLine, body.Text); } } [Test] public async Task TestMultipartDoubleBoundaryAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of double multipart boundaries Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the first part. ------=_NextPart_000_003F_01CE98CE.6E826F90 ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is technically the third part. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine, body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is technically the third part." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the first part." + Environment.NewLine, body.Text); Assert.IsInstanceOf<TextPart> (multipart[1], "Expected second child of the multipart to be text/plain"); body = (TextPart) multipart[1]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is technically the third part." + Environment.NewLine, body.Text); } } [Test] public void TestMultipartWithoutBoundaryParameter () { string text = @"Content-Type: multipart/mixed ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the first part. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the second part. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); int dashes = text.IndexOf ("--"); var preamble = text.Substring (dashes); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var multipart = (Multipart) parser.ParseEntity (); Assert.IsNull (multipart.Boundary, "Boundary"); Assert.AreEqual (0, multipart.Count, "Expected 0 children"); Assert.AreEqual (preamble, multipart.Preamble, "Preamble"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var multipart = (Multipart) parser.ParseEntity (); Assert.IsNull (multipart.Boundary, "Boundary"); Assert.AreEqual (0, multipart.Count, "Expected 0 children"); Assert.AreEqual (preamble.Replace ("\n", "\r\n"), multipart.Preamble, "Preamble"); } } [Test] public async Task TestMultipartWithoutBoundaryParameterAsync () { string text = @"Content-Type: multipart/mixed ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the first part. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the second part. ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); int dashes = text.IndexOf ("--"); var preamble = text.Substring (dashes); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var multipart = (Multipart) await parser.ParseEntityAsync (); Assert.IsNull (multipart.Boundary, "Boundary"); Assert.AreEqual (0, multipart.Count, "Expected 0 children"); Assert.AreEqual (preamble, multipart.Preamble, "Preamble"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var multipart = (Multipart) await parser.ParseEntityAsync (); Assert.IsNull (multipart.Boundary, "Boundary"); Assert.AreEqual (0, multipart.Count, "Expected 0 children"); Assert.AreEqual (preamble.Replace ("\n", "\r\n"), multipart.Preamble, "Preamble"); } } [Test] public void TestTruncatedImmediatelyAfterMessageRfc822Headers () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of message/rfc822 part truncated immediately after the MIME headers Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: message/rfc822 ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } } [Test] public async Task TestTruncatedImmediatelyAfterMessageRfc822HeadersAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of message/rfc822 part truncated immediately after the MIME headers Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: message/rfc822 ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } } [Test] public void TestMessageRfc822WithBoundaryBeforeMessage () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of message/rfc822 part with a From-marker before the message Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" Content-Length: 420 ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: message/rfc822 ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } } [Test] public async Task TestMessageRfc822WithBoundaryBeforeMessageAsync () { string text = @"From: mimekit@example.com To: mimekit@example.com Subject: test of message/rfc822 part with a From-marker before the message Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" Content-Length: 420 ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: message/rfc822 ------=_NextPart_000_003F_01CE98CE.6E826F90-- ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (stream, MimeFormat.Entity); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsNull (rfc822.Message, "Message"); } } [Test] public void TestMessageRfc822WithFromMarkerBeforeMessage () { string text = @"From - From: mimekit@example.com To: mimekit@example.com Subject: test of message/rfc822 part with a From-marker before the message Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" Content-Length: 420 ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: message/rfc822 From - From: mimekit@example.com To: mimekit@example.com Subject: embedded message Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 This is the embedded message body. ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var options = ParserOptions.Default.Clone (); options.RespectContentLength = true; var parser = new MimeParser (options, stream, MimeFormat.Mbox); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsInstanceOf<TextPart> (rfc822.Message.Body, "Expected child of the embedded message to be text/plain"); body = (TextPart) rfc822.Message.Body; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the embedded message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var options = ParserOptions.Default.Clone (); options.RespectContentLength = true; var parser = new MimeParser (options, stream, MimeFormat.Mbox); var message = parser.ParseMessage (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsInstanceOf<TextPart> (rfc822.Message.Body, "Expected child of the embedded message to be text/plain"); body = (TextPart) rfc822.Message.Body; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the embedded message body." + Environment.NewLine, body.Text); } } [Test] public async Task TestMessageRfc822WithFromMarkerBeforeMessageAsync () { string text = @"From - From: mimekit@example.com To: mimekit@example.com Subject: test of message/rfc822 part with a From-marker before the message Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Message-ID: <54AD68C9E3B0184CAC6041320424FD1B5B81E74D@localhost.localdomain> X-Mailer: Microsoft Office Outlook 12.0 Content-Type: multipart/mixed; boundary=""----=_NextPart_000_003F_01CE98CE.6E826F90"" Content-Length: 420 ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: text/plain; charset=utf-8 This is the message body. ------=_NextPart_000_003F_01CE98CE.6E826F90 Content-Type: message/rfc822 From - From: mimekit@example.com To: mimekit@example.com Subject: embedded message Date: Tue, 12 Nov 2013 09:12:42 -0500 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 This is the embedded message body. ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var options = ParserOptions.Default.Clone (); options.RespectContentLength = true; var parser = new MimeParser (options, stream, MimeFormat.Mbox); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsInstanceOf<TextPart> (rfc822.Message.Body, "Expected child of the embedded message to be text/plain"); body = (TextPart) rfc822.Message.Body; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the embedded message body." + Environment.NewLine, body.Text); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var options = ParserOptions.Default.Clone (); options.RespectContentLength = true; var parser = new MimeParser (options, stream, MimeFormat.Mbox); var message = await parser.ParseMessageAsync (); Assert.IsInstanceOf<Multipart> (message.Body, "Expected top-level to be a multipart"); var multipart = (Multipart) message.Body; Assert.AreEqual (2, multipart.Count, "Expected 2 children"); Assert.IsInstanceOf<TextPart> (multipart[0], "Expected first child of the multipart to be text/plain"); var body = (TextPart) multipart[0]; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the message body." + Environment.NewLine, body.Text); Assert.IsInstanceOf<MessagePart> (multipart[1], "Expected second child of the multipart to be message/rfc822"); var rfc822 = (MessagePart) multipart[1]; Assert.IsInstanceOf<TextPart> (rfc822.Message.Body, "Expected child of the embedded message to be text/plain"); body = (TextPart) rfc822.Message.Body; Assert.AreEqual ("text/plain; charset=utf-8", body.Headers[HeaderId.ContentType]); Assert.AreEqual ("utf-8", body.ContentType.Charset); Assert.AreEqual ("This is the embedded message body." + Environment.NewLine, body.Text); } } [Test] public void TestMessageRfc822WithMungedFromMarkerBeforeMessage () { string text = @"From - Fri Mar 7 02:51:22 1997 Return-Path: <jwz@netscape.com> Received: from gruntle ([205.217.227.10]) by dredd.mcom.com (Netscape Mail Server v2.02) with SMTP id AAA4040 for <jwz@netscape.com>; Fri, 7 Mar 1997 02:50:37 -0800 Sender: jwz@netscape.com (Jamie Zawinski) Message-ID: <331FF2FF.FF6@netscape.com> Date: Fri, 07 Mar 1997 02:50:39 -0800 From: Jamie Zawinski <jwz@netscape.com> Organization: Netscape Communications Corporation, Mozilla Division X-Mailer: Mozilla 3.01 (X11; U; IRIX 6.2 IP22) MIME-Version: 1.0 To: Jamie Zawinski <jwz@netscape.com> Subject: forwarded encrypted message Content-Type: message/rfc822; name=""smime18-encrypted.msg"" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename=""smime18-encrypted.msg"" X-Mozilla-Status: 0001 Content-Length: 2812 >From - Fri Dec 13 15:01:21 1996 Return-Path: <blaker@craswell.com> Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com (Netscape Mail Server v2.02) with SMTP id AAA19742 for <jwz@dredd.mcom.com>; Fri, 13 Dec 1996 14:59:31 -0800 Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id OAA23726 for <jwz@netscape.com>; Fri, 13 Dec 1996 14:58:13 -0800 Received: from peapod.deming.com (host20.deming.com [206.63.131.20]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id OAA00270 for <jwz@netscape.com>; Fri, 13 Dec 1996 14:59:27 -0800 (PST) Received: by peapod.deming.com from localhost (router,SLmail V2.0); Fri, 13 Dec 1996 15:01:48 Pacific Standard Time Received: by peapod.deming.com from seth (206.63.131.30::mail daemon; unverified,SLmail V2.0); Fri, 13 Dec 1996 15:01:02 Pacific Standard Time Message-Id: <3.0.32.19961213150855.009172e0@mail.craswell.com> X-Sender: blaker@mail.craswell.com X-Mailer: Windows Eudora Pro Version 3.0 (32) Date: Fri, 13 Dec 1996 15:09:42 -0800 To: Jamie Zawinski <jwz@netscape.com> From: ""Blake Ramsdell"" <blaker@craswell.com> Subject: Re: can you send me an encrypted message? MIME-Version: 1.0 Content-Type: application/x-pkcs7-mime; name=""smime.p7m"" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename=""smime.p7m"" MIAGCSqGSIb3DQEHA6CAMIACAQAxgDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcw FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAt IEluZGl2aWR1YWwgU3Vic2NyaWJlcgIQKQ/GF/RumodE+WtXiPJmhDANBgkqhkiG9w0BAQEF AARAb0tthyav05ce7KBWdlfN1M0R6wLQ2FWPVQynuWo/yHUoo3hiII7j15FXNgnxF7QkY5/p mZXg0P2eJ1iYQy1vZDCBzAIBADB2MGIxETAPBgNVBAcTCEludGVybmV0MRcwFQYDVQQKEw5W ZXJpU2lnbiwgSW5jLjE0MDIGA1UECxMrVmVyaVNpZ24gQ2xhc3MgMSBDQSAtIEluZGl2aWR1 YWwgU3Vic2NyaWJlcgIQDOtpec1+JM3EpqAMVqgtjzANBgkqhkiG9w0BAQEFAARAuqnsnz1O qEdx7NEMJDEdjccjdEuCM8x2euTYlU/GWNY+s2iKVahbT3/R8E8hp3YfrHd2sjvgy6teTOPO ZI2SxwAAMIAGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIlhWqtbsElaWggASCAjBooYYTWSBz 7A4l0Aho7mK85zpMyAR0xTKqHXT0zL9XpHbKPAcETaBTh1n7e8aJeQ93ONGAs6tVVlA6bpUN F3Q5O+ZuNXOMT83HIKRYEO1l8a+CH7XtUiQWtu/aBt12GQDX475WhPULKEJs7kLS2DwToRX/ ctwEPNwc6zfsOZoVTQ5HOwisvDZ2QGwa08Psj38SaQ0Y+ryk5FeiAtKQUZ0uuJWI/rRu64yj KmVs1DDId18coftA2rv/u2/zABEX8u5ckEkwS7fO7UHv6XMCQ3kqgqIZZE1zIGohfUdtOYYo M4eki3QDyovHPxEjBbnmpUw2xDN7/DdxYEZ4CteWurQ+VoP0PUM2qwi6EgM6MpVKg8KzOWdb aV51a1oQKtpJJFZqZtFf9SQ4OW6NKXHsJ2AF8W4OQ+ySWQN43wMk8dGJYlPrREqn5RufPg3k QM+s4VwTrS2TrU+ELZCYnJFfH+N7tE8ILrFMAteVxtqjat7OJRyDxy0cnBP+oG81Sr0zvbdC jUPUDFlrPgFjDrswX1UpkEE2OgKWmfc134AbysJFOuCIze2XqKB96rJvxS76ygzVvrU/4sI1 6VDlZUEuUPaBUOimFxRk/rqPJDI1M8rNKykw9qsoWQMRnvrODfzo7iVWQ0TQHiwfoBhs6Dvm UgrMwopFnzRdSHvT1acSqVfMYWm5nXImvtCuFAavkjDutE9+Y/LLFLBUpAVeu3rwW3wV0Tcv 9I6Afej0ntfbH9vlRwQIl7MeXMqoBV0AAAAAAAAAAAAA ".Replace ("\r\n", "\n"); using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text), false)) { var parser = new MimeParser (ParserOptions.Default, stream, MimeFormat.Mbox); var message = parser.ParseMessage (); Assert.IsInstanceOf<MessagePart> (message.Body, "Expected top-level to be a MessagePart"); var rfc822 = (MessagePart) message.Body; Assert.AreEqual ("smime18-encrypted.msg", rfc822.ContentType.Name, "MessagePart.ContentType.Name"); Assert.AreEqual ("inline", rfc822.ContentDisposition.Disposition, "MessagePart.ContentDisposition.DIsposition"); Assert.AreEqual ("smime18-encrypted.msg", rfc822.ContentDisposition.FileName, "MessagePart.ContentDisposition.FileName"); //Assert.AreEqual (ContentEncoding.SevenBit, rfc822.ContentTransferEncoding, "MessagePart.ContentTransferEncoding"); Assert.NotNull (rfc822.Message, "MessagePart.Message"); Assert.NotNull (rfc822.Message.MboxMarker, "MessagePart.Message.MboxMarker"); Assert.AreEqual (">From - Fri Dec 13 15:01:21 1996\n", Encoding.ASCII.GetString (rfc822.Message.MboxMarker)); Assert.AreEqual (14, rfc822.Message.Headers.Count, "MessagePart.Message.Headers.Count"); Assert.AreEqual (3, rfc822.Message.Body.Headers.Count, "MessagePart.Message.Body.Headers.Count"); } using (var stream = new MemoryStream (Encoding.ASCII.GetBytes (text.Replace ("\n", "\r\n")), false)) { var parser = new MimeParser (ParserOptions.Default, stream, MimeFormat.Mbox); var message = parser.ParseMessage (); Assert.IsInstanceOf<MessagePart> (message.Body, "Expected top-level to be a MessagePart"); var rfc822 = (MessagePart) message.Body; Assert.AreEqual ("smime18-encrypted.msg", rfc822.ContentType.Name, "MessagePart.ContentType.Name"); Assert.AreEqual ("inline", rfc822.ContentDisposition.Disposition, "MessagePart.ContentDisposition.DIsposition"); Assert.AreEqual ("smime18-encrypted.msg", rfc822.ContentDisposition.FileName, "MessagePart.ContentDisposition.FileName"); //Assert.AreEqual (ContentEncoding.SevenBit, rfc822.ContentTransferEncoding, "MessagePart.ContentTransferEncoding"); Assert.NotNull (rfc822.Message, "MessagePart.Message"); Assert.NotNull (rfc822.Message.MboxMarker, "MessagePart.Message.MboxMarker"); Assert.AreEqual (">From - Fri Dec 13 15:01:21 1996\r\n", Encoding.ASCII.GetString (rfc822.Message.MboxMarker)); Assert.AreEqual (14, rfc822.Message.Headers.Count, "MessagePart.Message.Headers.Count"); Assert.AreEqual (3, rfc822.Message.Body.Headers.Count, "MessagePart.Message.Body.Headers.Count"); } } [Test] public async Task TestMessageRfc822WithMungedFromMarkerBeforeMessageAsync () { string text = @"From - Fri Mar 7 02:51:22 1997 Return-Path: <jwz@netscape.com> Received: from gruntle ([205.217.227.10]) by dredd.mcom.com (Netscape Mail Server v2.02) with SMTP id AAA4040 for <jwz@netscape.com>; Fri, 7 Mar 1997 02:50:37 -0800 Sender: jwz@netscape.com (Jamie Zawinski) Message-ID: <331FF2FF.FF6@netscape.com> Date: Fri, 07 Mar 1997 02:50:39 -0800 From: Jamie Zawinski <jwz@netscape.com> Organization: Netscape Communications Corporation, Mozilla Division X-Mailer: Mozilla 3.01 (X11; U; IRIX 6.2 IP22) MIME-Version: 1.0 To: Jamie Zawinski <jwz@netscape.com> Subject: forwarded encrypted message Content-Type: message/rfc822; name=""smime18-encrypted.msg"" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename=""smime18-encrypted.msg"" X-Mozilla-Status: 0001 Content-Length: 2812 >From - Fri Dec 13 15:01:21 1996 Return-Path: <blaker@craswell.com> Received: from maleman.mcom.com ([198.93.92.3]) by dredd.mcom.com (Netscape Mail Server v2.02) with SMTP id AAA19742 for <jwz@dredd.mcom.com>; Fri, 13 Dec 1996 14:59:31 -0800 Received: from xwing.netscape.com (xwing.mcom.com [205.218.156.54]) by maleman.mcom.com (8.6.9/8.6.9) with ESMTP id OAA23726 for <jwz@netscape.com>; Fri, 13 Dec 1996 14:58:13 -0800 Received: from peapod.deming.com (host20.deming.com [206.63.131.20]) by xwing.netscape.com (8.7.6/8.7.3) with SMTP id OAA00270 for <jwz@netscape.com>; Fri, 13 Dec 1996 14:59:27 -0800 (PST) Received: by peapod.deming.com from localhost (router,SLmail V2.0); Fri, 13 Dec 1996 15:01:48 Pacific Standard Time Received: by peapod.deming.com from seth (206.63.131.30::mail daemon; unverified,SLmail V2.0); Fri, 13 Dec 1996 15:01:02 Pacific Standard Time Message-Id: <3.0.32.19961213150855.009172e0@mail.craswell.com> X-Sender: blaker@mail.craswell.com X-Mailer: Windows Eudora Pro Version 3.0 (32) Date: Fri, 13 Dec 1996 15:09:42 -0800 To: Jamie Zawinski <jwz@netscape.com> From: ""Blake Ramsdell"" <blaker@craswell.com> Subject: Re: can you send me an encrypted message?
{'addition_count': 22, 'commit_subject': 'Fixed MimeParser tests on Windows/VS', 'deletion_count': 36, 'file_extension': '.cs', 'lang': 'cs', 'license': 'mit', 'repo_name': 'jstedfast/MimeKit'}