Перейти к основному содержимому

Provider Adapter: Email Messaging (заглушка)

Назначение

Доставка канала Email (../domain/channel.md) через внешнего email-провайдера (SMTP/ESP). Заглушка: реализация отложена — контракт зафиксирован, отправка активируется per-канал feature-флагом (ChannelConfig.IsEnabled) по мере интеграции вендора. Provider input (delivery-вебхуки) считается недоверенным внешним вводом.

Границы Adapter-а

ПолеЗначение
ProviderEmail ESP (SMTP / транзакционный ESP — вендор TBD)
Сервисnotifications
Capabilitymessaging (email)
Adapter classEmailChannelProvider
Typed clientIEmailProviderClient (типизированный, вокруг вендорного SDK/HTTP)
Внутренняя операциявызывается dispatcher-ом при Channel = Email, Status = Pending
Реализациязаглушка (отложено) — до включения канала отправка не выполняется и возвращается код NTF_PROVIDER_NOT_IMPLEMENTED

Контракты Provider-а

Операция Provider-аDirectionInternal modelProvider-specific model
sendoutboundNotificationDispatchRequestEmailSendRequest (to/subject/html/text)
delivery/bounce/complaintcallbackProviderDeliveryReceiptEmailWebhookPayload (подписанный вебхук ESP)

Модель Internal NotificationDispatchRequest

Общая входная модель адаптеров каналов доставки (дом — ../domain/notification.md).

ПолеТипОбязательностьОписаниеMapping
NotificationIdGuidДаЭкземпляр доставки (идемпотентность)EmailSendRequest client-reference
RecipientAddress.EmailstringДаАдрес получателяto
RenderedTitlestring?НетТемаsubject
RenderedBodystringДаТело (html/text по Format)html/text
LocalestringДаЛокаль→ заголовки/шаблонная часть

Модель Provider-Specific EmailSendRequest

ПолеТипОбязательностьProvider formatValidationInternal mapping
tostringДаRFC 5322валидный emailRecipientAddress.Email
fromstringДаverified senderпо ChannelConfigконфиг
subjectstringДа≤ 256RenderedTitle
html/textstringДаmimeне пустоеRenderedBody
clientReferencestringДаidempotency= NotificationIdNotificationId

Предусловия диспатча и статусная семантика

  • Когда адаптер вызывается. Только для NotificationEntity с Channel = Email, Status = Pending и при ChannelConfig.IsEnabled = true. Пока канал — заглушка/выключен, email не является кандидатом на enqueue (../domain/notification.md «Резолв каналов»), поэтому Pending по email не создаётся и адаптер не вызывается.
  • Misconfig (включён, но не реализован). Если канал ошибочно включён при заглушке — send возвращает NTF_PROVIDER_NOT_IMPLEMENTED (non-retriable) → уведомление переводится в терминальный Failed + алерт (retry не крутится).
  • Sent = принято ESP. Успешный send (accepted) переводит уведомление в Sent; для ESP, подтверждающих доставку только вебхуком, Sent выставляется по delivered-квитанции. Sentтерминальный для email (INV-NTF-5).
  • Поздние bounce/complaint по уже Sent. Трактуются как delivery-сигнал: пишутся в LastError/ProviderMessageId (безопасные поля) и в аналитику dispatched; статус Sent в первой версии не переоткрывается (без отката Sent → Failed).
  • Failed до accept. Retriable-коды (NTF_PROVIDER_TRANSIENT/NTF_PROVIDER_RATE_LIMITED) → retry-worker повторяет до ChannelConfig.MaxAttempts (INV-NTF-7), после — терминальный Failed + алерт; non-retriable (NTF_PROVIDER_INVALID_RECIPIENT/NTF_PROVIDER_NOT_IMPLEMENTED) → терминальный Failed без повторов.

Безопасность

КонтрольПравило
Authenticationapi-key/OAuth ESP; verified sender-домен (SPF/DKIM/DMARC)
Signature validationdelivery-вебхук — HMAC-подпись ESP + timestamp + replay-window (≤ 5 мин)
Secretsapi-key/webhook-secret — в secret-store, ротация; не в ChannelConfig
PIIemail/тело — Sensitive; в логах маска (a***@x.ru), тело не логируется
Tenant bindingполучатель по RecipientUserId уведомления; sender/домен — платформенный

Resilience И Устойчивость

АспектПравило
TimeoutHTTP к ESP — 5с
Retryretriable-коды (5xx/429/timeout) → перевод в Failed → повтор retry-worker-ом (backoff по ChannelConfig)
Circuit breakerразмыкание на клиенте провайдера (open при серии ошибок ESP)
IdempotencyclientReference = NotificationId (ESP-дедуп)
Rate limitлокальный throttle ChannelConfig.RateLimitPerMinute под лимит ESP

Обработка Callback

ШагПравило
VerifyHMAC-подпись вебхука + timestamp + sender-домен
NormalizeEmailWebhookPayload → ProviderDeliveryReceipt (delivered/bounced/complained)
ValidateclientReference = известный NotificationId; типизированные ошибки
Dispatchприменить delivery-receipt: перевод уведомления в Sent/Failed (+ ProviderMessageId)
StoreProviderMessageId/LastError/статус на NotificationEntity (безопасные поля)

Маппинг Ошибок

Provider codeInternal errorПовторяемостьВидно пользователю
5xx / timeoutNTF_PROVIDER_TRANSIENTДаНет
429 rate limitNTF_PROVIDER_RATE_LIMITEDДа (backoff)Нет
invalid recipient / hard bounceNTF_PROVIDER_INVALID_RECIPIENTНетНет
не активирован (заглушка)NTF_PROVIDER_NOT_IMPLEMENTEDНетНет

Наблюдаемость

ТипПравило
Logssend-started/sent/provider-error/webhook-received/signature-failure (email/тело — маска)
Metricsnotifications_email_sent_total, notifications_email_error_rate, notifications_email_retry_total, circuit-state
TracescorrelationId, NotificationId, provider request id
Redactionapi-key/webhook-secret и raw email/тело — исключены

Обратные ссылки

Автоссылки: где используется этот документ.

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