From db3fa78f28a39d09ef435c1904b09ff5c5d7ad7d Mon Sep 17 00:00:00 2001 From: Yuri Davidovsky Date: Sat, 22 Nov 2014 17:49:49 +0000 Subject: [PATCH 1/4] Made breaking of the message body into 76 char lines optional. Set breakBody to false when using StoreMessage to override default behavior. --- ImapClient.cs | 5 +++-- MailMessage.cs | 35 ++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/ImapClient.cs b/ImapClient.cs index f92baf4..23f1656 100644 --- a/ImapClient.cs +++ b/ImapClient.cs @@ -1276,6 +1276,7 @@ public IEnumerable GetMessages(IEnumerable uids, FetchOptions /// The mailbox the message will be stored in. If this parameter is /// omitted, the value of the DefaultMailbox property is used to determine the mailbox to store /// the message in. + /// Signal whether the message body should be broken into 76 char lines. /// The unique identifier (UID) of the stored message. /// The message parameter is null. /// The mail message could not be stored. The @@ -1291,10 +1292,10 @@ public IEnumerable GetMessages(IEnumerable uids, FetchOptions /// the same UID. /// /// - public uint StoreMessage(MailMessage message, bool seen = false, string mailbox = null) { + public uint StoreMessage(MailMessage message, bool seen = false, string mailbox = null, bool breakBody = true) { AssertValid(); message.ThrowIfNull("message"); - string mime822 = message.ToMIME822(); + string mime822 = message.ToMIME822(breakBody); lock (sequenceLock) { PauseIdling(); if (mailbox == null) diff --git a/MailMessage.cs b/MailMessage.cs index 004101c..fb12dd2 100644 --- a/MailMessage.cs +++ b/MailMessage.cs @@ -42,10 +42,11 @@ public static class MailMessageExtension { /// /// The MailMessage instance to construct the textual representation /// from. + /// Signal whether the message body should be broken into 76 char lines. /// An RFC822/MIME-compliant string representing the specified mail message. /// The From property is null or has not been /// properly initialized. - internal static string ToMIME822(this MailMessage message) { + internal static string ToMIME822(this MailMessage message, bool breakBody = true) { NameValueCollection header = BuildHeader(message); StringBuilder builder = new StringBuilder(); @@ -63,7 +64,7 @@ internal static string ToMIME822(this MailMessage message) { } // The mail body is separated by an empty line from the header. builder.AppendLine(); - builder.Append(BuildBody(message, header)); + builder.Append(BuildBody(message, header, breakBody)); builder.AppendLine(); return builder.ToString(); @@ -208,11 +209,13 @@ static string GenerateContentBoundary() { /// The MailMessage instance to build the mail body from. /// The RFC822/MIME mail header to use for constructing the mail /// body. + /// Toggles the breaking of the message body lines. /// An RFC822/MIME-compliant mail body as a string. /// According to RFC2822 each line of a mail message should at max be 78 characters in /// length excluding carriage return and newline characters. This method accounts for that and - /// ensures line breaks are inserted to meet this requirement. - static string BuildBody(MailMessage m, NameValueCollection header) { + /// ensures line breaks are inserted to meet this requirement. Use breakBody set to false to disable + /// line breaking in case original message formatting has to be preserved. + static string BuildBody(MailMessage m, NameValueCollection header, bool breakBody = true) { StringBuilder builder = new StringBuilder(); bool multipart = header["Content-Type"].Contains("boundary"); // Just a regular RFC822 mail w/o any MIME parts. @@ -230,7 +233,7 @@ static string BuildBody(MailMessage m, NameValueCollection header) { builder.AppendLine("--" + boundary); AddNestedMixed(builder, m); } else { - AddBody(builder, m, header, true); + AddBody(builder, m, header, true, breakBody); foreach (AlternateView v in m.AlternateViews) { builder.AppendLine("--" + boundary); AddAttachment(builder, v); @@ -254,8 +257,10 @@ static string BuildBody(MailMessage m, NameValueCollection header) { /// The RFC822/MIME mail header to use for constructing the mail body. /// Set to true to append body headers before adding the actual body /// part content. + /// Sets whether the message body should be broken up into 76 char lines. + /// Breaking up the text may badly mess up the original formating of the message body. static void AddBody(StringBuilder builder, MailMessage m, - NameValueCollection header, bool addHeaders = false) { + NameValueCollection header, bool addHeaders = false, bool breakBody = true) { bool base64 = header["Content-Transfer-Encoding"] == "base64"; if (addHeaders) { string contentType = m.IsBodyHtml ? "text/html" : "text/plain"; @@ -273,11 +278,19 @@ static void AddBody(StringBuilder builder, MailMessage m, byte[] bytes = m.BodyEncoding.GetBytes(m.Body); body = Convert.ToBase64String(bytes); } - StringReader reader = new StringReader(body); - char[] line = new char[76]; - int read; - while ((read = reader.Read(line, 0, line.Length)) > 0) - builder.AppendLine(new string(line, 0, read)); + if (breakBody) + { + StringReader reader = new StringReader(body); + char[] line = new char[76]; + int read; + while ((read = reader.Read(line, 0, line.Length)) > 0) + builder.AppendLine(new string(line, 0, read)); + } + else + { + builder.Append(body); + builder.AppendLine(); + } } /// From 504b73a2bf9035a1f92e2ecbeabb8d2eb55d7a71 Mon Sep 17 00:00:00 2001 From: Yuri Davidovsky Date: Sat, 22 Nov 2014 17:57:54 +0000 Subject: [PATCH 2/4] Added an example to show how store a message in an IMAP folder without the message body broken up in 76 char lines. --- Examples.xml | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/Examples.xml b/Examples.xml index fc5afb0..7cc27a6 100644 --- a/Examples.xml +++ b/Examples.xml @@ -370,5 +370,50 @@ + + + This example demonstrates how to store a mail message on an IMAP server without forcing + the message body to be broken into 76 char lines as per RFC2822 in order to preserve message formatting. + + ImapClient Client = new ImapClient("imap.gmail.com", 993, "My_UsernamMe", + "My_Password", true, AuthMethod.Login); + + MailMessage message = CreateSimpleMailMessage(); + uint uid = Client.StoreMessage(message, //message to store + false, //mark the message as unseen + null, //use default mailbox + false); //do not force breaking of the message body + + Console.WriteLine("The UID of the stored mail message is " + uid); + + Client.Dispose(); + + // ........... + + // This creates a simple mail message with a text/plain body and a PNG image + // as a file attachment. + // Consult the MSDN website for more details on the System.Net.Mail.Mailmessage class. + static MailMessage CreateSimpleMailMessage() { + MailMessage message = new MailMessage(); + + message.From = new MailAddress("someone@someplace.com"); + message.To.Add("john.doe@someplace.com"); + + message.Subject = "This is just a test!"; + message.Body = "This is the text/plain body. An additional HTML body " + + "can optionally be attached as an alternate view. " + + "We also need to add a few more words to the message body in order to see " + + "whether they get broken by the StoreMessage procedure."; + + // Add the attachment. + Attachment attachment = new Attachment("some_image.png", "image/png"); + attachment.Name = "my_attached_image.png"; + message.Attachments.Add(attachment); + + return message; + } + + + \ No newline at end of file From 62c7cb309aa796f78596e20f56962435a4211063 Mon Sep 17 00:00:00 2001 From: Yuri Davidovsky Date: Sat, 22 Nov 2014 18:05:48 +0000 Subject: [PATCH 3/4] Updated the ImapClient interface, StoreMessages method, as well as parameter descriptions. --- IImapClient.cs | 6 ++++-- ImapClient.cs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/IImapClient.cs b/IImapClient.cs index b8652cf..9a09a56 100644 --- a/IImapClient.cs +++ b/IImapClient.cs @@ -424,6 +424,7 @@ IEnumerable GetMessages(IEnumerable uids, FetchOptions option /// The mailbox the message will be stored in. If this parameter is /// omitted, the value of the DefaultMailbox property is used to determine the mailbox to store /// the message in. + /// Signal whether the message body should be broken into 76 char lines. /// The unique identifier (UID) of the stored message. /// The message parameter is null. /// The mail message could not be stored. The @@ -439,7 +440,7 @@ IEnumerable GetMessages(IEnumerable uids, FetchOptions option /// the same UID. /// /// - uint StoreMessage(MailMessage message, bool seen = false, string mailbox = null); + uint StoreMessage(MailMessage message, bool seen = false, string mailbox = null, bool breakBody = true); /// /// Stores the specified mail messages on the IMAP server. @@ -451,6 +452,7 @@ IEnumerable GetMessages(IEnumerable uids, FetchOptions option /// The mailbox the messages will be stored in. If this parameter is /// omitted, the value of the DefaultMailbox property is used to determine the mailbox to store /// the messages in. + /// Signal whether the message body should be broken into 76 char lines. /// An enumerable collection of unique identifiers (UID) representing the stored /// messages on the server. /// The messages parameter is null. @@ -467,7 +469,7 @@ IEnumerable GetMessages(IEnumerable uids, FetchOptions option /// the same UID. /// IEnumerable StoreMessages(IEnumerable messages, bool seen = false, - string mailbox = null); + string mailbox = null, bool breakBody = true); /// /// Copies the mail message with the specified UID to the specified destination mailbox. diff --git a/ImapClient.cs b/ImapClient.cs index 23f1656..674b018 100644 --- a/ImapClient.cs +++ b/ImapClient.cs @@ -1328,6 +1328,7 @@ public uint StoreMessage(MailMessage message, bool seen = false, string mailbox /// The mailbox the messages will be stored in. If this parameter is /// omitted, the value of the DefaultMailbox property is used to determine the mailbox to store /// the messages in. + /// Signal whether the message body should be broken into 76 char lines. /// An enumerable collection of unique identifiers (UID) representing the stored /// messages on the server. /// The messages parameter is null. @@ -1344,11 +1345,12 @@ public uint StoreMessage(MailMessage message, bool seen = false, string mailbox /// the same UID. /// public IEnumerable StoreMessages(IEnumerable messages, bool seen = false, - string mailbox = null) { + string mailbox = null, bool breakBody = true) + { messages.ThrowIfNull("messages"); List list = new List(); foreach (MailMessage m in messages) - list.Add(StoreMessage(m, seen, mailbox)); + list.Add(StoreMessage(m, seen, mailbox, breakBody)); return list; } From 31c014164d4e6aba7003a77ea3a009f2982f5bdb Mon Sep 17 00:00:00 2001 From: Yuri Davidovsky Date: Sat, 22 Nov 2014 18:19:18 +0000 Subject: [PATCH 4/4] Fixed parameters for StoreMessage examples being swapped around. --- Examples.xml | 64 ++++++++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/Examples.xml b/Examples.xml index 7cc27a6..f53a72a 100644 --- a/Examples.xml +++ b/Examples.xml @@ -335,39 +335,39 @@ This example demonstrates how to store a mail message on an IMAP server. - ImapClient Client = new ImapClient("imap.gmail.com", 993, "My_UsernamMe", - "My_Password", true, AuthMethod.Login); - - MailMessage message = CreateSimpleMailMessage(); - uint uid = Client.StoreMessage(message); - - Console.WriteLine("The UID of the stored mail message is " + uid); - - Client.Dispose(); + ImapClient Client = new ImapClient("imap.gmail.com", 993, "My_UsernamMe", + "My_Password", AuthMethod.Login, true); + + MailMessage message = CreateSimpleMailMessage(); + uint uid = Client.StoreMessage(message); + + Console.WriteLine("The UID of the stored mail message is " + uid); + + Client.Dispose(); - // ........... + // ........... - // This creates a simple mail message with a text/plain body and a PNG image - // as a file attachment. - // Consult the MSDN website for more details on the System.Net.Mail.Mailmessage class. - static MailMessage CreateSimpleMailMessage() { - MailMessage message = new MailMessage(); + // This creates a simple mail message with a text/plain body and a PNG image + // as a file attachment. + // Consult the MSDN website for more details on the System.Net.Mail.Mailmessage class. + static MailMessage CreateSimpleMailMessage() { + MailMessage message = new MailMessage(); - message.From = new MailAddress("someone@someplace.com"); - message.To.Add("john.doe@someplace.com"); + message.From = new MailAddress("someone@someplace.com"); + message.To.Add("john.doe@someplace.com"); - message.Subject = "This is just a test!"; - message.Body = "This is the text/plain body. An additional HTML body " + - "can optionally be attached as an alternate view"; + message.Subject = "This is just a test!"; + message.Body = "This is the text/plain body. An additional HTML body " + + "can optionally be attached as an alternate view"; - // Add the attachment. - Attachment attachment = new Attachment("some_image.png", "image/png"); - attachment.Name = "my_attached_image.png"; - message.Attachments.Add(attachment); + // Add the attachment. + Attachment attachment = new Attachment("some_image.png", "image/png"); + attachment.Name = "my_attached_image.png"; + message.Attachments.Add(attachment); - return message; - } - + return message; + } + @@ -376,13 +376,13 @@ the message body to be broken into 76 char lines as per RFC2822 in order to preserve message formatting. ImapClient Client = new ImapClient("imap.gmail.com", 993, "My_UsernamMe", - "My_Password", true, AuthMethod.Login); + "My_Password", AuthMethod.Login, true); MailMessage message = CreateSimpleMailMessage(); uint uid = Client.StoreMessage(message, //message to store - false, //mark the message as unseen - null, //use default mailbox - false); //do not force breaking of the message body + false, //mark the message as unseen + null, //use default mailbox + false); //do not force breaking of the message body Console.WriteLine("The UID of the stored mail message is " + uid); @@ -401,7 +401,7 @@ message.Subject = "This is just a test!"; message.Body = "This is the text/plain body. An additional HTML body " + - "can optionally be attached as an alternate view. " + + "can optionally be attached as an alternate view. " + "We also need to add a few more words to the message body in order to see " + "whether they get broken by the StoreMessage procedure.";