Я решил, что собираюсь нарисовать линию на песке с двумя ограничениями:
- Заголовки To и Cc должны быть синтаксически анализируемыми строками CSV.
- Все, что MailAddress не может проанализировать, я просто не буду об этом беспокоиться.
Я также решил, что мне просто интересны адреса электронной почты, а не отображаемое имя, поскольку отображаемое имя очень проблематично и его трудно определить, тогда как адрес электронной почты я могу подтвердить. Поэтому я использовал MailAddress для проверки моего синтаксического анализа.
Я рассматривал заголовки To и Cc как строку csv, и опять же, все, что не разбирается таким образом, я не беспокоюсь об этом.
private string GetProperlyFormattedEmailString(string emailString)
{
var emailStringParts = CSVProcessor.GetFieldsFromString(emailString);
string emailStringProcessed = "";
foreach (var part in emailStringParts)
{
try
{
var address = new MailAddress(part);
emailStringProcessed += address.Address + ",";
}
catch (Exception)
{
//wasn't an email address
throw;
}
}
return emailStringProcessed.TrimEnd((','));
}
EDIT
Дальнейшие исследования показали, что мои предположения хороши. Прочтение спецификации RFC 2822 в значительной степени показывает, что поля To, Cc и Bcc являются полями csv-parseable. Так что да, это сложно, и есть много ошибок, как при любом синтаксическом анализе CSV, но если у вас есть надежный способ анализа полей CSV (который TextFieldParser в пространстве имен Microsoft.VisualBasic.FileIO есть и есть то, что я использовал для этого), то ты золотой.
Редактировать 2
Очевидно, они не должны быть действительными CSV-строками ... цитаты действительно запутывают. Так что ваш парсер csv должен быть отказоустойчивым. Я сделал это, чтобы попытаться разобрать строку, если это не удалось, он удаляет все кавычки и пытается снова:
public static string[] GetFieldsFromString(string csvString)
{
using (var stringAsReader = new StringReader(csvString))
{
using (var textFieldParser = new TextFieldParser(stringAsReader))
{
SetUpTextFieldParser(textFieldParser, FieldType.Delimited, new[] {","}, false, true);
try
{
return textFieldParser.ReadFields();
}
catch (MalformedLineException ex1)
{
//assume it's not parseable due to double quotes, so we strip them all out and take what we have
var sanitizedString = csvString.Replace("\"", "");
using (var sanitizedStringAsReader = new StringReader(sanitizedString))
{
using (var textFieldParser2 = new TextFieldParser(sanitizedStringAsReader))
{
SetUpTextFieldParser(textFieldParser2, FieldType.Delimited, new[] {","}, false, true);
try
{
return textFieldParser2.ReadFields().Select(part => part.Trim()).ToArray();
}
catch (MalformedLineException ex2)
{
return new string[] {csvString};
}
}
}
}
}
}
}
Единственное, что он не обработает, - это учетные записи в электронном письме, т. Е. "Обезьяна в заголовке" @ stupidemailaddresses.com.
А вот и тест:
[Subject(typeof(CSVProcessor))]
public class when_processing_an_email_recipient_header
{
static string recipientHeaderToParse1 = @"""Lastname, Firstname"" <firstname_lastname@domain.com>" + "," +
@"<testto@domain.com>, testto1@domain.com, testto2@domain.com" + "," +
@"<testcc@domain.com>, test3@domain.com" + "," +
@"""""Yes, this is valid""""@[emails are hard to parse!]" + "," +
@"First, Last <name@domain.com>, name@domain.com, First Last <name@domain.com>"
;
static string[] results1;
static string[] expectedResults1;
Establish context = () =>
{
expectedResults1 = new string[]
{
@"Lastname",
@"Firstname <firstname_lastname@domain.com>",
@"<testto@domain.com>",
@"testto1@domain.com",
@"testto2@domain.com",
@"<testcc@domain.com>",
@"test3@domain.com",
@"Yes",
@"this is valid@[emails are hard to parse!]",
@"First",
@"Last <name@domain.com>",
@"name@domain.com",
@"First Last <name@domain.com>"
};
};
Because of = () =>
{
results1 = CSVProcessor.GetFieldsFromString(recipientHeaderToParse1);
};
It should_parse_the_email_parts_properly = () => results1.ShouldBeLike(expectedResults1);
}