# Почта — Администрирование

Документ описывает администрирование почтовой подсистемы 1Формы: подключение почтовых серверов, настройку ящиков, управление очередями отправки и получения, шаблоны уведомлений, почтовые джобы, смарт-обработку писем и диагностику неполадок. Охватывает как серверный уровень (SMTP/IMAP/EWS), так и уровень категорий и пользователей. Предназначен для администраторов платформы и специалистов внедрения.

## Механизмы администрирования

Домен mail охватывает подключение почтовых серверов, настройку почтовых ящиков, управление очередями отправки/получения, шаблоны уведомлений и почтовые джобы. Администрирование использует:

- **Автоадминистрирование** — 8 форм (серверы, настройки, пользователи ящика, категории, шаблоны, очереди)
- **AdminSPA** — формы управления пользовательскими и сервисными почтовыми ящиками
- **Редактор сущностей** — 1 схема (`addressprovider.json` — адресные провайдеры)
- **API администрирования** — 4 маршрута (управление ящиками, очередями, шаблонами, заданиями)

### Автоадминистрирование

Формы и таблицы автоадминистрирования почты:

| Alias формы | Название | Таблица БД | Папка |
|-------------|----------|-----------|-------|
| `mail-servers` | Почта | dbo.EmailMailServers | Подключения |
| `email-settings` | Настройки почты | dbo.EmailSettings | Служебное |
| `email-mail-boxes-users` | Пользователи ящика | dbo.EmailMailBoxesUsers | Служебное |
| `mail-server-category` | Почтовые категории | dbo.MailServerCategory | Служебное |
| `mail-templates` | Шаблоны почтовых уведомлений | dbo.MailTemplates | Прочее |
| `email-job-send-queue` | Очередь на отправку | dbo.EmailJobSendQueue | Служебное |
| `email-job-send-queue-log` | Очередь отправки (лог) | dbo.EmailJobSendQueueLog | Служебное |
| `email-job-receive-queue-log` | Очередь на получение | dbo.EmailJobReceiveQueueLog | Служебное |

### EntityEditor и Admin API контроллеры

**EntityEditor** — схема `addressprovider.json` для таблицы `dbo.AddressProvider` (адресные провайдеры, например Dadata).

| Схема JSON | Таблица | Назначение |
|-----------|---------|------------|
| `addressprovider.json` | dbo.AddressProvider | Адресные провайдеры (Dadata и т.п.) |

Поля схемы: `Id`, `Name`, `Type` (enum: Dadata). Виртуальные поля: `ApiUrl`, `ApiKey`, `ApiSecret` (только при `Type=Dadata` и `context=update`).

**API администрирования** предоставляет 4 маршрута для управления почтовой подсистемой:

| Маршрут | Методы | Назначение |
|---------|--------|------------|
| `/api/admin/mail` | DELETE | Очистка очереди отправки |
| `/api/admin/mail-box` | GET, POST, DELETE | Управление ящиками, подписи, синхронизация папок |
| `/api/admin/mail-templates` | GET, POST, PUT, DELETE | Шаблоны уведомлений: создание, изменение и удаление, проверка содержимого, каталог событий и подстановок, разбор каскада, предпросмотр без отправки, экспорт и импорт |
| `/api/admin/jobs/mail` | POST | Ручной запуск почтовых заданий |

**Подписи почтового ящика в административном контуре.** Под `/api/admin/mail-box` доступны те же четыре операции с подписями ящика, что и в пользовательском контуре: список, сохранение, удаление и изменение порядка. Отличие — в проверке прав: административные методы требуют прав администрирования и работают с подписями любого ящика, не требуя, чтобы вызывающий был его пользователем или владельцем; проверяется только существование ящика, иначе возвращается «ящик не найден». Пользовательский контур не изменился: список подписей читают все пользователи ящика, изменять их может только владелец, остальным возвращается отказ.

## Ключевые настройки

### Почтовые серверы и глобальные настройки почты

**Почтовые серверы (EmailMailServers)** настраиваются в автоадминке через форму «Почта» (`mail-servers`, 6 секций). **Таблица БД:** `dbo.EmailMailServers`.

Секции формы и ключевые поля:

| Секция | Поля | Что контролирует |
|--------|------|------------------|
| Общее | `Name`*, `EmailDomains`, `NoRetryErrors`, `IsUserMailboxesAllowed` | Имя сервера, домены, разрешение пользовательских ящиков |
| Exchange Server | `IsExchange`, `EWSUrl`, `MailProviderId`, `MailServerCategoryId` | Подключение через EWS |
| CalDav | `IsCalDav`, `CalDavAddress`, `CalDavProviderId` | Интеграция с CalDav-календарём |
| Gmail | `IsGmail`, `ReceivedHeader` | Gmail-специфичные настройки |
| SMTP | `SMTPAddress`*, `SMTPPort`*, `SMTPUseSSL`, `SMTPAnonymous`, `SslProtocol` | Исходящая почта |
| IMAP | `IMAPAddress`*, `IMAPPort`*, `IMAPUseSSL` | Входящая почта |

**Дефолт SSL-флагов.** Флаги «Использовать SSL» — `SMTPUseSSL` (секция SMTP) и `IMAPUseSSL` (секция IMAP) — по умолчанию **сняты** (`0`/`false`): почтовый сервер можно создать без SSL, не трогая эти галки. Ранее у колонок не было значения по умолчанию, поэтому форма требовала их явного указания и не давала сохранить сервер без SSL.


**Анонимная отправка по SMTP (`SMTPAnonymous`).** Флаг относится только к SMTP: при `SMTPAnonymous = 1` письмо отправляется без SMTP-аутентификации — логин и пароль ящика на SMTP-сервер не передаются. На IMAP флаг **не влияет**: логин и пароль ящика передаются при каждом IMAP-подключении — и при синхронизации/получении писем, и при загрузке копии отправленного письма в папку «Отправленные». Ящику на сервере с `SMTPAnonymous = 1` всё равно нужны рабочие учётные данные для IMAP; IMAP-подключение не создаётся только для ящиков в режиме «только отправка» (`SendingOnly = 1`).

Если IMAP-логин не проходит на сервере с `SMTPAnonymous = 1`, отправка письма не прерывается и ящик не помечается признаком `InvalidCredentials`, но копия в «Отправленные» не сохраняется: в журнале джоба отправки появляется ошибка «Не удалось загрузить письмо в папку 'Отправленные'», а письмо остаётся в очереди на повторную отправку (адресат при этом уже получил его). При `SMTPAnonymous = 0` та же ошибка IMAP-авторизации трактуется как неверные учётные данные — ящику выставляется `InvalidCredentials = 1`.

**Зависимости:** секции Exchange/CalDav/Gmail — взаимоисключающие (активна одна в зависимости от типа сервера).

**Как применяется:** определяют провайдера подключения к почтовому серверу.

**Настройки почты (EmailSettings)** настраиваются в автоадминке через форму «Настройки почты» (`email-settings`). **Таблица БД:** `dbo.EmailSettings`.

| Группа полей | Что контролирует |
|-------------|------------------|
| `IsEmailEnabled` | Глобальное включение/выключение почтовой подсистемы |
| `IsEmailJobsEnabled` | Включение всех почтовых джобов |
| `IsEmailJobSyncEnabled` / `IsEmailJobReceiveEnabled` / `IsEmailJobSendEnabled` | Включение отдельных джобов |
| `IsEmailJobReceiveSecondaryEnabled` | Вторичная очередь получения |
| `IsEmailJobSyncDeleteEnabled` / `IsEmailJobPurgeDeletedEnabled` | Очистка удалённых |
| `UseMailBoxForSystemMessages` / `MailBoxForSystemMessagesId` | Ящик для системных уведомлений |
| `IsMultiThreadingEnabled` / `MultiThreadingNumThreads` | Общая многопоточность |
| `IsJobSyncMultiThreadingEnabled` / `JobSyncMultiThreadingNumThreads` | Многопоточность sync |
| `IsJobReceiveMultiThreadingEnabled` / `JobReceiveMultiThreadingNumThreads` | Многопоточность receive |
| `IsJobSendMultiThreadingEnabled` / `JobSendMultiThreadingNumThreads` | Многопоточность send |
| `IsEmailChainsEnabled` | Цепочки писем |
| `MaxReceiveQueueRecordsPerSession` / `MaxSendQueueRecordsPerSession` | Лимиты записей в очереди за сессию |
| `MaxRetriesToMoveToSecondQueue` / `MaxRetriesToQuitTrying` | Логика ретраев |
| `MaxDaysInQueue` | Время жизни в очереди |

**Как применяется:** все флаги проверяются перед запуском соответствующих почтовых заданий (Quartz).

#### Отключение заданий без перезапуска приложения (с 2.268.338)

Снятие галок в настройках почты останавливает уже запущенные задания **без перезапуска приложения**:

- Общее условие работы всех почтовых заданий — `IsEmailEnabled && IsEmailJobsEnabled`.
- Каждое почтовое задание (`EmailJobReceive`, `EmailJobReceiveSecondary`, `EmailJobSend`, `EmailJobSendSecondary`, `EmailJobSyncFolders`, `EmailJobSyncDelete`, `EmailJobPurgeDeleted`, `CleanMailBoxesJob`) перед запуском проверяет это условие и свой персональный флаг (`IsEmailJobReceiveEnabled`, `IsEmailJobSendEnabled` и т. д.). Если хотя бы один снят — задание сразу завершается с пометкой «Skipped: disabled in email settings».
- **Задержка до 30 секунд** до вступления в силу — время жизни кэша настроек почты в памяти. До истечения кэша задание ещё может стартовать.

**Важно:** обратное включение галок **без перезапуска приложения не работает**. Задания регистрируются в планировщике один раз — при старте приложения; если задание тогда не попало в планировщик (галка была снята) — последующее включение через интерфейс его не зарегистрирует. Для возврата нужен перезапуск узла.

### Почтовые ящики (EmailMailBoxes)

**Почтовые ящики (EmailMailBoxes)** настраиваются в AdminSPA (раздел Почта → Почтовые ящики). **Таблица БД:** `dbo.EmailMailBoxes`.

| Поле | Что контролирует |
|------|------------------|
| `MailServerID` | Привязка к серверу |
| `MailBoxName` / `SenderName` / `SenderEmail` | Отображение и адрес отправителя |
| `Login` / `Password` | Учётные данные. Пароль для подключения к почтовому серверу указывается при создании или редактировании ящика. **Безопасность:** поле «Пароль» доступно только в форме редактирования ящика и не выводится в гриде почтовых ящиков. |
| `LeaveCopies` | Оставлять копии на сервере |
| `Disabled` | Отключение ящика |
| `SendingOnly` | Только отправка (без синхронизации) |
| `NotUseInSmarts` | Исключить из смарт-действий |
| `EmailStoreDuration` | Срок хранения писем (дни) |
| `DaysCountToSyncOldMail` | Глубина синхронизации старой почты |
| `UseNTLM` | Признак хранится у ящика, но на аутентификацию при подключении не влияет: почтовая библиотека MailKit не поддерживает NTLM, поэтому и на SMTP, и на IMAP всегда передаются логин и пароль ящика. Рассчитывать на доменную аутентификацию по этому флагу нельзя — у ящика должны быть заполнены `Login` и `Password` |
| `ShowCounters` | Показывать счётчики в интерфейсе |
| `IsSynchronized` («Синхронизируется») | Режим хранения писем: включено — фоновая синхронизация в БД 1Формы (`SyncedMailProvider`, таблица `Emails`), нужно для почтовых смартов и приёма писем в задачи; выключено — прямой доступ к серверу (online IMAP/Exchange). Управляется галочкой «Синхронизируется» в форме ящика; при сохранении без изменения поля прежнее значение не сбрасывается |

![Мастер подключения почтового ящика: сопоставление папок для синхронизации (входящие, отправленные, корзина и т.д.)](https://help.1forma.ru/help-images/mail/mail_create_step_3.png)

Связанная форма: «Пользователи ящика» (`email-mail-boxes-users`) — привязка пользователей к ящику.

Подписи ящика настраиваются в том же диалоге редактирования: блок «Подписи электронной почты» со списком, созданием, правкой, удалением и стрелками порядка. Это тот же раздел, который владелец ящика видит в своих настройках почты, и те же данные — отдельного административного списка нет. Блок появляется только у сохранённого ящика; при создании нового его нет. Если сервер отказал, открывается окно с текстом ошибки, а список остаётся прежним.

**Почта категории (ServiceMailBoxes)** настраивается в AdminSPA (раздел Почта → Сервисные ящики). **Таблица БД:** `dbo.ServiceMailBoxes`. Привязывает почтовый ящик к категории для автоматической обработки входящих писем (создание задач из писем).

### Шаблоны уведомлений (MailTemplates)

**Где настраивается:** страница «Почтовые шаблоны» в администрировании (`/administration/mail-templates`), автоадминка → форма «Шаблоны почтовых уведомлений» (`mail-templates`) или API администрирования
**Таблица БД:** `dbo.MailTemplates`

8 полей: шаблоны для различных типов уведомлений (создание задачи, комментарий, подпись и т.д.). Поддерживают HTML + переменные подстановки.

**Редактор шаблонов.** Шаблоны настраиваются на странице «Почтовые шаблоны» раздела администрирования (`/administration/mail-templates`); пункт меню «Почтовые шаблоны» открывает её вместо страницы старой админки.

В списке выводятся событие, описание, категория, язык, формат, активность и отметка «Побеждает» — она стоит у шаблона, который применится для выбранного сочетания события, категории и языка. Над списком фильтры: событие, категория, язык, «Только активные» и «Только глобальные».

Кнопка добавления и клик по строке открывают редактор. Поля: событие (из справочника событий с описаниями), описание, активность, категория, язык (обязателен), формат — «Дизайн» или «Классический» — и тело шаблона. Тело набирается в XML-редакторе в формате из раздела «HTML-шаблоны уведомлений» ниже; подстановки вставляются кнопками палитры в позицию курсора тегами вида `<inline type="..." id="..."/>`. Палитра строится по выбранному событию и разбита на группы «Параметры», «Ресурсы», «Контролы» и «Доп. параметры»; пока событие не выбрано, вместо неё выводится подсказка, а подстановки, которым нужна категория, появляются только после её выбора. При редактировании существующего шаблона событие, категорию и формат изменить нельзя — другая привязка означает новый шаблон.

| Кнопка | Что делает |
|---|---|
| Создать из эталона | Загружает в редактор эталонный шаблон события из поставки; если тело уже заполнено, запрашивает подтверждение замены |
| Проверить | Проверяет XML и подстановки до сохранения и сообщает, валиден шаблон или содержит ошибки |
| Предпросмотр | По номеру задачи и получателю показывает тему и тело письма, не отправляя его |
| Какой шаблон сработает | Показывает шаблон, который применится для выбранного сочетания, и цепочку выбора; если подходящего шаблона нет, называет резервный вариант |

Изменять шаблоны может только пользователь с правом god: кнопки доступны любому администратору, но запрос на запись от остальных сервер отклоняет. Тестовой отправки письма в редакторе нет — вместо неё предпросмотр.

**Импорт и экспорт.** На странице «Почтовые шаблоны» рядом со списком есть блок выгрузки и загрузки шаблонов в XML. Экспорт скачивает файл `TemplatesExportFile.xml`; флажок «Только дефолтные» ограничивает выгрузку шаблонами по умолчанию. Импорт принимает только файл с расширением `.xml` — файл другого формата не отправляется, выводится ошибка. Флажок «Включить новые» сразу включает загруженные шаблоны, «Сохранить старые дефолтные» оставляет существующие нетронутыми; если он снят, перед импортом запрашивается подтверждение, и при отказе импорт не выполняется. Удаляется при этом не всё подряд: под замену попадает только шаблон с тем же именем, той же категорией и тем же языком, что и загружаемая строка, — остальные языки того же шаблона остаются. После импорта выводится число загруженных шаблонов, список перечитывается. Все три флажка по умолчанию включены. Эндпоинты: `POST /api/admin/mail-templates/export?defaultOnly={true|false}` и `POST /api/admin/mail-templates/import` (файл в поле `xmlFile`, параметры `newTemplatesOn`, `leaveOldTemplates`).

**Язык при импорте.** Язык строки определяется по алиасу языка из файла, а не по его номеру: номера языков на разных площадках не совпадают, а алиас переносится. Алиас ищется сначала точным совпадением, затем без учёта регистра. Если в файле встретился алиас, которого на площадке нет, или алиас, который без учёта регистра указывает сразу на два языка, импорт отклоняется целиком — до того, как что-либо записано, — и в ответе перечислены все такие алиасы сразу. Старые выгрузки без колонки алиаса импортируются по-прежнему, по номеру языка из файла; по номеру идёт и строка, у которой алиас пустой. Если языка с таким номером на площадке нет, импорт тоже отклоняется.

**Язык в файле выгрузки.** Каждая строка файла несёт колонку `LangAlias` — код языка шаблона из [справочника языков](https://help.1forma.ru/domains/localization/admin.md). Номер языка в строке тоже остаётся, но переносится между площадками именно алиас. Файл сохраняется вместе с XML-схемой; служебные колонки связи шаблона с категорией и языком в выгрузку не попадают. Выгрузка целиком прерывается ошибкой, если у какой-то строки язык отсутствует в справочнике языков или у языка пустой алиас: в сообщении перечислены номера таких языков, файл не формируется. Лечится приведением справочника языков в порядок — добавить недостающий язык или заполнить алиас — и повторной выгрузкой.

**Имена шаблонов (события).** Имя шаблона должно строго совпадать с именем события — иначе шаблон не активируется. Поле «Описание» произвольное.

При создании задачи отправляются три независимых письма — исполнителям, подписчикам и уведомляемым, — и каждое включается только собственным шаблоном: `TaskCreatePerformerSend`, `TaskCreateSubscriberSend`, `TaskCreateNotifySend`. Письмо уходит, если шаблон с этим именем включён, не привязан к категории и его тело не пустое; шаблон другого события, выключенный шаблон и шаблон с пустым телом ветку не активируют. Чтобы уходили все три письма, нужны все три шаблона.

| Группа | События |
|---|---|
| **Задачи: жизненный цикл** | `TaskCreated`, `TaskCreateNotifySend`, `TaskCreatePerformerSend`, `TaskCreateSubscriberSend`, `TaskFromYourNameCreated`, `TaskTextChanged`, `TaskTextChangedWithoutDifferencies`, `TaskAccepted`, `Noacceptant`, `AccessDenied` |
| **Задачи: статус и срок** | `StateChanged`, `StateChangedForcibly`, `StateChangeNotificationToAll`, `DueChanged`, `DueChangedOverdue` |
| **Задачи: исполнители и подписчики** | `PerformerAdded`, `PerformerAddedToOwner`, `PerformerRemoved`, `PerformerRefused`, `ResponsibleAdded`, `ResponsibleRemoved`, `SubscriberAdded` |
| **Подписи (акцепт)** | `SignatureAccepted`, `SignatureRejected`, `SignatureSnapshot`, `DynSignatureAccepted`, `DynSignatureRejected`, `AcceptantAssigned`, `AcceptantAssignedWithEmptyFields`, `AcceptantAssignedEscalate`, `AcceptantAssignedWithEmptyFieldsEscalate`, `AcceptantDelegated`, `AcceptantDelegatedEscalate`, `AcceptantDelegatedWithEmptyFields`, `AcceptantDelegatedWithEmptyFieldsEscalate` |
| **Комментарии** | `NewComment`, `NewCommentSimple`, `EditComment`, `EditCommentSimple` |
| **Параметры и файлы** | `ExtParamsChanged`, `FileDescriptionUpdated` |
| **Заместители** | `AssistantAdded`, `AssistantAddedwDates`, `AssistantRemoved`, `HelperNotification` |
| **Доступ и пользователи** | `ChangeGroupSubcatPermission`, `UserInvitation`, `Absence` |
| **Пароли** | `NewPassword`, `RemindPassword`, `PasswordRecovery`, `PasswordRecoveryForCustomerZone` |
| **Дефолт** | `DefaultTemplate` — стандартный шаблон по умолчанию |

> Ссылки на задачи в шаблонах формируются в формате `/spa/tasks/{TaskID}` без учёта `Users.UseNewTaskCard`.

### Почтовые джобы и очереди

**Почтовые задания** настраиваются через API администрирования (`/api/admin/jobs/mail`).

| Маршрут | Назначение |
|----------|------------|
| `POST mailboxes/clean` | Ручная очистка ящиков |
| `POST folders/sync` | Ручная синхронизация папок |
| `POST folders/sync-disabled` | Синхронизация отключённых |
| `POST folders/sync-multithreaded` | Многопоточная синхронизация |

Автоматический запуск: Quartz-джобы, управляемые через `dbo.EmailSettings`.

Вся почтовая обработка выполняется асинхронно: каждый джоб запускается по расписанию и обрабатывает свою очередь.

| Джоб | Назначение |
|------|------------|
| Синхронизация (`EmailJobSyncFolders`) | Проверяет наличие новых писем и синхронизирует флаги прочтения. Формирует очередь на получение, но сам письма не скачивает |
| Получение (`EmailJobReceive`) | Скачивает письма из очереди, сформированной джобом синхронизации |
| Получение, вторая очередь (`EmailJobReceiveSecondary`) | Обрабатывает «проблемные» письма (>5 неудачных попыток), чтобы не блокировать основную очередь |
| Отправка (`EmailJobSend`) | Обрабатывает очередь на отправку |
| Отправка, вторая очередь (`EmailJobSendSecondary`) | Повторяет отправку писем с >5 ошибками |
| Синхронизация удаления (`EmailJobSyncDelete`) | Двусторонняя синхронизация удаления: удалённые на сервере удаляются в 1Форме и наоборот |
| Очистка удалённых (`EmailJobPurgeDeleted`) | Физическое удаление из БД писем, помеченных для удаления |
| Очистка ящиков (`EmailJobCleanMailBoxes`) | Удаляет письма старше N дней (параметр «Хранить письма N дней») |

**Очереди отправки и получения.** Настройка через автоадминку: формы «Очередь на отправку» (`email-job-send-queue`), «Очередь отправки (лог)» (`email-job-send-queue-log`), «Очередь на получение» (`email-job-receive-queue-log`). **Таблицы БД:** `dbo.EmailJobSendQueue`, `dbo.EmailJobSendQueueLog`, `dbo.EmailJobReceiveQueueLog`.

Используются для мониторинга и ручной диагностики. Очистка очереди отправки: `DELETE /api/admin/mail/clear-mail-sending-queue`.

## Типичные ошибки настройки

Частые проблемы настройки почты и способы их диагностики:

| Симптом | Причина | Где проверить | SQL-диагностика |
|---------|---------|---------------|-----------------|
| Письма не отправляются | `IsEmailEnabled = 0` или `IsEmailJobSendEnabled = 0` | Форма `email-settings` | `select IsEmailEnabled, IsEmailJobSendEnabled from dbo.EmailSettings` |
| Ящик не синхронизируется | `IsSynchronized = 0`, либо `Disabled = 1`, либо `SendingOnly = 1` | AdminSPA → Почтовые ящики (галочка «Синхронизируется») | `select MailBoxID, MailBoxName, IsSynchronized, Disabled, SendingOnly, InvalidCredentials from dbo.EmailMailBoxes where MailBoxID = {id}` |
| Ошибка авторизации | Неверные Login/Password или `InvalidCredentials = 1` | Форма `email-mail-boxes` | `select MailBoxID, MailBoxName, InvalidCredentials, LastSyncException from dbo.EmailMailBoxes where InvalidCredentials = 1` |
| Очередь отправки растёт | Джоб send отключён или лимит слишком мал | Формы `email-settings` + `email-job-send-queue` | `select count(*) as QueueSize from dbo.EmailJobSendQueue; select MaxSendQueueRecordsPerSession, MaxRetriesToQuitTrying from dbo.EmailSettings` |
| Входящие письма не создают задачи | Нет привязки ящика к категории | Форма `service-mail-boxes` | `select * from dbo.ServiceMailBoxes where MailBoxID = {boxId}` |
| SMTP-ошибки | Неверный адрес/порт/SSL | Форма `mail-servers` → секция SMTP | `select MailServerID, Name, SMTPAddress, SMTPPort, SMTPUseSSL from dbo.EmailMailServers` |

## Диагностика почтового подключения

Встроенной функции проверки подключения (тест-кнопки) в системе нет. Диагностика выполняется по существующим элементам интерфейса и логам.

**Проверка почтового сервера:**

1. Откройте форму **Почта** (`mail-servers`).
2. Убедитесь, что создан почтовый сервер и в секции **SMTP** заполнены адрес, порт и параметры шифрования (`SMTPAddress`, `SMTPPort`, `SMTPUseSSL`).
3. Для серверов Exchange / CalDav / Gmail проверьте соответствующую секцию формы.

**Проверка глобального состояния:**

1. Откройте форму **Настройки почты** (`email-settings`).
2. Убедитесь, что флаг `IsEmailEnabled` включён — иначе почтовая подсистема полностью отключена.
3. Убедитесь, что флаг `IsEmailJobSendEnabled` включён — иначе джоб отправки не запускается.

**Проверка состояния ящика:**

1. Откройте форму **Почтовые ящики** (`email-mail-boxes`).
2. Проверьте поля ящика:
   - `Disabled` — если `1`, ящик отключён.
   - `InvalidCredentials` — если `1`, авторизация не пройдена.
   - `LastSyncException` — текст последней ошибки синхронизации.

**Ручной запуск джоба отправки:**

1. Откройте форму **Почта** (`mail-servers`).
2. Нажмите кнопку **«Джоб отправки: Send Job»** — система выполнит отправку писем из очереди.
3. После запуска проверьте очередь `email-job-send-queue` — количество записей должно уменьшаться.

**Проверка очереди отправки:**

1. Откройте форму **Очередь на отправку** (`email-job-send-queue`).
2. Если очередь растёт, а письма не уходят — проверьте настройки в форме **Настройки почты**: `IsEmailJobSendEnabled`, `MaxSendQueueRecordsPerSession`.

**Включение SMTP-лога.** Для детальной диагностики проблем с отправкой включите лог SMTP-команд:

1. Включите ключ `UseSmtpLog` в `CustomSettings`.
2. Журнал SMTP-команд пишется в «Сессии почтовых джобов» (`log_mail`).

## Почтовые смарты (Smart)

Настройка почтовых смартов доступна по кнопке **Smart** на странице почтовых серверов. Смарты позволяют автоматически выполнять действия при поступлении письма в указанную папку. Обработка работает только для ящиков с включённой опцией **«Синхронизируется»** (`IsSynchronized = 1`); дополнительно ящик не должен быть отключён (`Disabled = 0`) и не должен работать в режиме только отправки (`SendingOnly = 0`).

По кнопке **Создать** открывается окно привязки пакета действий к почтовой папке. Выбираются:

- Почтовый ящик (из числа синхронизируемых)
- Почтовая папка в этом ящике (например, INBOX)

**Доступные действия:**

| Категория | Действия |
|-----------|----------|
| Стандартные | Вложить файл, Изменить/массово изменить/копировать/очистить ДП, Назначить/удалить заместителя, Обновить свойство пользователя, Перейти в статус / сделать переход / принудительно изменить статус, Создать/удалить задачу, Создать/уволить пользователя |
| Почтовые | Отправить email / email на группу / системный email / SMS, Переместить почтовое сообщение в папку, Привязать письмо к задаче |
| Сторонние DLL | Синхронизировать дополнительные параметры задач |

Имперсонализация, OAuth, NTLM и прочие EWS-специфичные параметры описаны в [администрировании календаря](https://help.1forma.ru/domains/calendar/admin.md) (раздел EWS). Здесь — только почтовый контекст.

## Почтовые ящики категории (ServiceMailBoxes)

Подключение ящика к категории позволяет автоматически создавать задачи из входящих писем. Ящик, привязанный к категории, **не должен** быть закреплён за пользователем.

**5-шаговая инструкция подключения:**

1. В разделе «Системный» создать категорию (например, «Почта»). Специальный маршрут не требуется.
2. Отключить обязательный срок в настройках категории: **Основные настройки → Настройки задачи → Срок**.
3. Перейти в **Дополнительные настройки → Почта → Почтовые ящики** и подключить email-адрес внутреннего ящика.
4. Включить опцию **Обрабатывать авто-ответы** в настройках ящика.
5. В **общих настройках приложения** указать выбранный ящик как «Почтовый ящик для ответов».

### 9 настроек ящика категории

Настройки подключения ящика категории:

| Настройка | Описание |
|-----------|----------|
| Email\* | Почтовый адрес ящика |
| Логин\* | Имя, отображаемое в отправленных письмах |
| Пароль\* | Пароль от ящика |
| Сервер\* | Адрес IMAP/SMTP (например, `imap.gmail.com`) |
| Порт\* | Порт соединения |
| Протокол | **IMAP** (рекомендуется) или **POP3** |
| SSL | Шифрование соединения (рекомендуется включить) |
| IMAP-папка | Папка для загрузки писем (по умолчанию INBOX) |
| Процедура при завершении обработки (SQL) | Хранимая процедура, выполняемая после обработки всех писем |
| Количество писем для загрузки | Лимит за сессию (по умолчанию 100) |
| Дублировать тело письма в текст задачи | Текст письма вставляется и в комментарий, и в текст задачи |
| Создавать новых пользователей | Адресаты из «Кому», отсутствующие в системе, автоматически добавляются |
| Обрабатывать авто-ответы | Ответы на первоначальное письмо → комментарии в существующей задаче, а не новые задачи |
| Вкладывать оригинал письма | Исходное письмо вкладывается в задачу при создании |

### Аутентификация отправителя входящих писем

Сервисный ящик создаёт задачи и действия от имени отправителя входящего письма. Чтобы отправитель определялся только по письмам, подлинность которых подтверждена вашим почтовым сервером (MTA) — по заголовку `Authentication-Results` (результаты `SPF`/`DKIM`/`DMARC` и совпадение проверенного домена с доменом в `From`), — настраиваются ключи `SettingsCustom`:

| Ключ | Назначение |
|------|-----------|
| `ServiceMailTrustedAuthservIds` | Список `authserv-id` (через запятую) доверенных MTA в заголовке `Authentication-Results`. Пусто — ни один узел не доверен. **Заполнение ключа включает проверку.** |
| `ServiceMailSenderAuthMode` | `auto` (по умолчанию — проверка включается, как только заполнен `ServiceMailTrustedAuthservIds`; до этого ведётся только журналирование и поведение не меняется), `audit` (только журнал), `enforce` (проверка всегда). |
| `ServiceMailTrustedFromDomains` | Необязательный список доменов `From` (через запятую), которым разрешена атрибуция при доверенном `Authentication-Results`. Пусто — без ограничения по домену. |

**Требования к почтовому шлюзу.** Чтобы проверка работала, входящий шлюз должен добавлять в письма заголовок `Authentication-Results` с результатами `SPF`/`DKIM`/`DMARC` и удалять либо перезаписывать одноимённые заголовки, пришедшие вместе с письмом извне.

Когда проверка активна и письмо её не проходит, задача или комментарий создаётся от системного пользователя (робота), а не от адреса из `From`; исполнители и подписчики из `To`/`CC` не назначаются, новые пользователи по такому письму не создаются. Проверка действует на уровне домена; субдомены (`mail.example.com` и `example.com`) считаются разными — для рассылки с субдомена нужна собственная успешная отметка.

### Протоколы, заголовки маршрутизации и заполнение ДП

**Протоколы: IMAP vs POP3 vs EWS:**

| Параметр | IMAP | POP3 | EWS |
|----------|------|------|-----|
| Порт | 143 (plain), 993 (SSL) | 110 (plain), 995 (SSL) | 443 (HTTPS) |
| Синхронизация папок | Да (мног папок) | Нет (только INBOX) | Да |
| OAuth-аутентификация | Почтовый сервер | Почтовый сервер | Настраивается в календаре |
| Имперсонализация | Нет | Нет | Настраивается в календаре |
| NTLM-аутентификация | Нет (MailKit не поддерживает; `UseNTLM` не влияет) | Нет (MailKit не поддерживает) | Настраивается в календаре |

Подробнее об EWS-параметрах (домен, URL, логин, SID, имперсонализация) — в [администрировании календаря](https://help.1forma.ru/domains/calendar/admin.md).

> **Известное ограничение отображения.** До фикса SPA мог сохранить протокол «IMAP» как числовое значение `0`, не соответствующее ни одному протоколу на бэкенде (валидные значения: IMAP=2, POP3=1) — это приводило к ошибке обработки писем для такого ящика. Фикс исправил сохранение новых значений, но список ящиков по-прежнему показывает **любое** значение протокола, кроме `2` (IMAP), как «POP3» — включая уже испорченные старые записи с `0`. Если ящик отображается как POP3, но ведёт себя не так, как ожидается (или заводился как IMAP) — открыть форму ящика и заново явно выбрать протокол, чтобы пересохранить корректное значение.

**Формат заголовков для маршрутизации.** Концепция описана в [бизнес-документации](https://help.1forma.ru/domains/mail/business.md) (раздел «Формат заголовков для маршрутизации»).

Маркеры в теме письма определяют действие системы. Вместо `[1f]` подставляется значение «Краткое имя приложения» из общих настроек:

| Заголовок | Действие |
|-----------|----------|
| *(пустой)* | Создание новой задачи |
| `[1f]<taskid>` | Запись в существующую задачу |
| `[1f]c<commentid>` | Ответ на комментарий |

Примеры:
```
#12345         → задача 12345
[1f]c42        → ответ на комментарий 42
```

**Заполнение ДП из письма.** Тело письма может содержать XML-теги для заполнения ДП:

```xml
<extparams><extparam id="ID_параметра">Значение</extparam></extparams>
```

> **Важно:** при заполнении ДП из письма необходимо отключить HTML в настройках категории. Подробнее — в [бизнес-документации](https://help.1forma.ru/domains/mail/business.md) (раздел «Заполнение ДП из письма»).

## Настройки почты и сообщений категории

### Почтовые настройки и сообщения категории

На уровне категории можно управлять подключением почтового ящика и параметрами приёма писем (см. раздел «Почтовые ящики категории» выше).

Те же настройки доступны на отдельной странице AdminSPA **«Почтовые сообщения»** (`/administration/subcategory-mail-messages/{subcatId}`): чип на неё — в блоке «Основные настройки» экрана категории, пункт «Почтовые сообщения» — в боковом блоке «Почта». Страница читает и сохраняет значения через контракт `GET`/`POST /api/admin/subcategories/{subcatId}/settings/mail`; раздел «Администрирование» открыт администратору системы.

Настройки отправки уведомлений для задач категории:

| Настройка | Описание |
|-----------|----------|
| Не посылать почтовые сообщения | Отключает все почтовые уведомления для задач категории (задачи при этом продолжают отображаться в ленте). Значение по умолчанию: пользовательская настройка `ScDisableMail` |
| Добавить в заголовки писем параметр | Вставить в тему письма значение выбранного ДП |
| Добавить в заголовки писем текст | Вставить в тему письма произвольный текст |
| Почтовое сообщение об отклонении | Текст письма при отклонении задачи |
| Почтовый ящик для внешних пользователей | Email-адрес и имя отправителя, подставляемые для внешних контрагентов |

Все поля этой секции скрыты при активной опции **Не посылать почтовые сообщения**.

**Ограничение длины.** Три поля ограничены 200 символами каждое: текст, добавляемый в заголовки писем, почтовый ящик внешних пользователей и имя отправителя. Более длинное значение не сохраняется — страница показывает сообщение с именем поля и пределом, а прежние почтовые настройки категории остаются в силе. Значение ровно в 200 символов сохраняется без обрезки.

**Как работает отправка уведомлений внешним пользователям**

Получатель считается внешним, если в его профиле снят признак «Сотрудник компании» — даже если у него заполнен внутренний Email. Для таких пользователей система использует адрес и имя из поля «Почтовый ящик для внешних пользователей» категории.

Если у внешнего получателя не заполнен внешний Email, используется внутренний Email. Если не заполнено внешнее отображаемое имя — используется стандартное отображаемое имя пользователя. Уведомление отправляется независимо от того, заходил ли внешний получатель в систему хотя бы раз.

Для корректной отправки убедитесь, что в профиле внешнего пользователя заполнен хотя бы один адрес (внутренний или внешний Email).

### Отключение отдельных типов почтовых уведомлений в категории

**Вопрос (типовой кейс):** как в настройках категории отключить только определённый тип почтового уведомления — например письмо заявителю о создании задачи — оставив остальные письма?

**Ответ: на уровне категории это невозможно.** Единственный почтовый переключатель у категории — флаг **«Не посылать почтовые сообщения»** (см. таблицу выше). Он работает по принципу «всё или ничего»: отключает почтовые уведомления по **всем** событиям категории сразу (задачи при этом продолжают отображаться в ленте). Тонкой настройки по отдельным типам событий (создание задачи, комментарий, смена статуса и т.д.) на уровне категории нет.

**Где тип события отключается по отдельности — только на уровне пользователя.** В личных настройках уведомлений (Профиль → «Уведомления») каждый тип события настраивается отдельно — столбец **«Непрочитанные»**; общий тумблер дублирования уведомлений на почту — **«Не присылать почтовые сообщения»** (действует глобально по пользователю; режимы «Когда я в онлайне» / «В рабочее время» / «Когда я отсутствую»). Эти настройки применяются ко всем категориям, где не включён категорийный флаг «Не посылать почтовые сообщения». Подробнее — [notifications/business.md](https://help.1forma.ru/domains/notifications/business.md).

| Что нужно отключить | Где | Гранулярность |
|---|---|---|
| Все письма категории | Категория → «Не посылать почтовые сообщения» | Вся категория целиком |
| Конкретный тип события | Профиль пользователя → «Уведомления», столбец «Непрочитанные» | Per-пользователь, per-тип, глобально по категориям |
| Дублирование на почту целиком | Профиль → «Не присылать почтовые сообщения» | Per-пользователь, все типы |

**Частая путаница:** письмо о создании задачи приходит заявителю, хотя «не должно». Причина обычно не в категории, а в том, что у пользователя включён этот тип в столбце «Непрочитанные». Отдельно: пользователю **не** приходит уведомление о действии, которое он совершил сам (создал задачу сам → письмо «задача создана» себе не получит — оно уходит другим адресатам: исполнителям, наблюдателям).

## HTML-шаблоны уведомлений: теги, CSS, клиенты

### Формат шаблона и поддерживаемые HTML-теги

Шаблоны хранятся в `dbo.MailTemplates` (поле `TemplateContent`) в виде XML со специальным синтаксисом 1Формы. Тело письма всегда отправляется как HTML.

Элемент тела шаблона обязан называться `mailbody` или `body` — другого имени рендерер не принимает. Проверка выполняется при формировании письма, а не при сохранении шаблона: шаблон с телом под другим именем сохраняется, но отправка уведомления по нему завершается ошибкой шаблона.

Два режима рендеринга определяются полем `Standard` шаблона:

- `Standard = 0` (старый режим): CDATA-блоки выводятся как сырой HTML, поддерживаются теги-команды.
- `Standard = 1` (новый режим): CDATA-блоки **пропускаются**, HTML-теги вставляются через XML-элементы с атрибутами.

При импорте шаблона `Standard` принудительно устанавливается в `1`.

Рендерер **не фильтрует теги по списку разрешённых**: любой HTML-тег, вставленный как XML-элемент в шаблоне, попадает в письмо без изменений. Ограничений на стороне платформы нет.

Практически используемые теги (используются в системных шаблонах):

| Категория | Теги |
|-----------|------|
| Текст | `<p>`, `<br>`, `<b>`, `<font color="...">`, `<strong>`, `<em>` |
| Структура | `<table>`, `<tr>`, `<td>`, `<div>` |
| Ссылки | `<a href="...">` |
| Изображения | `<img>` (см. ниже) |
| Запрещено email-клиентами | `<script>`, `<iframe>`, `<form>` — платформа не блокирует, но клиенты вырежут |

### CSS: inline стили и совместимость с email-клиентами

Платформа не делает автоматического CSS-инлайнинга — тело письма уходит в письмо как есть.

Рекомендации:

- **`<style>` в `<head>`** — технически передаётся в письмо, но:
  - **Gmail** вырезает `<style>` в `<head>` полностью.
  - **Outlook 2016+** игнорирует большинство CSS в `<style>`.
  - **Apple Mail, Яндекс.Почта, Thunderbird** поддерживают `<style>` в `<head>`.
- **Inline CSS** (`style="..."` на каждом теге) — единственный надёжный способ для Outlook и Gmail.
- Все системные XML-шаблоны 1Формы (`Mail/*.xml`) используют **только inline CSS**.

**Вывод:** использовать только inline CSS. `<style>`-блоки работают в части клиентов, но ломают Outlook и Gmail.

Пример правильного подхода:
```html
<table align="left" cellpadding="3" cellspacing="0" width="100%" style="font-family: Arial; font-size: 10pt">
  <tr>
    <td style="color: #1f497d">...</td>
  </tr>
</table>
```

**Совместимость с email-клиентами:**

| Клиент | `<style>` в `<head>` | Inline CSS | `<table>` | `<font>` |
|--------|----------------------|------------|-----------|----------|
| Gmail (web) | Нет | Да | Да | Да |
| Outlook 2016+ | Частично | Да | Да | Да |
| Apple Mail | Да | Да | Да | Да |
| Яндекс.Почта | Да | Да | Да | Да |
| Thunderbird | Да | Да | Да | Да |

Данные о совместимости приведены по общей практике email-клиентов.

### Подстановка переменных в шаблоне (теги-команды)

Шаблон — XML. Переменные вставляются специальными тегами, а не `{{mustache}}` или `%name%`:

| Тег | Что подставляет |
|-----|-----------------|
| `<parameter name="taskid"/>` | Динамический параметр по имени (передаётся в шаблон при вызове) |
| `<inline type="Parameter" id="..."/>` | Аналог parameter (Standard=1) |
| `<inline type="Resource" value="..."/>` | Строка из ресурсного файла `MailResources` |
| `<inline type="Control" id="..."/>` | Управляющий элемент (ссылка на задачу, ДП и т.п.) |
| `<tasktext/>` | Текст задачи |
| `<tasktextshort/>` | Краткий текст задачи |
| `<tasklink fullmode="true"/>` | Ссылка на задачу |
| `<taskentityname/>` | Название типа сущности (задача/заявка/...) |
| `<subcat/>` | Название категории |
| `<extparams/>` | Блок дополнительных параметров (ДП) |
| `<unsubscribelink/>` | Ссылка для отписки |
| `<spectaskid/>` | Системный ID задачи |
| `<subjectPrefix/>` / `<subjectPostfix/>` | Префикс/постфикс темы письма |
| `<br/>` | Перенос строки |
| `<formatted resource="...">` | Форматированная строка с подстановками |

Параметры `<parameter name="..."/>` зависят от типа события (tcEvent). Общие:
`subcatid`, `taskid`, `comment`, `taskuser`, `additionalhtml`, `shortcomment`, `custommailtext`, `State`, `NextState`, `userwhochangedstate`, `createdtask`, `orderedtime`, `PlannedTime`.

#### Подстановки текста комментария

В шаблонах писем о новом комментарии текст комментария выводится двумя подстановками:

| Параметр | Что подставляет |
|---|---|
| `comment` | HTML комментария — форматирование, изображения, ссылки на задачи. Когда письма уходят от имени системного ящика, перед этим HTML добавляется служебный блок «Автор → Получатели» с автором комментария и его адресатами |
| `commentwithoutsender` | Тот же HTML комментария вместе со ссылками на файлы, но без служебного блока «Автор → Получатели» |

`commentwithoutsender` применяют, когда отправитель и получатели уже выведены отдельными элементами шаблона и служебный блок в теле письма их дублирует. Если письма уходят не от системного ящика, служебный блок не добавляется и обе подстановки дают один и тот же текст. Для конфиденциальной задачи получателю без доступа к содержимому обе подстановки заменяются сообщением о скрытом тексте — как и остальные текстовые параметры письма.

### Готовый минимальный шаблон: изображения, размер и ограничения

**Изображения и вложения.** `<img src="...">` передаётся в письмо без изменений. Платформа не делает CID-встраивание (inline Base64) автоматически. Рекомендуется использовать внешние URL (корпоративный хост или CDN). Вложенные файлы — через `<attachments/>` тег (добавляет прикреплённые файлы задачи).

Ограничение на размер тела письма определяется SMTP-сервером, не платформой. Платформа не обрезает. Максимальное количество вложений не ограничено платформой (цикл `foreach` по `Attachments`).

Рабочий XML-шаблон (Standard=0, на основе системных шаблонов 1Формы):

```xml
<?xml version="1.0" encoding="utf-8" ?>
<email>
  <subject>
    <subjectPrefix/><parameter name="custommailtext"/><subjectPostfix/>
  </subject>
  <body>
    <![CDATA[
    <table align="left" cellpadding="3" cellspacing="0" width="100%"
           style="font-family: Arial; font-size: 10pt;">
      <tr>
        <td>
    ]]>
    <parameter name="comment"/>
    <![CDATA[
        </td>
      </tr>
      <tr bgcolor="#dbe5f1">
        <td style="color: #1f497d;">
    ]]>
    <tasklink fullmode="true"/>
    <![CDATA[
        </td>
      </tr>
      <tr>
        <td style="font-size: 8pt; color: gray;">
    ]]>
    <subcat/>
    <![CDATA[
        </td>
      </tr>
      <tr>
        <td style="font-size: 10pt; color: #1f497d;">
    ]]>
    <unsubscribelink/>
    <![CDATA[
        </td>
      </tr>
    </table>
    ]]>
  </body>
</email>
```

Ключевые правила:

1. HTML вставляется через CDATA (`<![CDATA[...]]>`).
2. CSS только inline.
3. Для таблиц использовать `<table>` с `cellpadding`/`cellspacing` — Outlook не поддерживает CSS box model.
4. Переменные 1Формы — XML-теги вне CDATA.

## Серверные настройки: appsettings.json и CustomSettings

**appsettings.json — обходные настройки SMTP:**

| Ключ | Тип | Назначение |
|------|-----|------------|
| `UseHacksForMailSending` | bool | Включает обходные настройки SMTP-отправки (например, выбор схемы кодирования темы письма для совместимости со старыми клиентами / шлюзами) |

### CustomSettings — глобальные ключи почты

Глобальные настройки почтовой подсистемы:

| Ключ | Тип / Default | Назначение |
|------|---------------|------------|
| `DisableSmtpChunking` | bool | Отключение chunked transfer encoding для SMTP. Если `true` — тело письма передаётся монолитным блоком (используется при несовместимости со старыми SMTP-серверами) |
| `UseSmtpLog` | bool | Логирование SMTP-команд в журнал «Сессии почтовых джобов» (`log_mail`). Включать для диагностики проблем с отправкой |
| `SaveExecuteJobLogForEmailJobSyncFolders` | bool | Логирование синхронизации папок ящиков в журнал заданий по таймеру (`log_jobs`). Помогает отлавливать «отстающие» IMAP/EWS-джобы |
| `ScDisableMail` | `0` / `1` | Глобальное массовое включение настройки категории «Не посылать почтовые сообщения». Удобно при миграциях / отладочных дампах БД |
| `UseMailToLinksForSignaturesFromEmails` | `0` / `1` | Если `1` — кнопки резолюций в письмах с запросом подписи становятся `mailto:`-ссылками: клик открывает почтовый клиент с заполненными полями (`subject = "TaskSignatureID + ResolutionKey="`, `body = текст комментария`). Ответное письмо приходит на ящик из общих настроек («Почтовый ящик для ответов» или «Внешний…»), задание `ServiceMailBoxesJob` обрабатывает его и выносит резолюцию. ⚠️ Требует, чтобы в системной категории «Уведомление о прочтении» был настроен соответствующий ящик. Если `0` или пусто — обычные ссылки на интерфейс 1Формы |
| `ImapTimeout` | int (мс) | Таймаут IMAP-подключения и одной операции при синхронизации ящика. По умолчанию 40 000; значение `0` или меньше — таймаут не ограничен. Увеличить при таймаутах от удалённого Exchange/IMAP-сервера |
| `MailBoxUnresolvedRetryTimeoutSec` | int (сек) / 300 | Таймаут повторной проверки в БД почтового ящика, отсутствующего в кеше провайдеров. Смягчает плавающую ошибку «MailBox not found» при разрешении ящика (в т.ч. при обработке вложений) |

**Переподключение при обрыве IMAP.** Если соединение с сервером обрывается во время приёма письма, задание переподключается к папке и повторяет загрузку этого письма. Если повтор снова упирается в обрыв или в неверные учётные данные ящика, письмо остаётся в очереди и обрабатывается на следующем запуске.

## Почтовая библиотека

С версии **2.268** для работы с протоколами IMAP и SMTP, разбора MIME-сообщений и очистки HTML-тел писем платформа использует open-source библиотеки **MailKit** и **MimeKit**. Очистка HTML выполняется через библиотеку **HtmlSanitizer**.

Ранее использовалась коммерческая библиотека **MailBee.NET**, требовавшая лицензионного ключа. После миграции лицензия не нужна — это упрощает развёртывание и снимает зависимость от поставщика для on-prem-инсталляций (в том числе в контуре ФСТЭК-сертификации). Поведение протоколов IMAP/POP3/SMTP, маршрутизация писем, шаблоны уведомлений и почтовые смарты при миграции не изменились.

Протокол **MAPI** не поддерживается. Для работы с MAPI рекомендуется промежуточный обработчик (**DavMail**). Таймаут IMAP-операций настраивается ключом `ImapTimeout` (см. таблицу CustomSettings выше; по умолчанию 40 секунд).

### Совместимость с HCL Domino IMAP (с 2.268.374, задача #2100592)

Для синхронизации ящиков на **HCL Domino** в IMAP-поиске «писем после даты» используются критерии `DeliveredAfter` / `DeliveredBefore` / `DeliveredOn` (internal date сообщения) вместо `SentSince` / `SentBefore` / `SentOn`. Domino не поддерживает реляционные операторы поверх текстового заголовка `Date:` (на котором построен `SENTSINCE`) и при таком запросе возвращает ошибку или пустой результат; фильтрация по internal date — числовому полю — отрабатывает штатно. На Exchange / Gmail / Yandex / Mail.ru изменение прозрачно: internal date совпадает со временем доставки в `INBOX`.

## Хранение паролей ящиков

С версии 2.268 шифрование паролей выполняется через штатный сервис шифрования платформы — `EncryptionService` (формат `VENC:`, ключ `EncKey`). Ранее использовался устаревший `SimpleAES` (RijndaelManaged, CWE-327); способ расшифровки выбирается по формату самого значения, отката на прежний алгоритм нет. Расшифровка происходит в памяти приложения при подключении к почтовому серверу (SMTP / IMAP / Exchange / CalDav). В гриде ящиков пароль не выводится и доступен только в форме редактирования.

Пароли хранятся в колонках `EmailMailBoxes` (`Password`, `CalDavPassword`) и `ServiceMailBoxes` (`Password`); в защищённое хранилище `IntegrationSecrets` пароли ящиков не пишутся. Чтение из колонок двухформатное: значение с префиксом `VENC:` расшифровывает `EncryptionService`, значение старого формата — унаследованный AES. Новый или изменённый пароль записывается сразу в `VENC:`.

Для перевода уже сохранённых паролей старого формата в `VENC:` без потери данных предназначена утилита `MailBoxPasswordReEncryptionService`, вызываемая из Lua:

```lua
local srv = UTILS:resolve_instance('TCClassLib', 'TCClassLib.Services.Mail.MailBoxPasswordReEncryptionService');
srv:ReEncryptAll();
```

Автоматического запуска у утилиты нет — её вызывает ТП вручную, и до прогона сохранённые пароли остаются в базе в том формате, в котором были записаны: на работу почты это не влияет, чтение понимает оба формата. Запускать её следует после раскатки сборки на **все** инстансы, работающие с одной базой, — инстанс старой сборки значение `VENC:` не прочитает. Утилита обходит `EmailMailBoxes` (пароль и пароль CalDAV) и `ServiceMailBoxes` (пароль), по каждой таблице пишет в ActionLog итог: всего, перешифровано, пропущено, ошибок. Повторный запуск безопасен — значения, уже переведённые в `VENC:`, пропускаются.

**Объявление перешифровки завершённой.** После прогона утилиты площадка может закрыть чтение старого формата: настройка `MailBoxesLegacyReEncryptionCompleted` = `true` запрещает расшифровку немаркированных значений на рабочем пути. С этого момента ящик с остатком старого формата не подключается: в журнал пишется ошибка с идентификатором ящика и источником значения (таблица и колонка), наружу отдаётся отказ — шифртекст вместо пароля в почтовый сервер не уходит. Тот же ключ закрывает и открытый пароль сервисного ящика в старом формате. Утилита перешифровки ключом не ограничена: её миграционный путь читает старый формат всегда, поэтому найденный остаток чинится повторным прогоном. Порядок один: сначала прогон на всех инстансах, затем ключ.

Ключ `EncKey` хранится централизованно в настройках платформы (`Settings.EncKey`) — не рядом с шифротекстом, как в старом `SimpleAES`. Пароли защищены от прямого чтения из БД (например, при доступе к резервной копии), но уровень защиты **не эквивалентен HSM** или внешнему хранилищу ключей — это симметричное шифрование без отдельной инфраструктуры управления ключами. Этот аспект учитывают при ИБ-аудите инсталляции.

### Сертифицированная сборка (1F Certificate Edition)

В сертифицируемой сборке прежнего шифровальщика паролей нет: `SimpleAES` вместе с его единственным потребителем в сборку не входит. Значение, записанное актуальным форматом площадки (в этом профиле — конверт `$v2$`), читается штатным сервисом шифрования; значение прежнего формата — шифртекст без маркера нового формата и открытый пароль сервисного ящика — не читается. Обращение к ящику завершается отказом с идентификатором ящика и источником значения, в журнал уходит ошибка, в почтовый сервер не отправляется ни шифртекст, ни расшифровка. Ящик молча не подключится — это ожидаемое поведение такой сборки, а не сбой авторизации.

Настройка `MailBoxesLegacyReEncryptionCompleted` в этом профиле не читается: отказ безусловен, значение ключа на поведение не влияет. Утилиты перешифровки и миграционного чтения прежнего формата в нём тоже нет. Остаток чинится одним из двух способов: заменить пароль ящика — при сохранении нового значения пароль перезапишется актуальным форматом — либо перешифровать остаток на исходной площадке, на полной сборке, до формирования дампа.

См. также: [support-guide.md](https://help.1forma.ru/domains/mail/support-guide.md) § 3.0 — типовой ответ на запрос ИБ-аудита.

**Связанные документы:**

- [Смарт-действия — администрирование](https://help.1forma.ru/domains/smart-actions/admin.md) — смарт-действия с почтой (отправка email из пакетов)
