public void TestEncodedWordLithuanian() { const string input = "=?ISO-8859-13?Q?Fwd=3A_Dvira=E8iai_vasar=E0_vagiami_da=FEniau=2C_bet_draust?="; string result = EncodedWord.Decode(input); Assert.AreEqual("Fwd: Dviračiai vasarą vagiami dažniau, bet draust", result); }
public void TestEncodedWordDanish() { const string subject = "=?iso-8859-1?Q?SV:_Ticket(13349550)_-_Sp=F8rgsm=E5l_omkring_CBB_privat?="; string result = EncodedWord.Decode(subject); Assert.AreEqual("SV: Ticket(13349550) - Spørgsmål omkring CBB privat", result); }
public void TestOnlyWhiteSpaceBetweenEncodingsAreIgnored() { const string input = "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=) (=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)"; string result = EncodedWord.Decode(input); Assert.AreEqual("(ab) (ab)", result); }
public void TestWhiteSpaceBetweenEncodingsAreIgnoredWithMultipleParts2() { const string input = "(=?UTF-8?Q?a?= =?UTF-8?Q?b?= =?UTF-8?Q?c?= =?UTF-8?Q?a?= =?UTF-8?Q?b?= =?UTF-8?Q?c?=)"; string result = EncodedWord.Decode(input); Assert.AreEqual("(abcabc)", result); }
/// <summary> /// This will decode a single value of the form: %3D%3DIamHere /// Which is basically a <see cref="EncodedWord"/> form just using % instead of = /// </summary> /// <param name="valueToDecode">The value to decode</param> /// <param name="encoding">The encoding used to decode with</param> /// <returns>The decoded value that corresponds to <paramref name="valueToDecode"/></returns> private static String DecodeSingleValueEx(String valueToDecode, String encoding) { // The encoding used is the same as QuotedPrintable, we only // need to change % to = // And otherwise make it look like the correct EncodedWord encoding valueToDecode = "=?" + encoding + "?Q?" + valueToDecode.Replace("%", "=") + "?="; return(EncodedWord.Decode(valueToDecode)); }
/// <summary> /// Parses a the value for the header Content-Type to /// a <see cref="ContentType"/> object. /// </summary> /// <param name="headerValue">The value to be parsed</param> /// <returns>A <see cref="ContentType"/> object</returns> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentType ParseContentType(string headerValue) { if (headerValue == null) { throw new ArgumentNullException("headerValue"); } // We create an empty Content-Type which we will fill in when we see the values ContentType contentType = new ContentType(); // Now decode the parameters List <KeyValuePair <string, string> > parameters = Rfc2231Decoder.Decode(headerValue); foreach (KeyValuePair <string, string> keyValuePair in parameters) { string key = keyValuePair.Key.Trim(); string value = keyValuePair.Value.Trim(); switch (key) { case "": // This is the MediaType - it has no key since it is the first one mentioned in the // headerValue and has no = in it. contentType.MediaType = value; break; case "boundary": contentType.Boundary = StringHelper.RemoveQuotesIfAny(value); break; case "charset": string toInsert = StringHelper.RemoveQuotesIfAny(value); contentType.CharSet = toInsert; break; case "name": contentType.Name = EncodedWord.Decode(StringHelper.RemoveQuotesIfAny(value)); break; default: // This is to shut up the code help that is saying that contentType.Parameters // can be null - which it cant! if (contentType.Parameters == null) { throw new Exception("The ContentType parameters property is null. This will never be thrown."); } // We add the unknown value to our parameters list // "Known" unknown values are: // - title // - report-type contentType.Parameters.Add(key, value); break; } } return(contentType); }
public void TestEncodedWordOnSubjectWithSpaces() { const string subject = "=?iso-8859-1?Q?Re: Yahoo! Mail (comment acc=E9der, restaurer, etc)?="; string result = EncodedWord.Decode(subject); Assert.AreEqual("Re: Yahoo! Mail (comment accéder, restaurer, etc)", result); }
public void TestEncodedWordOnNonEncodedString() { const string notEncodedString = "test that this is not touched ?! ?=..?= =?...?="; string result = EncodedWord.Decode(notEncodedString); Assert.AreEqual(notEncodedString, result); }
/// <summary> /// Parses an email address from a MIME header<br/> /// <br/> /// Examples of input: /// <c>Eksperten mailrobot <[email protected]></c><br/> /// <c>"Eksperten mailrobot" <[email protected]></c><br/> /// <c><[email protected]></c><br/> /// <c>[email protected]</c><br/> /// <br/> /// It might also contain encoded text, which will then be decoded. /// </summary> /// <param name="input">The value to parse out and email and/or a username</param> /// <returns>A <see cref="RfcMailAddress"/></returns> /// <exception cref="ArgumentNullException">If <paramref name="input"/> is <see langword="null"/></exception> /// <remarks> /// <see href="http://tools.ietf.org/html/rfc5322#section-3.4">RFC 5322 section 3.4</see> for more details on email syntax.<br/> /// <see cref="EncodedWord.Decode">For more information about encoded text</see>. /// </remarks> internal static RfcMailAddress ParseMailAddress(string input) { if (input == null) { throw new ArgumentNullException("input"); } // Decode the value, if it was encoded input = EncodedWord.Decode(input.Trim()); // Find the location of the email address var indexStartEmail = input.LastIndexOf('<'); var indexEndEmail = input.LastIndexOf('>'); try { if (indexStartEmail >= 0 && indexEndEmail >= 0) { // Check if there is a username in front of the email address var username = indexStartEmail > 0 ? input.Substring(0, indexStartEmail).Trim() : string.Empty; // Parse out the email address without the "<" and ">" indexStartEmail = indexStartEmail + 1; var emailLength = indexEndEmail - indexStartEmail; var emailAddress = input.Substring(indexStartEmail, emailLength).Trim(); // There has been cases where there was no emailaddress between the < and > if (!string.IsNullOrEmpty(emailAddress)) { // If the username is quoted, MailAddress' constructor will remove them for us return(new RfcMailAddress(new MailAddress(emailAddress, username), input)); } } // This might be on the form [email protected] // Check if there is an email, if notm there is no need to try if (input.Contains("@")) { return(new RfcMailAddress(new MailAddress(input), input)); } } catch (FormatException) { // Sometimes invalid emails are sent, like [email protected]. (last period is illigal) // Ignore the error } // It could be that the format used was simply a name // which is indeed valid according to the RFC // Example: // Eksperten mailrobot return(new RfcMailAddress(input)); }
private void CreateEncodeWord() { EncodedWord = Word; List <char> goodLetters = GoodGuesses.Select(g => g.Letter).ToList(); foreach (char c in Word.Distinct()) { if (!goodLetters.Contains(c)) { EncodedWord = EncodedWord.Replace(c, '_'); } } }
/// <summary> /// This will decode a single value of the form: %3D%3DIamHere /// Which is basically a <see cref="EncodedWord"/> form just using % instead of = /// </summary> /// <param name="valueToDecode">The value to decode</param> /// <param name="encoding">The encoding used to decode with</param> /// <returns>The decoded value that corresponds to <paramref name="valueToDecode"/></returns> /// <exception cref="ArgumentNullException">If <paramref name="valueToDecode"/> is <see langword="null"/></exception> /// <exception cref="ArgumentNullException">If <paramref name="encoding"/> is <see langword="null"/></exception> private static string DecodeSingleValue(string valueToDecode, string encoding) { if (valueToDecode == null) { throw new ArgumentNullException("valueToDecode"); } if (encoding == null) { throw new ArgumentNullException("encoding"); } // The encoding used is the same as QuotedPrintable, we only // need to change % to = // And otherwise make it look like the correct EncodedWord encoding valueToDecode = "=?" + encoding + "?Q?" + valueToDecode.Replace("%", "=") + "?="; return(EncodedWord.Decode(valueToDecode)); }
/// <summary> /// Parses a single header and sets member variables according to it. /// </summary> /// <param name="headerName">The name of the header</param> /// <param name="headerValue">The value of the header in unfolded state (only one line)</param> /// <exception cref="ArgumentNullException">If <paramref name="headerName"/> or <paramref name="headerValue"/> is <see langword="null"/></exception> private void ParseHeader(string headerName, string headerValue) { if (headerName == null) { throw new ArgumentNullException("headerName"); } if (headerValue == null) { throw new ArgumentNullException("headerValue"); } switch (headerName.ToUpperInvariant()) { // See http://tools.ietf.org/html/rfc5322#section-3.6.3 case "TO": To = RfcMailAddress.ParseMailAddresses(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.3 case "CC": Cc = RfcMailAddress.ParseMailAddresses(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.3 case "BCC": Bcc = RfcMailAddress.ParseMailAddresses(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.2 case "FROM": // There is only one MailAddress in the from field From = RfcMailAddress.ParseMailAddress(headerValue); break; // http://tools.ietf.org/html/rfc5322#section-3.6.2 // The implementation here might be wrong case "REPLY-TO": // This field may actually be a list of addresses, but no // such case has been encountered ReplyTo = RfcMailAddress.ParseMailAddress(headerValue); break; // http://tools.ietf.org/html/rfc5322#section-3.6.2 case "SENDER": Sender = RfcMailAddress.ParseMailAddress(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.5 // RFC 5322: // The "Keywords:" field contains a comma-separated list of one or more // words or quoted-strings. // The field are intended to have only human-readable content // with information about the message case "KEYWORDS": string[] keywordsTemp = headerValue.Split(','); foreach (string keyword in keywordsTemp) { // Remove the quotes if there is any Keywords.Add(StringUtility.RemoveQuotesIfAny(keyword.Trim())); } break; // See http://tools.ietf.org/html/rfc5322#section-3.6.7 case "RECEIVED": // Simply add the value to the list Received.Add(new Received(headerValue.Trim())); break; case "IMPORTANCE": Importance = HeaderFieldParser.ParseImportance(headerValue.Trim()); break; // See http://tools.ietf.org/html/rfc3798#section-2.1 case "DISPOSITION-NOTIFICATION-TO": DispositionNotificationTo = RfcMailAddress.ParseMailAddresses(headerValue); break; case "MIME-VERSION": MimeVersion = headerValue.Trim(); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.5 case "SUBJECT": Subject = EncodedWord.Decode(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.7 case "RETURN-PATH": // Return-paths does not include a username, but we // may still use the address parser ReturnPath = RfcMailAddress.ParseMailAddress(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.4 // Example Message-ID // <*****@*****.**> case "MESSAGE-ID": MessageId = HeaderFieldParser.ParseId(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.4 case "IN-REPLY-TO": InReplyTo = HeaderFieldParser.ParseMultipleIDs(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.4 case "REFERENCES": References = HeaderFieldParser.ParseMultipleIDs(headerValue); break; // See http://tools.ietf.org/html/rfc5322#section-3.6.1)) case "DATE": Date = headerValue.Trim(); DateSent = Rfc2822DateTime.StringToDate(headerValue); break; // See http://tools.ietf.org/html/rfc2045#section-6 // See ContentTransferEncoding class for more details case "CONTENT-TRANSFER-ENCODING": ContentTransferEncoding = HeaderFieldParser.ParseContentTransferEncoding(headerValue.Trim()); break; // See http://tools.ietf.org/html/rfc2045#section-8 case "CONTENT-DESCRIPTION": // Human description of for example a file. Can be encoded ContentDescription = EncodedWord.Decode(headerValue.Trim()); break; // See http://tools.ietf.org/html/rfc2045#section-5.1 // Example: Content-type: text/plain; charset="us-ascii" case "CONTENT-TYPE": ContentType = HeaderFieldParser.ParseContentType(headerValue); break; // See http://tools.ietf.org/html/rfc2183 case "CONTENT-DISPOSITION": ContentDisposition = HeaderFieldParser.ParseContentDisposition(headerValue); break; // See http://tools.ietf.org/html/rfc2045#section-7 // Example: <foo4*[email protected]> case "CONTENT-ID": ContentId = HeaderFieldParser.ParseId(headerValue); break; default: // This is an unknown header // Custom headers are allowed. That means headers // that are not mentionen in the RFC. // Such headers start with the letter "X" // We do not have any special parsing of such // Add it to unknown headers UnknownHeaders.Add(headerName, headerValue); break; } }
/// <summary> /// Parses a the value for the header Content-Disposition to a <see cref="ContentDisposition"/> object. /// </summary> /// <param name="headerValue">The value to be parsed</param> /// <returns>A <see cref="ContentDisposition"/> object</returns> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentDisposition ParseContentDisposition(string headerValue) { if (headerValue == null) { throw new ArgumentNullException(nameof(headerValue)); } // See http://www.ietf.org/rfc/rfc2183.txt for RFC definition // Create empty ContentDisposition - we will fill in details as we read them var contentDisposition = new ContentDisposition(); // Now decode the parameters var parameters = Rfc2231Decoder.Decode(headerValue); foreach (var keyValuePair in parameters) { var key = keyValuePair.Key.ToUpperInvariant().Trim(); var value = Utility.RemoveQuotesIfAny(keyValuePair.Value.Trim()); switch (key) { case "": // This is the DispisitionType - it has no key since it is the first one // and has no = in it. contentDisposition.DispositionType = value; break; // The correct name of the parameter is filename, but some emails also contains the parameter // name, which also holds the name of the file. Therefore we use both names for the same field. case "NAME": case "FILENAME": // The filename might be in qoutes, and it might be encoded-word encoded contentDisposition.FileName = EncodedWord.Decode(value); break; case "CREATION-DATE": // Notice that we need to create a new DateTime because of a failure in .NET 2.0. // The failure is: you cannot give contentDisposition a DateTime with a Kind of UTC // It will set the CreationDate correctly, but when trying to read it out it will throw an exception. // It is the same with ModificationDate and ReadDate. // This is fixed in 4.0 - maybe in 3.0 too. // Therefore we create a new DateTime which have a DateTimeKind set to unspecified var creationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.CreationDate = creationDate; break; case "MODIFICATION-DATE": case "MODIFICATION-DATE-PARM": var midificationDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.ModificationDate = midificationDate; break; case "READ-DATE": var readDate = new DateTime(Rfc2822DateTime.StringToDate(value).Ticks); contentDisposition.ReadDate = readDate; break; case "SIZE": contentDisposition.Size = SizeParser.Parse(value); break; case "CHARSET": // ignoring invalid parameter in Content-Disposition case "VOICE": break; default: if (!key.StartsWith("X-")) { throw new ArgumentException( "Unknown parameter in Content-Disposition. Ask developer to fix! Parameter: " + key); } contentDisposition.Parameters.Add(key, value); break; } } return(contentDisposition); }
/// <summary> /// Parses a the value for the header Content-Type to /// a <see cref="ContentType"/> object. /// </summary> /// <param name="headerValue">The value to be parsed</param> /// <returns>A <see cref="ContentType"/> object</returns> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentType ParseContentType(string headerValue) { if (headerValue == null) { throw new ArgumentNullException(nameof(headerValue)); } // We create an empty Content-Type which we will fill in when we see the values var contentType = new ContentType(); // Now decode the parameters var parameters = Rfc2231Decoder.Decode(headerValue); foreach (var keyValuePair in parameters) { var key = keyValuePair.Key.ToUpperInvariant().Trim(); var value = Utility.RemoveQuotesIfAny(keyValuePair.Value.Trim()); switch (key) { case "": // This is the MediaType - it has no key since it is the first one mentioned in the // headerValue and has no = in it. // Check for illegal content-type var v = value.ToUpperInvariant().Trim('\0'); if (v.Equals("TEXT") || v.Equals("TEXT/")) { value = "text/plain"; } contentType.MediaType = value; break; case "BOUNDARY": contentType.Boundary = value; break; case "CHARSET": contentType.CharSet = value; break; case "NAME": contentType.Name = EncodedWord.Decode(value); break; default: // This is to shut up the code help that is saying that contentType.Parameters // can be null - which it cant! if (contentType.Parameters == null) { throw new Exception("The ContentType parameters property is null. This will never be thrown."); } // We add the unknown value to our parameters list // "Known" unknown values are: // - title // - report-type contentType.Parameters.Add(key, value); break; } } return(contentType); }
/// <summary> /// Parses a the value for the header Content-Type to /// a <see cref="ContentType"/> object. /// </summary> /// <param name="headerValue">The value to be parsed</param> /// <returns>A <see cref="ContentType"/> object</returns> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentType ParseContentType(string headerValue) { if (headerValue == null) { throw new ArgumentNullException("headerValue"); } // We create an empty Content-Type which we will fill in when we see the values ContentType contentType = new ContentType(); // Now decode the parameters List <KeyValuePair <string, string> > parameters = Rfc2231Decoder.Decode(headerValue); bool setMediaType = false; foreach (KeyValuePair <string, string> keyValuePair in parameters) { string key = keyValuePair.Key.ToUpperInvariant().Trim(); string value = keyValuePair.Value.Trim().RemoveQuotesIfAny(); switch (key) { case "": // This is the MediaType - it has no key since it is the first one mentioned in the // headerValue and has no = in it. if (!setMediaType) { // Check for illegal content-type string v = value.ToUpperInvariant(); if (v.Equals("TEXT") || v.Equals("TEXT/")) { value = "text/plain"; } contentType.MediaType = cleanMediaType(value); //Have now set the media type, ignore any later entries without a key (see #21) setMediaType = true; } else { //DefaultLogger.Log.LogDebug("Multiple values without a key in the Content Type header. Only the first will get used as the media type"); } break; case "BOUNDARY": contentType.Boundary = value; break; case "CHARSET": contentType.CharSet = value; break; case "NAME": contentType.Name = EncodedWord.Decode(value); break; default: // This is to shut up the code help that is saying that contentType.Parameters // can be null - which it cant! if (contentType.Parameters == null) { throw new Exception( "The ContentType parameters property is null. This will never be thrown."); } // We add the unknown value to our parameters list // "Known" unknown values are: // - title // - report-type contentType.Parameters.Add(key, value); break; } } return(contentType); }
/// <summary> /// Parses a the value for the header Content-Disposition to a <see cref="ContentDisposition"/> object. /// </summary> /// <param name="headerValue">The value to be parsed</param> /// <returns>A <see cref="ContentDisposition"/> object</returns> /// <exception cref="ArgumentNullException">If <paramref name="headerValue"/> is <see langword="null"/></exception> public static ContentDisposition ParseContentDisposition(string headerValue) { if (headerValue == null) { throw new ArgumentNullException("headerValue"); } // See http://www.ietf.org/rfc/rfc2183.txt for RFC definition // Create empty ContentDisposition - we will fill in details as we read them ContentDisposition contentDisposition = new ContentDisposition(); // Now decode the parameters List <KeyValuePair <string, string> > parameters = Rfc2231Decoder.Decode(headerValue); foreach (KeyValuePair <string, string> keyValuePair in parameters) { string key = keyValuePair.Key.Trim(); string value = keyValuePair.Value; switch (key) { case "": // This is the DispisitionType - it has no key since it is the first one // and has no = in it. contentDisposition.DispositionType = value; break; case "filename": // The filename might be in qoutes, and it might be encoded-word encoded contentDisposition.FileName = EncodedWord.Decode(StringHelper.RemoveQuotesIfAny(value)); break; case "creation-date": // Notice that we need to create a new DateTime because of a failure in .NET 2.0. // The failure is: you cannot give contentDisposition a DateTime with a Kind of UTC // It will set the CreationDate correctly, but when trying to read it out it will throw an exception. // It is the same with ModificationDate and ReadDate. // This is fixed in 4.0 - maybe in 3.0 too. // Therefore we create a new DateTime which have a DateTimeKind set to unspecified DateTime creationDate = new DateTime(Rfc2822DateTime.StringToDate(value.Replace("\"", "")).Ticks); contentDisposition.CreationDate = creationDate; break; case "modification-date": DateTime midificationDate = new DateTime(Rfc2822DateTime.StringToDate(value.Replace("\"", "")).Ticks); contentDisposition.ModificationDate = midificationDate; break; case "read-date": DateTime readDate = new DateTime(Rfc2822DateTime.StringToDate(value.Replace("\"", "")).Ticks); contentDisposition.ReadDate = readDate; break; case "size": contentDisposition.Size = int.Parse(value, CultureInfo.InvariantCulture); break; default: throw new ArgumentException("Unknown parameter in Content-Disposition. Ask developer to fix!"); } } return(contentDisposition); }
/// <summary> /// Parses an email address from a MIME header<br/> /// <br/> /// Examples of input: /// <c>Eksperten mailrobot <[email protected]></c><br/> /// <c>"Eksperten mailrobot" <[email protected]></c><br/> /// <c><[email protected]></c><br/> /// <c>[email protected]</c><br/> /// <br/> /// It might also contain encoded text, which will then be decoded. /// </summary> /// <param name="input">The value to parse out and email and/or a username</param> /// <returns>A <see cref="MailAddress"/></returns> /// <exception cref="ArgumentNullException">If <paramref name="input"/> is <see langword="null"/></exception> /// <remarks> /// <see href="http://tools.ietf.org/html/rfc5322#section-3.4">RFC 5322 section 3.4</see> for more details on email syntax.<br/> /// <see cref="EncodedWord.Decode">For more information about encoded text</see>. /// </remarks> internal static MailAddress ParseMailAddress(string input) { if (input == null) { throw new ArgumentNullException("input"); } // Decode the value, if it was encoded input = EncodedWord.Decode(input.Trim()); // Find the location of the email address int indexStartEmail = input.LastIndexOf('<'); int indexEndEmail = input.LastIndexOf('>'); int indexAtEmail = input.LastIndexOf('@'); //Display Name string displayName = "", address = ""; //Find it if (indexStartEmail == -1 || indexEndEmail == -1) { if (indexAtEmail != -1) { displayName = input.Substring(0, indexAtEmail); address = input; } } else { // Check if there is a username in front of the email address if (indexStartEmail > 0) { // Parse out the user displayName = input.Substring(0, indexStartEmail).Trim(); displayName = displayName.Trim('"'); } else { // There was no user displayName = string.Empty; } // Parse out the email address without the "<" and ">" indexStartEmail = indexStartEmail + 1; int emailLength = indexEndEmail - indexStartEmail; address = input.Substring(indexStartEmail, emailLength).Trim(); } //Regex mailRegex = new Regex(@"^\w+@\w+(\.\w+)+(\,\w+@\w+(\.\w+)+)*$"); //严格验证 //mailRegex.IsMatch(address) //宽松验证 if (!address.Contains("@")) { throw new FormatException(string.Format("无效的 Mail 地址格式:{0}", address)); } MailAddress mailAddress = new MailAddress(displayName, address); // It could be that the format used was simply a name // which is indeed valid according to the RFC // Example: // Eksperten mailrobot return(mailAddress); }
/// <summary> /// Parses an email address from a MIME header<br/> /// <br/> /// Examples of input: /// <c>Eksperten mailrobot <[email protected]></c><br/> /// <c>"Eksperten mailrobot" <[email protected]></c><br/> /// <c><[email protected]></c><br/> /// <c>[email protected]</c><br/> /// <br/> /// It might also contain encoded text, which will then be decoded. /// </summary> /// <param name="input">The value to parse out and email and/or a username</param> /// <returns>A <see cref="RfcMailAddress"/></returns> /// <exception cref="ArgumentNullException">If <paramref name="input"/> is <see langword="null"/></exception> /// <remarks> /// <see href="http://tools.ietf.org/html/rfc5322#section-3.4">RFC 5322 section 3.4</see> for more details on email syntax.<br/> /// <see cref="EncodedWord.Decode">For more information about encoded text</see>. /// </remarks> internal static RfcMailAddress ParseMailAddress(string input) { if (input == null) { throw new ArgumentNullException("input"); } // Decode the value, if it was encoded input = EncodedWord.Decode(input.Trim()); //Remove any redundant sets of angle brackets around the email address int lastOpenAngleBracketIdx = input.LastIndexOf('<'); int lastCloseAngleBracketIdx = input.LastIndexOf('>'); //Find the index of the first angle bracket in this series of angle brackets, e.g "a>b" <<*****@*****.**>> wouldn't find the angle bracket in the display name int firstOpenAngleBracketIdx = lastOpenAngleBracketIdx; int firstCloseAngleBracketIdx = lastCloseAngleBracketIdx; while (firstOpenAngleBracketIdx > 0 && //There is a character before the last open angle bracket input[firstOpenAngleBracketIdx - 1] == '<' && //The character before the last open angle bracket is another open angle bracket input[firstCloseAngleBracketIdx - 1] == '>') //The character before the last close angle bracket is another close angle bracket { //Update the first angle bracket indices firstOpenAngleBracketIdx--; firstCloseAngleBracketIdx--; } //If the email address in the input string is enclosed in multiple angle brackets if (firstOpenAngleBracketIdx != lastOpenAngleBracketIdx) { //Remove the multiple angle brackets surrounding the email address from the input string leaving just a single set input = input.Substring(0, firstOpenAngleBracketIdx) + //Part before any angle brackets (display name if there is one) input.Substring(lastOpenAngleBracketIdx, firstCloseAngleBracketIdx - lastOpenAngleBracketIdx + 1); //actual email address, including one angle bracket either side } // Find the location of the email address int indexStartEmail = input.LastIndexOf('<'); int indexEndEmail = input.LastIndexOf('>'); try { if (indexStartEmail >= 0 && indexEndEmail >= 0) { string username; // Check if there is a username in front of the email address if (indexStartEmail > 0) { // Parse out the user username = input.Substring(0, indexStartEmail).Trim(); } else { // There was no user username = string.Empty; } // Parse out the email address without the "<" and ">" indexStartEmail = indexStartEmail + 1; int emailLength = indexEndEmail - indexStartEmail; string emailAddress = input.Substring(indexStartEmail, emailLength).Trim(); // There has been cases where there was no emailaddress between the < and > if (!string.IsNullOrEmpty(emailAddress)) { // If the username is quoted, MailAddress' constructor will remove them for us return(new RfcMailAddress(new MailAddress(emailAddress, username), input)); } } // This might be on the form [email protected] // Check if there is an email, if notm there is no need to try if (input.Contains("@")) { return(new RfcMailAddress(new MailAddress(input), input)); } } catch (FormatException) { // Sometimes invalid emails are sent, like [email protected]. (last period is illigal) //DefaultLogger.Log.LogError("RfcMailAddress: Improper mail address: \"" + input + "\""); } // It could be that the format used was simply a name // which is indeed valid according to the RFC // Example: // Eksperten mailrobot return(new RfcMailAddress(input)); }