Механизм "Отложенная отправка писем", при записи документа

Иногда требуется отправлять письма при записи документа. Чтобы избежать проблем с производительностью, сделал механизм «Отложенная отправка писем».

В механизме реализовано: 

  • выбор времени отправки.
  • возможность прикрепить во вложение печатную форму "Табличный документ".
  • проверка по ссылке отправляли или нет письмо по данному документу.
  • возможность оправлять письма и без привязки к документу.

1. Создаем регистр сведений

Объект — тип ДокументСсылка

Вложения — тип ХранилищеЗначения

ДатаКогдаОтправить, ДатаОтправки — тип Дата и время

Адрес,Тема,Текст,Расширение — тип Строка

2. Добавляем регламентное задание, которое будет периодически отправлять письма.

3. К регламентному заданию привязываем процедуру, которая проверяет появились письма к отправке и отправляет их.

 
Процедура ОтложеннаяОтправкаПисем() Экспорт

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПисьмаОтправленные.Адрес КАК Адрес,
| ПисьмаОтправленные.Тема КАК Тема,
| ПисьмаОтправленные.Текст КАК Текст,
| ПисьмаОтправленные.Вложения КАК Вложения,
| ЕСТЬNULL(ПисьмаОтправленные.Объект.Номер, ""file"") КАК Номер,
| ПисьмаОтправленные.Объект КАК Объект,
| ПисьмаОтправленные.ДатаКогдаОтправить КАК ДатаКогдаОтправить,
| ПисьмаОтправленные.Расширение КАК Расширение
|ИЗ
| РегистрСведений.ОтложеннаяОтправкаПисем КАК ПисьмаОтправленные
|ГДЕ
| ПисьмаОтправленные.ДатаКогдаОтправить <= &ТекущаяДата
| И ПисьмаОтправленные.ДатаОтправки = &ПустаяДата";

Запрос.УстановитьПараметр("ПустаяДата", Дата(1,1,1));
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());

РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
Отказ = Ложь;
СоответствиеВложений = Новый Соответствие;
МассивТабДок = ВыборкаДетальныеЗаписи.Вложения.Получить();
Если МассивТабДок <> Неопределено Тогда
Для Каждого ТабДокумент Из МассивТабДок Цикл
ИмяФайла = ВыборкаДетальныеЗаписи.Номер+ "." + ВыборкаДетальныеЗаписи.Расширение;
ИмяВременногоФайла = КаталогВременныхФайлов() + ИмяФайла;
Попытка
Если ВРег(ВыборкаДетальныеЗаписи.Расширение) = "XLS" Тогда
ТабДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLS);
ИначеЕсли ВРег(ВыборкаДетальныеЗаписи.Расширение) = "PDF" Тогда
ТабДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.PDF);
ИначеЕсли ВРег(ВыборкаДетальныеЗаписи.Расширение) = "XLSX" Тогда
ТабДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.XLSX);
ИначеЕсли ВРег(ВыборкаДетальныеЗаписи.Расширение) = "TXT" Тогда
ТабДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.TXT);
ИначеЕсли ВРег(ВыборкаДетальныеЗаписи.Расширение) = "ODS" Тогда
ТабДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.ODS);
ИначеЕсли ВРег(ВыборкаДетальныеЗаписи.Расширение) = "DOCX" Тогда
ТабДокумент.Записать(ИмяВременногоФайла, ТипФайлаТабличногоДокумента.DOCX);
КонецЕсли;
Исключение
ОписаниеОшибки = ОписаниеОшибки();
Отказ = Истина;
Прервать;
КонецПопытки;
СоответствиеВложений.Вставить(ИмяФайла, Новый ДвоичныеДанные(ИмяВременногоФайла));
УдалитьФайлы(ИмяВременногоФайла);
КонецЦикла;
КонецЕсли;

Если Не Отказ Тогда
Попытка
Параметры1 = Новый Структура;
Параметры1.Вставить("Кому", ВыборкаДетальныеЗаписи.Адрес);
Параметры1.Вставить("Тема", ВыборкаДетальныеЗаписи.Тема);
Параметры1.Вставить("Тело", ВыборкаДетальныеЗаписи.Текст);
Параметры1.Вставить("ТипТекста", "Строка");
Параметры1.Вставить("Вложения", СоответствиеВложений);
//Тут идет отправка через типовой механизм БСП
РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(Справочники.УчетныеЗаписиЭлектроннойПочты.СистемнаяУчетнаяЗаписьЭлектроннойПочты, Параметры1);
Исключение
ОписаниеОшибки = ОписаниеОшибки();
Отказ = Истина;
КонецПопытки;
КонецЕсли;

Если Не Отказ Тогда
МенеджерЗаписи = РегистрыСведений.ОтложеннаяОтправкаПисем.СоздатьМенеджерЗаписи();
ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ВыборкаДетальныеЗаписи);
МенеджерЗаписи.Прочитать();
Если МенеджерЗаписи.Выбран() Тогда
МенеджерЗаписи.ДатаОтправки  = ТекущаяДата();
МенеджерЗаписи.Записать();
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;

КонецПроцедуры

 

4. Добавляем в общий модуль процедуру регистрации новых писем к отправке.

 
Процедура ДобавитьПисьмоВРегистрПисьмаОтправленные(СтруктураНастройка) Экспорт

Набор = РегистрыСведений.ОтложеннаяОтправкаПисем.СоздатьНаборЗаписей();
Набор.Отбор.ДатаКогдаОтправить.Установить(СтруктураНастройка.ДатаКогдаОтправить);
Набор.Отбор.Объект.Установить(СтруктураНастройка.Объект);
Запись = Набор.Добавить();
ЗаполнитьЗначенияСвойств(Запись,СтруктураНастройка);
Если ТипЗнч(СтруктураНастройка.МассивТабДок) = Тип("Массив") И СтруктураНастройка.МассивТабДок.Количество() > 0 Тогда
Запись.Вложения = Новый ХранилищеЗначения(СтруктураНастройка.МассивТабДок, Новый СжатиеДанных());
КонецЕсли;
Попытка
Набор.Записать();
Исключение
ОписаниеОшибки = ОписаниеОшибки();
КонецПопытки;

КонецПроцедуры

 

5. В модуль документа или другом месте добавляем вызов процедуры ДобавитьПисьмоВРегистрПисьмаОтправленные

 
&НаСервере
Процедура ОтправкаНаСервере()

объект1 = РеквизитФормыВЗначение("Объект");

ТабДокумент = Новый ТабличныйДокумент;
Макет    =  объект1.ПолучитьМакет("Макет");
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ТабДокумент.Вывести(ОбластьЗаголовок);

СтрНастройка = Новый Структура;
СтрНастройка.Вставить("Адрес", "abc123@abc123.ru");
СтрНастройка.Вставить("Тема" , "Тема письма");
СтрНастройка.Вставить("Текст", "Текст письма");
МассивТабДок = Новый Массив;
МассивТабДок.Добавить(ТабДокумент);
СтрНастройка.Вставить("МассивТабДок", МассивТабДок);
СтрНастройка.Вставить("Объект", Документ);
СтрНастройка.Вставить("Расширение", "XLS");
СтрНастройка.Вставить("ДатаКогдаОтправить", ТекущаяДата());
СлужебныеПроцедурыИФункции.ДобавитьПисьмоВРегистрПисьмаОтправленные(СтрНастройка);

КонецПроцедуры

 

6. Функция проверки отправляли письмо или нет по ссылке документа.

 
Функция ПисьмоОтправляли(Док) Экспорт

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПисьмаОтправленные.Объект КАК Объект
|ИЗ
| РегистрСведений.ОтложеннаяОтправкаПисем КАК ПисьмаОтправленные
|ГДЕ
| ПисьмаОтправленные.Объект = &Док";
Запрос.УстановитьПараметр("Док",Док);
Возврат Не Запрос.Выполнить().Пустой();

КонецФункции

 

Тестировал на платформе 1С:Предприятие 8.3 (8.3.13.1644)

6 Comments

  1. Поручик

    БСП: Получение и отправка электронных писем.

    УправлениеЭлектроннойПочтой.ПолучениеИОтправкаЭлектронныхПисем

    Reply
  2. John_d

    (1) Спасибо, но одной процедуры без параметров недостаточно. Вот если бы ссылку на статью с подробным и простым описанием, как настроить это в БСП.

    Reply
  3. Fragster

    (2) в БСП достаточно записать документ «ЭлектронноеПисьмоИсходящее» с заполненными реквизитами и он сам отправится в фоне. По заполнению реквизитов — в справку к БСП и списку процедур в ОтправкаПочтовыхСообщений и прочих у соответствующей подсистемы.

    Reply
  4. volokitinac

    На большом объеме записей на регистре будет много

    база будет пухнуть из-за данных в МассивТабДок

    пару лет назад до БСП, пришлось писать аналог на двух очередях, подписках и регламентных заданиях

    1. Очередь для обработки новых документов для получения печатных форм

    2. Очередь для рассылки полученных документов

    как развитие можно завернуть на параллельные фоновые задания. но не стал.

    Reply
  5. Трактор

    Я не гружу событие при записи. Регламентным заданием раз в минуту выбираю документы по которым надо отправить письма и создаю письма. Отправкой созданных писем занимается другое регламентное задание.

    Reply
  6. John_d

    (5) Как вариант, но у меня требовали доказательств, что письма отправляются. Пользователи заходили в этот регистр и видели всю интересующую их информацию. С учетом, что тема и текст письма динамически формировались для разных получателей.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *