При интеграции почтовых сервисов с платформой 1С:Предприятие разработчики часто сталкиваются с задачей регулярной обработки входящей корреспонденции: необходимо выбрать только новые сообщения, обработать их содержимое, сохранить прикрепленные файлы и отметить письма как прочитанные. Однако стандартный отбор по признаку новых писем может возвращать пустой результат, даже если во входящем ящике присутствуют непрочитанные сообщения. Разберем причины такого поведения и пошагово построим надежный механизм загрузки почты.
Проанализируем специфику протокола IMAP и работу объекта платформы ИнтернетПочта. В структуре ПараметрыОтбораIMAP разработчики часто пытаются применить следующий отбор:
ПараметрыОтбораIMAP = Новый Структура;
ПараметрыОтбораIMAP.Вставить("New", Истина);
Заголовки = ИнтернетПочта.ПолучитьЗаголовки(ПараметрыОтбораIMAP);
Выясним причину, по которой этот код возвращает 0 сообщений. В спецификации IMAP флаг New (соответствующий системному флагу \Recent) означает, что письмо поступило в почтовый ящик с момента последнего подключения любого клиента к папке. Как только почтовый сервер фиксирует подключение (например, вход через веб-интерфейс, почтовый клиент на смартфоне или предварительный опрос самой 1С), сервер сразу же снимает признак \Recent. При этом письмо остается непрочитанным, но уже перестает быть «новым» для протокола IMAP.
Большинство почтовых сервисов (Яндекс, Mail.ru, Gmail) не сохраняют статус \Recent между сессиями. Поэтому для корректной выборки всей неразобранной почты необходимо использовать отбор по признаку прочтения Seen (или Прочитанные), устанавливая его в значение Ложь.
Разберем по шагам создание надежного алгоритма подключения к почтовому серверу, получения непрочитанных сообщений, их обработки и автоматической пометки прочитанными.
ИнтернетПочтовыйПрофиль, заполняем параметры авторизации, адреса серверов и порты. Для протокола IMAP с шифрованием SSL стандартно используется порт 993, а для SMTP с SSL — порт 465.ИнтернетПочта и вызываем метод Подключиться() с передачей профиля и протокола ПротоколИнтернетПочты.IMAP.ПараметрыОтбораIMAP.Вставить("Seen", Ложь) и передаем её в метод ПолучитьЗаголовки().Выбрать(), передавая третьим параметром значение Истина, чтобы письма на сервере автоматически пометились как прочитанные.Письмо.Вложения, проверяем расширения файлов и сохраняем данные на диск с помощью метода Записать() объекта ДвоичныеДанные.Отключиться() в блоке завершения работы.Посмотрим на пример законченной процедуры для загрузки непрочитанных сообщений и выгрузки файлов вложений на диск:
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераIMAP = IMAPСервер;
Профиль.ПользовательIMAP = Пользователь;
Профиль.ПарольIMAP = Пароль;
Профиль.ПортIMAP = 993;
Профиль.ИспользоватьSSLIMAP = Истина;
ИнтернетПочта = Новый ИнтернетПочта;
Попытка
ИнтернетПочта.Подключиться(Профиль, ПротоколИнтернетПочты.IMAP);
Исключение
Сообщить("Ошибка подключения к почтовому серверу: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
ПараметрыОтбораIMAP = Новый Структура;
ПараметрыОтбораIMAP.Вставить("Seen", Ложь);
Заголовки = ИнтернетПочта.ПолучитьЗаголовки(ПараметрыОтбораIMAP);
Если Заголовки.Количество() > 0 Тогда
// Третий параметр ОтмечатьКакПрочтенные = Истина устанавливает флаг Seen на сервере
МассивСообщений = ИнтернетПочта.Выбрать(, Заголовки, Истина);
Для Каждого Письмо Из МассивСообщений Цикл
Для Каждого Вложение Из Письмо.Вложения Цикл
Попытка
ИмяФайла = Вложение.ИмяФайла;
ПолныйПуть = ПутьСохранения + ИмяФайла;
// Сохраняем двоичные данные вложения
Вложение.Данные.Записать(ПолныйПуть);
Сообщить("Файл успешно сохранен: " + ИмяФайла);
Исключение
Сообщить("Ошибка при сохранении файла " + Вложение.ИмяФайла + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЦикла;
КонецЦикла;
КонецЕсли;
ИнтернетПочта.Отключиться();
Рассмотрим подробнее тонкости, на которые следует обратить внимание при промышленной эксплуатации почтовых обработок:
Истина в метод Выбрать(, Заголовки, Истина), платформа пометит письма прочитанными сразу при скачивании. Если в процессе сохранения файлов на диск возникнет ошибка (например, переполнение диска или блокировка доступа), письмо останется прочитанным на сервере и при следующем цикле уже не будет обработано. В критически важных сценариях надежнее скачивать письма без автоматической пометки, а статус прочтения изменять отдельно только после успешной обработки каждого файла.Прав(ИмяФайла, 3), так как она не учитывает регистр (.PDF vs .pdf) и четырехсимвольные расширения (.xlsx, .docx). Рекомендуется приводить строку к нижнему регистру с помощью функции НРег() и выделять расширение корректным поиском точки.ПутьСохранения гарантированно оканчивалась символом разделителя пути, а имена вложений не содержали недопустимых файловой системой символов.