Итак, ситуация: на предприятии активно используются уведомления e-mail. Конфигурация УТ11, учетная запись 1С подключена к SMTP, письма отправляются регламентным заданием. Если в каком-то из писем указан неверный по формату адрес получателя (например, скопированный из Word и заканчивающийся «переводом строки») — SMTP возвращает ошибку, но 1С её обрабатывать на стадии отправки не умеет (ИнтернетПочта.Послать()). Соответсвенно в журнале регистрации ничего не зафиксировано, регламентное задание успешно работает, но письма перестают отправляться.
Проблема проверки адреса конечно не нова, но обычно предлагается решения с проверкой адреса через регулярные выражения, используя VBScript (RegExp) или Java. Но погрузившись немного в тему, я пришел к выводу что более правильный способ предлагается в http://www.lexpr.ru/node/382.
В кратце — алгоритм проверяет адрес на соответствие RFC 1035 “Domain Implementation and Specification”, RFC 2234 “ABNF for Syntax Specifications”, RFC 2821 “Simple Mail Transfer Protocol”, RFC 2822 “Internet Message Format”. Правда, выяснилось что «жизнь шире наших схем» и домен 1C, например, им не соответсвует 🙂
Ну и собственно реализовал некий неполный аналог (алгоритма предложенного автором статьи по ссылке) в виде функции в общем модуле в 1С.
Применительно к УТ11 данная проверка дополнительно к штатным исользуется перед записью контактной информации в
УправлениеКонтактнойИнформацией.ЗаполнитьРеквизитыТабличнойЧастиДляАдресаЭлектроннойПочты()
и перед отправкой письма в функции
ЭлектроннаяПочта.ОтправитьСообщение()
при формировании адреса получателя. После работы типового кода каждый идентифицированный адрес проверяется указанной функцией и удаляется если не проходит проверку; если в результате не остается ни одного получателя — вызывается исключение.
Соответсвенно происходит переход к отправке следующего письма и запись об ошибке в журнале регистрации.
Код проверочной функции:
Функция EmailValid(Адрес) Экспорт
//Адрес = «test@me@gmail.narod.am»;
ЛатинскиеБуквы = «abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ»;
Цифры = «0123456789»;
//ищем крайний справа символ @ для правильного выделения локальной и доменной части
ИндексСобаки = Найти(Адрес,«@»);
//1. строка адреса вообще не содержит разделителя
Если ИндексСобаки = 0 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
УрезаемаяСтрока = Сред(Адрес, ИндексСобаки+1);
Пока Найти(УрезаемаяСтрока,«@») > 0 Цикл
ИндексСобаки = ИндексСобаки + Найти(УрезаемаяСтрока,«@»);
УрезаемаяСтрока = Сред(УрезаемаяСтрока, ИндексСобаки+1);
КонецЦикла;
ДоменнаяЧасть = Сред(Адрес, ИндексСобаки+1);
ЛокальнаяЧасть = Лев(Адрес, ИндексСобаки—1);
//2. Проверяем длину локальной части
Если СтрДлина(ЛокальнаяЧасть) < 1 ИЛИ СтрДлина(ЛокальнаяЧасть) > 64 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
//3. Проверяем длину доменной части
Если СтрДлина(ДоменнаяЧасть) < 1 ИЛИ СтрДлина(ДоменнаяЧасть) > 255 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
//4. Проверяем что локальная части не начинается и не заканчивается на «.»
Если Лев(ЛокальнаяЧасть, 1) = «.» ИЛИ Прав(ЛокальнаяЧасть, 1) = «.» Тогда
Возврат ЛОЖЬ;
КонецЕсли;
//5. Локальная части не содержит 2 или более «.» подряд
Если Найти(ЛокальнаяЧасть, «..») > 0 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
//Проверка доменной части
//6. Доменная часть не начинается с точки
Если Лев(ДоменнаяЧасть, 1) = «.» Тогда
Возврат ЛОЖЬ;
КонецЕсли;
//7. Доменная часть не содержит 2 или более «.» подряд
Если Найти(ДоменнаяЧасть, «..») > 0 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
//8. Проверка частей доменной части
//каждая часть начинается с буквы и заканчивается буквой или цифрой
//каждая часть длиной не более 63 символов
ИдентификаторыДоменнойЧасти = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ДоменнаяЧасть, «.»);
Для Каждого ИдентификаторДомена ИЗ ИдентификаторыДоменнойЧасти Цикл
Если СтрДлина(ИдентификаторДомена) > 63 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
Если Найти(ЛатинскиеБуквы, Лев(ИдентификаторДомена,1)) = 0
//для доменов, нарушающих RFC 1035 п.2.3.1, например @1c.ru 🙂
И Найти(Цифры, Лев(ИдентификаторДомена,1)) = 0
Тогда
Возврат ЛОЖЬ;
КонецЕсли;
Если Найти(ЛатинскиеБуквы, Прав(ИдентификаторДомена,1)) = 0 И Найти(Цифры, Прав(ИдентификаторДомена,1)) = 0 Тогда
Возврат ЛОЖЬ;
КонецЕсли;
КонецЦикла;
//Все проверки пройдены — радуемся
Возврат ИСТИНА;
КонецФункции




ЛокальнаяЧасть не проверяется на Не ЛатинскиеБуквы, а вот ДоменнаяЧасть, по-моему, может содержать Не ЛатинскиеБуквы.
А скорость работы?
Чем не устроили регулярные выражения?
(2) Очевидно тем, что регулярки чуждые элементы в организме 1С Предприятия. Ну и работать в 1С они могут только в windows среде.
(3) Поручик, возражаю. Берем и пользуемся почти что родной библиотекой (отвечает в 1С за Юникод) на любой системе (виндоус или линукс).
(2) ShantinTD, насколько я понял не написано еще такого выражения которое бы корректно пропускало некоторые допустимые адреса 🙂
Адреса: Abc@def@example.com, customer/department=shipping@example.com и !def!xyz%abc@example.com с точки зрения RFC все являются правильными, но отвергнутся 90% регулярок.
Ну и действительно я о RexV8 не знал.
По поводу скорости работы — это не самое медленное место в УТ11 🙂
1. По скорости описанный механизм проигрывает в 2 раза регулярам
2. «…регулярки чуждые элементы в организме 1С Предприятия…» Наверно, такие же чуждые, как и внешние компоненты)))
Насчёт чуждых — это хорошая отмазка пользоваться кривыми медленными велосипедами, вместо чтобы сделать по-человечески, да ещё наработанные ранее паттерны использовать…
Очень ждём родной объект — «Новый РегулярноеВыражение».
(6)По поводу скорости — внутри отправки электронного письма исходящего из УТ11, даже если такая проверка в 2 раза медленнее регулярки — на время выполнения всей функции отправки влияния не зафиксировано. Если процесс длится 100 единиц, в него добавляют 2 варианта проверки — быстрый за 1 единицу и медленный за 2 — то это не критерий.
(7) по поводу наработанных паттернов — вновь про примеры корректных адресов, которые ими отвергаются Abc@def@example.com, customer/department=shipping@example.com и !def!xyz%abc@example.com
1. Интересно посмотреть на «стандарт» относительно адресов электронной почты.
2. Интересно узнать: какой процент поставщиков услуг электронной почты (назовем их так) позволяет использовать исключительно корректные адреса?
К размышлению: в HTML5 определены поля ввода в том числе с типом email. То есть не просто текст, а именно адрес электронной почты. И есть проверка на правильность (валидность). Так вот каждый браузер сам реализует поддержку стандарта HTML5, и у каждого браузера получается разный результат при проверке одного и того же адреса. Причем так: некорректный адрес некоторыми браузерами определяется как корректный, и наоборот. (Сейчас уже не вспомню конкретно по браузерам, но в 2011 году проходил обучение — тестировал во всевозможных комбинациях).
(7), действительно «очень ждем».
А говорить, что «и так сойдет, все равно медленно работает» — неправильно. Просто в некоторых масштабах позволительно (?) не замечать потерь производительности.
Лучше чуть медленнее, но родными средствами!
Так что спасибо =)
(10) SeiOkami, в «два раза» это не «чуть медленнее»…
Пример: кто-то втиснул в самописную конфу алгоритм расчета МД5. Родными средствами. То есть совсем родными — на встроенном языке. Ничего, что в 100 раз (!!! не шутка, без преувеличения) медленнее, чем внешними средствами. На 8.3 поправил, конечно, но «осадок остался»…
(7) Сомневаюсь, что будет Новый РегулярноеВыражение в программе, предназначенной для построения учетных систем. Много случаев применения упоротого парсинга текста в типовых и нетиповых конфигурациях, обработках и часто такая потребность возникает? Не зря ведь встроенные регулярки имеются только в интерпретируемых языках, ориентированных именно на обработку текста.
(12) Поручик, не знаю, не знаю. Мне часто приходится работать с текстом средствами 1с. Уж намного чаще, чем ГенераторомСлучайныхЧисел.
(4) ShantinTD, так вроде под Линукс еще нет версии компоненты. Как сказано в тексте статьи: «Основные планы на ближайшее будещее — сделать linux-версию.»
(8) 1cge, «реализовал некий неполный аналог в виде функции» — что именно не проверяется, раз неполный?
Друзья, вот я все понимаю, кроме одной вещи — ну почему нельзя почитать документацию и подумать как сделать по нормальному.
Попробуйте отталкиваться от сценария использования:
1. в системе вводится почтовый адрес
2. адрес введенный пользователем проверяется на корректность.
Таким образом возникает вопрос — какой адрес считать валидыным ? ответ — читаем стандарт
Вопрос — Каким образом максимально быстро проверять адрес ? ответ — регулярными выражениями
Вопрос — как в 1С использовать регулярные выражения ? Нативно в 1С можно использовать такие выражения с помощью библиотеки Александра Орефкова — сама библиотека уже внутри платформы.
За сим откланиваюсь — глядишь ссылки кому то помогут сделать полноценный продукт-подсистему.
(14) Неполный аналог того что предложил автор статьи из приведенной ссылки.
(15) lustin, спасибо. На один из вопросов (моих) ответил.
Вопрос про то, кто разрешает (регистрирует) невалидные адреса — остается открытым.
(12) Поручик, ничего вредного в появлении Новый РегулярноеВыражение не будет. Зато можно будет избежать «упоротых» разборов текста. В том числе — в типовых конфигурациях.
(14) V_V_V, читаем несколькими строками выше — «всегда есть в 1С, даже под linux». Есть поправка — начиная с релиза 8.2.14. Но и это решается копированием файлов в нужную папку.
(1)
+1.
Представленный алгоритм «забанит» все адреса почтового сервера 1С 🙂
(18)(1) Спасибо. Внес изменение (чтобы работал домен 1С) 🙂
(19) 1cge,
Вы не против, если мы будем использовать Ваш алгоритм в конфигурации онлайн сервиса ?
Написать свой — не вопрос, но раз уж есть готовое решение, почему бы и нет 🙂
(20)Не против
(21) 1cge,
спасибо
(12) Поручик, не чаще упоротых способов работы с xsd-схемами или ковариационного анализа. Любая строго формализованная учётная система, имеющая на постоянном неручном входе слабоформализованный поток мусора, обязана иметь средства разбора, в т.ч. регулярки. Это куда важней, чем дендрограммы или рандомайзеры.
Эта функция из подсистемы «Базовая функциональность» из БСП 2.1. Модуль ОбщегоНазначенияКлиентСервер.
Присутствует во всех конфигурациях такой подсистемой (Документооборот, БП, УПП и пр.)
(24) Эта самописная функция, источник указан.
Действительно, в БСП появилась АдресЭлектроннойПочтыСоответствуетТребованиям(); 1) не знал :); 2) она немного другая, может в чем-то правильнее, в чем-то нет, например опять требует единственного вхождения «@» и соответственно по нему выделяет локальную и доменную часть.
(25) 1cge, поспорю. Читаем по приведенным в (15) lustin ссылкам, видим официальный стандарт на формат адреса электронной почты, и даже регулярное выражение, под которое должен попадать адрес. И адрес с двумя @ под него не попадает. Так что очень сомнительно, насколько «правильный» такой адрес. Хотя не отрицаю, что может существовать (наверное, сам не проверял и не встречал).
(26).
abc@def@example.com и «Abc@def»@example.com — правильные, потому что «@» экранировано «» или внутри закавыченной строки.
Т.е. RFC такие адреса допускает, другое дело в реале маловероятно их использование, потому что почтовики не дадут создать такой адрес.
(27) 1cge, для проверки пользуюсь notepad++ и плагином RegEx Helper. Под вот то большое регулярное выражение попадает только второй адрес — с кавычками. Первый адрес — только после первой собаки начиная (def@example.com). Опять же: не утверждаю, что это истина в последней инстанции, но хотя бы есть с чем сравнить.
Для справки: в обсуждениях вышеупомянутого мной RexV8 говорится о том, что VBScript и ICU работают по разному.
(11) Мыши плакали и кололись, но продолжали жрать кактус.
(0) Учите регулярки, учите внешние компоненты. На boost внешняя компонента для работы с regex пишется за полчаса под все платформы.
(29) Спасибо за совет…
Там правда в тексте и описании было написано что проверка без использования внешних скриптов и регулярок, это так сказать одно из требований было. Так что за то и другое в курсе, не переживайте.
Плохо это или хорошо — другое дело и смотря с какой точки зрения 🙂
давным-давно писал подобное на 7.7. не думал, что кому-то ещё может быть интересно.
Показать
с пол-пинка переделывается под 8-ку
Если в доменном имени нет точки, или если в доменном имени после точки ничего не стоит — пишет, что адрес верен… Допилю, но вот.
Добавил еще:
Показать
Ошибка у вас.
Должно быть так:
тоже добавил
//++ СимволыЭлПочты = «! # $ % & ‘ * + -/ = ? #k8SjZc9Dxk _ ` { | } ~ @»; //— ……………………… ДлинаСтоки = СтрДлина(Адрес); Для Сч = 1 По ДлинаСтоки Цикл Если НЕ (Найти(ЛатинскиеБуквы,Сред(Адрес,Сч,1)) <> 0 ИЛИ Найти(Цифры,Сред(Адрес,Сч,1)) <> 0 ИЛИ Найти(СимволыЭлПочты,Сред(Адрес,Сч,1)) <> 0 ) Тогда Возврат ЛОЖЬ; КонецЕсли; КонецЦикла;Показать
У меня проходит такое «ee@eee@ee33» Ну а разве это адрес?