public void TestComplexMultiPartMessage() { const string multiPartMessage = "MIME-Version: 1.0\r\n" + "From: Nathaniel Borenstein <*****@*****.**>\r\n" + "To: Ned Freed <*****@*****.**>\r\n" + "Date: Fri, 07 Oct 1994 16:15:05 -0700 (PDT)\r\n" + "Subject: A multipart example\r\n" + "Content-Type: multipart/mixed;\r\n" + "\t\t\t\t\t\t boundary=unique-boundary-1\r\n" + "\r\n" + "This is the preamble area of a multipart message.\r\n" + "Mail readers that understand multipart format\r\n" + "should ignore this preamble.\r\n" + "\r\n" + "If you are reading this text, you might want to\r\n" + "consider changing to a mail reader that understands\r\n" + "how to properly display multipart messages.\r\n" + "\r\n" + "--unique-boundary-1\r\n" + "\r\n" + " ... Some text appears here ...\r\n" + "--unique-boundary-1\r\n" + "Content-type: text/plain; charset=US-ASCII\r\n" + "\r\n" + "This could have been part of the previous part, but\r\n" + "illustrates explicit versus implicit typing of body\r\n" + "parts.\r\n" + "--unique-boundary-1\r\n" + "Content-Type: multipart/parallel; boundary=unique-boundary-2\r\n" + "\r\n" + "--unique-boundary-2\r\n" + "Content-Type: audio/basic\r\n" + "Content-Transfer-Encoding: base64\r\n" + "\r\n" + "dGVzdCBhdWRpbw==\r\n" + // "test audio" in base64 "--unique-boundary-2\r\n" + "Content-Type: image/jpeg\r\n" + "Content-Transfer-Encoding: base64\r\n" + "\r\n" + "dGVzdCBpbWFnZQ==\r\n" + // "test image" in base64 "--unique-boundary-2--\r\n" + "\r\n" + "--unique-boundary-1\r\n" + "Content-type: text/enriched\r\n" + "\r\n" + "This is <bold><italic>enriched.</italic></bold>\r\n" + "<smaller>as defined in RFC 1896</smaller>\r\n" + "\r\n" + "Isn\'t it\r\n" + "<bigger><bigger>cool?</bigger></bigger>\r\n" + "--unique-boundary-1\r\n" + "Content-Type: message/rfc822\r\n" + "\r\n" + "From: Test <*****@*****.**>\r\n" + "To: Test <*****@*****.**>\r\n" + "Subject: Test subject\r\n" + "Content-Type: Text/plain; charset=ISO-8859-1\r\n" + "Content-Transfer-Encoding: Quoted-printable\r\n" + "\r\n" + "... Additional text in ISO-8859-1 goes here ... 3 + 5 =3D 8\r\n" + "--unique-boundary-1--"; // No special characters used - we can use ASCII to get the bytes OPMessage message = new OPMessage(Encoding.ASCII.GetBytes(multiPartMessage)); Assert.AreEqual("1.0", message.Headers.MimeVersion); // From Assert.AreEqual("Nathaniel Borenstein", message.Headers.From.DisplayName); Assert.AreEqual("*****@*****.**", message.Headers.From.Address); // To Assert.NotNull(message.Headers.To); Assert.AreEqual(1, message.Headers.To.Count); Assert.AreEqual("Ned Freed", message.Headers.To[0].DisplayName); Assert.AreEqual("*****@*****.**", message.Headers.To[0].Address); // Date Assert.AreEqual("Fri, 07 Oct 1994 16:15:05 -0700 (PDT)", message.Headers.Date); // -0700 is the same as adding 7 hours in the UTC DateTime Assert.AreEqual(new DateTime(1994, 10, 7, 23, 15, 05, DateTimeKind.Utc), message.Headers.DateSent); // Subject Assert.AreEqual("A multipart example", message.Headers.Subject); MessagePart part1 = message.MessagePart; Assert.AreEqual("multipart/mixed", part1.ContentType.MediaType); Assert.IsTrue(part1.IsMultiPart); Assert.NotNull(part1.MessageParts); Assert.IsNull(part1.Body); // There is a total of 5 multiparts in the first message (unique-boundary-1) Assert.AreEqual(5, part1.MessageParts.Count); // Fetch out the parts, which are checked against later System.Collections.Generic.List<MessagePart> attachments = message.FindAllAttachments(); System.Collections.Generic.List<MessagePart> textVersions = message.FindAllTextVersions(); // We are now going one level deeper into the message tree { MessagePart part1Part1 = part1.MessageParts[0]; Assert.NotNull(part1Part1); Assert.IsFalse(part1Part1.IsMultiPart); Assert.NotNull(part1Part1.Body); Assert.AreEqual("text/plain", part1Part1.ContentType.MediaType); Assert.AreEqual(" ... Some text appears here ...", part1Part1.GetBodyAsText()); // Check that the fetching algoritm for finding a plain-text version is working Assert.AreEqual(part1Part1, message.FindFirstPlainTextVersion()); // Check this message is included in the text version Assert.Contains(part1Part1, textVersions); // But not included in the attachments Assert.IsFalse(attachments.Contains(part1Part1)); // We are now going one level deeper into the message tree { MessagePart part1Part2 = part1.MessageParts[1]; Assert.NotNull(part1Part2); Assert.IsFalse(part1Part2.IsMultiPart); Assert.NotNull(part1Part2.Body); Assert.AreEqual("text/plain", part1Part2.ContentType.MediaType); Assert.AreEqual("US-ASCII", part1Part2.ContentType.CharSet); Assert.AreEqual("This could have been part of the previous part, but\r\n" + "illustrates explicit versus implicit typing of body\r\n" + "parts.", part1Part2.GetBodyAsText()); // Check this message is included in the text version Assert.Contains(part1Part2, textVersions); // But not included in the attachments Assert.IsFalse(attachments.Contains(part1Part2)); } // We are now going one level deeper into the message tree { MessagePart part1Part3 = part1.MessageParts[2]; Assert.NotNull(part1Part3); Assert.IsTrue(part1Part3.IsMultiPart); Assert.IsNotNull(part1Part3.MessageParts); Assert.IsNull(part1Part3.Body); // There is a total of message parts in part1Part3 Assert.AreEqual(2, part1Part3.MessageParts.Count); Assert.AreEqual("multipart/parallel", part1Part3.ContentType.MediaType); // Check this message is not in the text versions Assert.IsFalse(textVersions.Contains(part1Part3)); // Check this message is not included in the attachments Assert.IsFalse(attachments.Contains(part1Part3)); // We are now diving into part1Part3 multiparts - therefore going one level deeper in the message tree { MessagePart part1Part3Part1 = part1Part3.MessageParts[0]; Assert.NotNull(part1Part3Part1); Assert.IsFalse(part1Part3Part1.IsMultiPart); Assert.NotNull(part1Part3Part1.Body); Assert.AreEqual("audio/basic", part1Part3Part1.ContentType.MediaType); Assert.AreEqual(ContentTransferEncoding.Base64, part1Part3Part1.ContentTransferEncoding); Assert.AreEqual("test audio", part1Part3Part1.GetBodyAsText()); // Check this message is not in the text versions Assert.IsFalse(textVersions.Contains(part1Part3Part1)); // Check this message is included in the attachments Assert.Contains(part1Part3Part1, attachments); MessagePart part1Part3Part2 = part1Part3.MessageParts[1]; Assert.NotNull(part1Part3Part2); Assert.IsFalse(part1Part3Part2.IsMultiPart); Assert.NotNull(part1Part3Part2.Body); Assert.AreEqual("image/jpeg", part1Part3Part2.ContentType.MediaType); Assert.AreEqual(ContentTransferEncoding.Base64, part1Part3Part2.ContentTransferEncoding); Assert.AreEqual("test image", part1Part3Part2.GetBodyAsText()); // Check this message is not in the text versions Assert.IsFalse(textVersions.Contains(part1Part3Part2)); // Check this message is included in the attachments Assert.Contains(part1Part3Part2, attachments); } } // We are now going one level deeper into the message tree { MessagePart part1Part4 = part1.MessageParts[3]; Assert.NotNull(part1Part4); Assert.IsFalse(part1Part4.IsMultiPart); Assert.NotNull(part1Part4.Body); Assert.AreEqual("text/enriched", part1Part4.ContentType.MediaType); Assert.AreEqual("This is <bold><italic>enriched.</italic></bold>\r\n" + "<smaller>as defined in RFC 1896</smaller>\r\n" + "\r\n" + "Isn\'t it\r\n" + "<bigger><bigger>cool?</bigger></bigger>", part1Part4.GetBodyAsText()); // Check this message is in the text versions Assert.Contains(part1Part4, textVersions); // Check this message is not included in the attachments Assert.IsFalse(attachments.Contains(part1Part4)); } // We are now going one level deeper into the message tree { MessagePart part1Part5 = part1.MessageParts[4]; Assert.NotNull(part1Part5); Assert.IsFalse(part1Part5.IsMultiPart); Assert.NotNull(part1Part5.Body); Assert.AreEqual("message/rfc822", part1Part5.ContentType.MediaType); Assert.AreEqual("From: Test <*****@*****.**>\r\n" + "To: Test <*****@*****.**>\r\n" + "Subject: Test subject\r\n" + "Content-Type: Text/plain; charset=ISO-8859-1\r\n" + "Content-Transfer-Encoding: Quoted-printable\r\n" + "\r\n" + "... Additional text in ISO-8859-1 goes here ... 3 + 5 =3D 8", part1Part5.GetBodyAsText()); // Check this message is in the text versions Assert.Contains(part1Part5, textVersions); // Check this message is not included in the attachments Assert.IsFalse(attachments.Contains(part1Part5)); // This last part is actually a message. Lets try to parse it OPMessage lastMessage = new OPMessage(part1Part5.Body); // From Assert.AreEqual("Test", lastMessage.Headers.From.DisplayName); Assert.AreEqual("*****@*****.**", lastMessage.Headers.From.Address); // To Assert.NotNull(lastMessage.Headers.To); Assert.AreEqual(1, lastMessage.Headers.To.Count); Assert.AreEqual("Test", lastMessage.Headers.To[0].DisplayName); Assert.AreEqual("*****@*****.**", lastMessage.Headers.To[0].Address); // Subject Assert.AreEqual("Test subject", lastMessage.Headers.Subject); // We are now going one level deeper into the message tree { MessagePart lastPart = lastMessage.MessagePart; Assert.IsFalse(lastPart.IsMultiPart); Assert.IsNull(lastPart.MessageParts); Assert.NotNull(lastPart.Body); Assert.AreEqual(ContentTransferEncoding.QuotedPrintable, lastPart.ContentTransferEncoding); Assert.AreEqual("Text/plain", lastPart.ContentType.MediaType); Assert.AreEqual("ISO-8859-1", lastPart.ContentType.CharSet); // Notice that =3D has been decoded to = because it was QuotedPrintable encoded Assert.AreEqual("... Additional text in ISO-8859-1 goes here ... 3 + 5 = 8", lastPart.GetBodyAsText()); } } } }
public void TestContentTypeWithLargeCharactersCanStillBeFound() { const string messagePartContent = "Content-Type: TEXT/PLAIN\r\n" + "\r\n" + // End of message headers "foo"; OPMessage message = new OPMessage(Encoding.ASCII.GetBytes(messagePartContent)); // Cna be found MessagePart textHtml = message.FindFirstPlainTextVersion(); Assert.NotNull(textHtml); Assert.AreEqual("foo", textHtml.GetBodyAsText()); // Can still be found System.Collections.Generic.List<MessagePart> messageParts = message.FindAllTextVersions(); Assert.IsNotEmpty(messageParts); Assert.AreEqual(1, messageParts.Count); Assert.AreEqual(textHtml, messageParts[0]); }