Example #1
0
		/// <summary>
		/// Creates a new empty instance of the MailMessage class from a string
		/// containing a raw mail message header.
		/// </summary>
		/// <param name="text">A string containing the mail header to create
		/// the MailMessage instance from.</param>
		/// <returns>A MailMessage instance with initialized Header fields but
		/// no content</returns>
		internal static IMailMessage FromHeader(string text) {
			NameValueCollection header = ParseMailHeader(text);
			IMailMessage m = new IMailMessage();
			foreach (string key in header) {
				string value = header.GetValues(key)[0];
				try {
						m.Headers.Add(key, value);
				} catch {
					// HeaderCollection throws an exception if adding an empty string as
					// value, which can happen, if reading a mail message with an empty
					// subject.
					// Also spammers often forge headers, so just fall through and ignore.
				}
			}
			Match ma = Regex.Match(header["Subject"] ?? "", @"=\?([A-Za-z0-9\-]+)");
			if (ma.Success) {
				/* encoded-word subject */
                m.SubjectEncoding = Util.GetEncoding(ma.Groups[1].Value);
                string decoded = Util.DecodeWords(header["Subject"]);

                if(!string.IsNullOrEmpty(decoded))
                    decoded = Regex.Replace(decoded, @"\r", String.Empty);

                if(!string.IsNullOrEmpty(decoded))
                decoded = Regex.Replace(decoded, @"\n", String.Empty);
                   
                m.Subject = decoded;
			} else {
				m.SubjectEncoding = Encoding.ASCII;
                string subject = header["Subject"];

                if (!string.IsNullOrEmpty(subject))
                    subject = Regex.Replace(subject, @"\r", String.Empty);

                if (!string.IsNullOrEmpty(subject))
                    subject = Regex.Replace(subject, @"\n", String.Empty);

                m.Subject = subject;
			}
			m.Priority = ParsePriority(header["Priority"]);
			SetAddressFields(m, header);
			return m;
		}
Example #2
0
		/// <summary>
		/// Sets the address fields (From, To, CC, etc.) of a MailMessage
		/// object using the specified mail message header information.
		/// </summary>
		/// <param name="m">The MailMessage instance to operate on</param>
		/// <param name="header">A collection of mail and MIME headers</param>
		private static void SetAddressFields(IMailMessage m, NameValueCollection header) {
			string[] addr;
			if (header["To"] != null) {
				addr = ParseAddressList(header["To"]);
                foreach (string s in addr)
                {
                    try
                    {
                        m.To.Add(Util.DecodeWords(s));
                    }
                    catch (Exception e)
                    {
 
                    }
                }
			}
			if (header["Cc"] != null) {
				addr = ParseAddressList(header["Cc"]);
                foreach (string s in addr)
                {
                    try
                    {
                        m.CC.Add(Util.DecodeWords(s));
                    }
                    catch { }
                }
			}
			if (header["Bcc"] != null) {
				addr = ParseAddressList(header["Bcc"]);
                foreach (string s in addr)
                {
                    try
                    {
                        m.Bcc.Add(Util.DecodeWords(s));
                    }
                    catch { }
                }
			}
			if (header["From"] != null) {
				addr = ParseAddressList(header["From"]);
                if (addr.Length > 0)
                {
                    try
                    {
                        m.From = new MailAddress(Util.DecodeWords(addr[0]));
                    }
                    catch { }
                }
			}
			if (header["Sender"] != null) {
				addr = ParseAddressList(header["Sender"]);
				if(addr.Length > 0)
                {
                    try
                    {
                        m.Sender = new MailAddress(Util.DecodeWords(addr[0]));
                    }
                    catch { }
                }
			}
			if (header["Reply-to"] != null) {
				addr = ParseAddressList(header["Reply-to"]);
                foreach (string s in addr)
                {
                    try
                    {
                        m.ReplyToList.Add(Util.DecodeWords(s));
                    }
                    catch { }
                }
			}
		}
Example #3
0
		/// <summary>
		/// Stores the specified mail messages on the IMAP server.
		/// </summary>
		/// <param name="messages">An array of mail messages to store on the server.</param>
		/// <param name="seen">Set this to true to set the \Seen flag for each message
		/// on the server.</param>
		/// <param name="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.</param>
		/// <exception cref="NotAuthenticatedException">Thrown if the method was called
		/// in a non-authenticated state, i.e. before logging into the server with
		/// valid credentials.</exception>
		/// <exception cref="BadServerResponseException">Thrown if the mail messages could
		/// not be stored. The message property of the exception contains the error message
		/// returned by the server.</exception>
		/// <returns>An array containing the unique identifiers (UID) of the stored
		/// messages.</returns>
		/// <remarks>A unique identifier (UID) is a 32-bit value assigned to each
		/// message which uniquely identifies the message within a mailbox. No two
		/// messages in a mailbox share the the same UID.</remarks>
		/// <seealso cref="StoreMessage"/>
		public List<long> StoreMessages(IMailMessage[] messages, bool seen = false,
			string mailbox = null) {
			List<long> list = new List<long>();
			foreach (IMailMessage m in messages)
				list.Add(StoreMessage(m, seen, mailbox));
			return list;
		}
Example #4
0
        /// <summary>
        /// Returns only the plain TEXT data of the messages. All HTML is stripped out. All replies stripped out according to the > google indents for replies. All forwarded areas stripped out also based on google.
        /// </summary>
        /// <param name="uids">The list of uids to get the messages text for</param>
        /// <param name="seen">If false then the \Seen flag is not set</param>
        /// <param name="mailbox">The mailbox to get the messages from</param>
        /// <returns>Returns a dictionary where the UIDs are the keys and the text data is the value</returns>
        public Dictionary<long, string> GetPreviewText(long[] uids)
        {
            if (!Authed)
                throw new NotAuthenticatedException();
            lock (sequenceLock)
            {
                if (this.selectedMailbox == null)
                    throw new InvalidOperationException("No mailbox or folder currently selected.");

                string uidRange = Util.BuildUIDRange(uids);
                Dictionary<long, string> results = new Dictionary<long, string>();
                /* Retrieve and parse the body structure of the mail message */
                Dictionary<long, string> structures = GetBodystructure(uids);
                try
                {
                    foreach (long uid in structures.Keys)
                    {
                        Bodypart[] parts = Bodystructure.Parse(structures[uid]);

                        IMailMessage message = new IMailMessage();
                        string htmlContent = "";
                        foreach (Bodypart part in parts)
                        {

                            if (part.Subtype.ToLower() == "plain")
                            {
                                string content = GetBodypart(uid, part.PartNumber, false);

                                content = Util.StripReplies(Util.DecodeWords(part, content));

                                htmlContent = Util.StripSpecialCharacters(Util.StripCSSDeclerations(Regex.Replace(System.Net.WebUtility.HtmlDecode(Regex.Replace(Util.StripTagsCharArray(content), "&nbsp;", " ")), @"\s{2,}", " "))).Trim();

                                break;
                            }
                            else if (part.Subtype.ToLower() == "html")
                            {
                                string content = GetBodypart(uid, part.PartNumber, false);

                                HtmlAgilityPack.HtmlDocument document = new HtmlDocument();
                                content = Util.DecodeWords(part, content);
                                document.LoadHtml(content);

                                if (document.DocumentNode.SelectSingleNode("//body") != null)
                                    content = document.DocumentNode.SelectSingleNode("//body").InnerText;
                                else
                                    content = document.DocumentNode.InnerText;

                                htmlContent = Util.StripSpecialCharacters(Util.StripCSSDeclerations(Regex.Replace(System.Net.WebUtility.HtmlDecode(Regex.Replace(Util.StripTagsCharArray(content), "&nbsp;", " ")), @"\s{2,}", " "))).Trim();

                                break;
                            }
                        }

                        results.Add(uid, htmlContent);
                    }
                }
                catch (FormatException)
                {
                    throw new BadServerResponseException("Server returned erroneous " +
                        "body structure.");
                }
                catch (Exception e)
                {
                    return results;
                }

                return results;
            }
        }
Example #5
0
		/// <summary>
		/// Stores the specified mail message on the IMAP server.
		/// </summary>
		/// <param name="message">The mail message to store on the server.</param>
		/// <param name="seen">Set this to true to set the \Seen flag for the message
		/// on the server.</param>
		/// <param name="mailbox">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.</param>
		/// <exception cref="NotAuthenticatedException">Thrown if the method was called
		/// in a non-authenticated state, i.e. before logging into the server with
		/// valid credentials.</exception>
		/// <exception cref="BadServerResponseException">Thrown if the mail message could
		/// not be stored. The message property of the exception contains the error message
		/// returned by the server.</exception>
		/// <returns>The unique identifier (UID) of the stored message.</returns>
		/// <remarks>A unique identifier (UID) is a 32-bit value assigned to each
		/// message which uniquely identifies the message within a mailbox. No two
		/// messages in a mailbox share the the same UID.</remarks>
		/// <seealso cref="StoreMessages"/>
		/// <include file='Examples.xml' path='S22/Imap/ImapClient[@name="StoreMessage"]/*'/>
		public long StoreMessage(IMailMessage message, bool seen = false, string mailbox = null) {
			if (!Authed)
				throw new NotAuthenticatedException();
            if (mailbox == null)
                mailbox = defaultMailbox;

			string mime822 = message.ToMIME822();
			lock (sequenceLock) {
				string tag = GetTag();
				string response = SendCommandGetResponse(tag + "APPEND " +
					mailbox.QuoteString() + (seen ? @" (\Seen)" : "") +
					" {" + mime822.Length + "}");
				/* Server is required to send a continuation response to signal
				 * we can go ahead with the actual message data */
				if (!response.StartsWith("+"))
					throw new BadServerResponseException(response);
				response = SendCommandGetResponse(mime822);
				if (!IsResponseOK(response, tag))
					throw new BadServerResponseException(response);
				return GetHighestUID();
			}
		}
Example #6
0
        /// <summary>
        /// Gets just the message HTML or TEXT of the messages
        /// </summary>
        /// <param name="uids">The list of uids to get the html for</param>
        /// <param name="seen">If false then the \Seen flag is not set</param>
        /// <param name="mailbox">The mailbox to get messages from</param>
        /// <returns>Returns a dictionary where the UIDs are the keys and the message data is the value</returns>
        public Dictionary<long, string> GetMessageHTML(long[] uids)
        {
            if (!Authed)
                throw new NotAuthenticatedException();
            lock (sequenceLock)
            {
                if (this.selectedMailbox == null)
                    throw new InvalidOperationException("No mailbox or folder currently selected.");

                Dictionary<long, string> results = new Dictionary<long, string>();
                /* Retrieve and parse the body structure of the mail message */
                Dictionary<long, string> structures = GetBodystructure(uids);
                try
                {
                    foreach (long uid in structures.Keys)
                    {
                        Bodypart[] parts = Bodystructure.Parse(structures[uid]);
                        string htmlContent = "";
                        IMailMessage message = new IMailMessage();
                        foreach (Bodypart part in parts)
                        {
                            if (part.Subtype.ToLower() == "html")
                            {
                                /* fetch the content */
                                htmlContent = GetBodypart(uid, part.PartNumber, false);
                                message.AddBodypart(part, Util.DecodeWords(part,htmlContent));
                                break;
                            }
                        }

                        if (htmlContent != string.Empty)
                        {
                            results.Add(uid, message.Body);
                            continue;
                        }

                        //Well we didn't find any html blocks so lets find just the plain text

                        foreach (Bodypart part in parts)
                        {
                            if (part.Subtype.ToLower() == "plain")
                            {
                                /* fetch the content */
                                htmlContent = GetBodypart(uid, part.PartNumber, false);
                                message.AddBodypart(part, Util.DecodeWords(part,htmlContent));
                                break;
                            }
                        }

                        results.Add(uid, message.Body);
                    }
                }
                catch (FormatException)
                {
                    throw new BadServerResponseException("Server returned erroneous " +
                        "body structure.");
                }
            
                return results;
            }
        }
Example #7
0
		/// <summary>
		/// Creates a nested multipart/alternative part which contains all entries
		/// from the AlternateViews collection of the specified MailMessage instance
		/// as well as the body part for the Body and BodyEncoding properties of the
		/// specified MailMessage instance.
		/// </summary>
		/// <param name="builder">The StringBuilder instance to append to.</param>
		/// <param name="m">The MailMessage instance whose AlternateView collection
		/// will be added to the nested multipart/alternative part.</param>
		/// <param name="header">The RFC822/MIME mail header to use for
		/// constructing the mail body.</param>
		/// <remarks>This is used if the MailMessage instance contains both alternative
		/// views and attachments. In this case the created RFC822/MIME mail message will
		/// contain nested body parts.</remarks>
		internal void AddNestedAlternative(StringBuilder builder, IMailMessage m,
			NameValueCollection header) {
			string boundary = GenerateContentBoundary();
			builder.AppendLine("Content-Type: multipart/alternative; boundary=" + boundary);
			builder.AppendLine();
			// Add the body parts to the nested multipart/alternative part
			builder.AppendLine("--" + boundary);
			AddBody(builder, m, header, true);
			foreach (AlternateView v in m.AlternateViews) {
				builder.AppendLine("--" + boundary);
				AddAttachment(builder, v);
			}
			builder.AppendLine("--" + boundary + "--");
		}
Example #8
0
		/// <summary>
		/// Adds a body part to the specified Stringbuilder object composed from
		/// the Body and BodyEncoding properties of the MailMessage class.
		/// </summary>
		/// <param name="builder">The Stringbuilder to append the body part to.</param>
		/// <param name="m">The MailMessage instance to build the body part from.</param>
		/// <param name="header">The RFC822/MIME mail header to use for
		/// constructing the mail body.</param>
		/// <param name="addHeaders">Set to true to append body headers before
		/// adding the actual body part content.</param>
		internal void AddBody(StringBuilder builder, IMailMessage m,
			NameValueCollection header, bool addHeaders = false) {
			bool base64 = header["Content-Transfer-Encoding"] == "base64";
			if (addHeaders) {
				string contentType = m.IsBodyHtml ? "text/html" : "text/plain";
				if (m.BodyEncoding != null)
					contentType = contentType + "; charset=" + m.BodyEncoding.WebName;
				builder.AppendLine("Content-Type: " + contentType);
				if (m.Body != null && !m.Body.IsASCII()) {
					builder.AppendLine("Content-Transfer-Encoding: base64");
					base64 = true;
				}
				builder.AppendLine();
			}
			string body = m.Body;
			if (base64) {
				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));
		}
Example #9
0
		/// <summary>
		/// Builds an RFC822/MIME-compliant mail body from the specified
		/// MailMessage instance and returns it as a formatted string.
		/// </summary>
		/// <param name="m">The MailMessage instance to build the mail body
		/// from.</param>
		/// <param name="header">The RFC822/MIME mail header to use for
		/// constructing the mail body.</param>
		/// <returns>An RFC822/MIME-compliant mail body as a string.
		/// </returns>
		/// <remarks>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.</remarks>
		internal string BuildBody(IMailMessage m, NameValueCollection header) {
			StringBuilder builder = new StringBuilder();
			bool multipart = header["Content-Type"].Contains("boundary");
			// Just a regular RFC822 mail w/o any MIME parts
			if (!multipart) {
				AddBody(builder, m, header);
				return builder.ToString();
			}
			Match match = Regex.Match(header["Content-Type"], @"boundary=(\w+)");
			string boundary = match.Groups[1].Value;
			// Start boundary
			builder.AppendLine("--" + boundary);
			bool nestParts = m.AlternateViews.Count > 0 && m.Attachments.Count > 0;
			if (nestParts) {
				AddNestedAlternative(builder, m, header);
				builder.AppendLine("--" + boundary);
				AddNestedMixed(builder, m);
			} else {
				AddBody(builder, m, header, true);
				foreach (AlternateView v in m.AlternateViews) {
					builder.AppendLine("--" + boundary);
					AddAttachment(builder, v);
				}
				foreach (Attachment a in m.Attachments) {
					builder.AppendLine("--" + boundary);
					AddAttachment(builder, a);
				}
			}
			// End boundary
			builder.AppendLine("--" + boundary + "--");
			return builder.ToString();
		}
Example #10
0
		/// <summary>
		/// Builds a RFC822/MIME-compliant mail header from the specified
		/// MailMessage instance and returns it as a NameValueCollection.
		/// </summary>
		/// <param name="m">The MailMessage instance to build the header
		/// from.</param>
		/// <returns>A NameValueCollection representing the RFC822/MIME
		/// mail header fields.</returns>
		internal NameValueCollection BuildHeader(IMailMessage m) {
			string[] ignore = new string[] {
				"MIME-Version", "Date", "Subject", "From", "To", "Cc", "Bcc",
				"Content-Type", "Content-Transfer-Encoding", "Priority",
				"Reply-To", "X-Priority", "Importance", "Sender", "Message-Id"
			};
			NameValueCollection header = new NameValueCollection() {
				{ "MIME-Version", "1.0" },
				{ "Date", DateTime.Now.ToString("R") },
				{ "Priority", PriorityMap[m.Priority] },
				{ "Importance", ImportanceMap[m.Priority] }
			};
			if (m.From == null)
				throw new InvalidOperationException("The From property must not be null");
			header.Add("From", m.From.To822Address());
			if (m.Subject != null)
				header.Add("Subject", m.Subject.IsASCII() ? m.Subject : QEncode(m.Subject));
			foreach (MailAddress a in m.To)
				header.Add("To", a.To822Address());
			foreach (MailAddress a in m.CC)
				header.Add("Cc", a.To822Address());
			foreach (MailAddress a in m.Bcc)
				header.Add("Bcc", a.To822Address());
			bool multipart = m.AlternateViews.Count > 0 || m.Attachments.Count > 0;
			if (!multipart) {
				string contentType = m.IsBodyHtml ? "text/html" : "text/plain";
				if (m.BodyEncoding != null)
					contentType = contentType + "; charset=" + m.BodyEncoding.WebName;
				header.Add("Content-Type", contentType);
				if (m.Body != null && !m.Body.IsASCII())
					header.Add("Content-Transfer-Encoding", "base64");
			} else {
				string contentType = (m.Attachments.Count == 0 ?
					"multipart/alternative" : "multipart/mixed") + "; boundary=" +
					GenerateContentBoundary();
				header.Add("Content-Type", contentType);
			}
			// Add any custom headers added by user
			foreach (string key in m.Headers) {
				if (ignore.Contains(key, StringComparer.OrdinalIgnoreCase))
					continue;
				header.Add(key, m.Headers.GetValues(key)[0]);
			}
			return header;
		}