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

Email Sender — отправка писем

email-sender-api — провайдер-библиотека для формирования и отправки транзакционных писем. Разделён на две Nx-библиотеки:

  • data-access (@crewsforge-back/email-sender-data-access) — «данные»: реестр типов писем, поддерживаемые языки, типы и утилита-конструктор HTML (constructEmailHtml) с рендером шаблонов и кэшированием.
  • features/sender (@crewsforge-back/email-sender-api-features-sender) — «фича»: EmailSenderService с высокоуровневыми методами (верификация регистрации, код смены пароля, уведомление о смене пароля, код админа), отправляющий письма через mailer-client.

Используется приложением auth-api во всех сценариях, где нужно отправить письмо.

Поддерживаемые языки заданы в data-access/.../constants/email-lang.constants.ts:

export const EMAIL_LANG = ['en', 'ru'] as const; // тип EmailLangTypes

Реестр типов писем — constants/email-types.constants.ts (EMAIL_TYPES). Каждый тип описывает id, name, templateFileName и список ожидаемых variables:

name (тип)Файл шаблонаПеременныеКогда отправляется
registry_email_verificationregistry_email_verification.htmluserName, emailCode, blockLinkВерификация email при регистрации (customer и employee)
password_change_codepassword_change_code.htmluserName, code, device, ipЗапрос на смену/сброс пароля — отправка кода подтверждения
password_changed_notificationpassword_changed_notification.htmluserName, device, ipУведомление об успешной смене пароля

Плюс отдельный inline-шаблон для админа (не из HTML-файлов, а функция в коде) — см. ниже.

Как конструируется письмо (email-constructor.utils + шаблоны)

Заголовок раздела «Как конструируется письмо (email-constructor.utils + шаблоны)»

Ядро — data-access/.../utils/email-constructor.utils.ts:

  • constructEmailHtml({ typeName, lang, variables }) — главная функция:
    1. resolveEmailTypeOrThrow находит тип в EMAIL_TYPES (иначе бросает ошибку «Unknown email type»).
    2. Пробует взять HTML из in-memory кэша templatesCache[typeName][lang].
    3. Если нет — loadTemplateHtml читает файл path.join(__dirname, 'assets', 'email-templates', <lang>, <templateFileName>) синхронно (fs.readFileSync) и кладёт в кэш.
    4. renderTemplate подставляет переменные: плейсхолдеры вида {{ varName }} заменяются значениями из variables (через coerceVariableToString: null/undefined'', числа/булевы → строка, объекты → JSON.stringify).
  • preloadAllEmailTemplates() — прогревает кэш всеми парами (тип × язык). Вызывается в конструкторе EmailSenderService, поэтому все шаблоны загружаются один раз при старте.

Шаблоны рендерятся простой заменой {{...}} — без движка типа Handlebars.

Файлы лежат в apps/auth-api/src/assets/email-templates/{en,ru}/ (по одному на каждый язык):

ФайлЯзык(и)Тип письмаТриггер
en/registry_email_verification.html, ru/registry_email_verification.htmlen, ruregistry_email_verificationРегистрация: отправка кода верификации email (sendRegistryVerificationEmail)
en/password_change_code.html, ru/password_change_code.htmlen, rupassword_change_codeЗапрос сброса пароля: отправка кода (sendPasswordChangeCodeEmail)
en/password_changed_notification.html, ru/password_changed_notification.htmlen, rupassword_changed_notificationПароль изменён: уведомление (sendPasswordChangedNotificationEmail)

Отдельно — features/sender/.../templates/admin-verification-code.template.ts: inline TS-функция adminVerificationCodeTemplate(code, lang='en'), генерирующая HTML прямо в коде (без файла). Помечена как PLACEHOLDER — требует дизайн-ревью. Используется методом sendAdminVerificationCode (код входа админа, действителен 15 минут).

EmailSenderService инжектит MailerClientService (@crewsforge-back/mailer-client) и вызывает mailerClient.send({ to, html }). mailer-client — обёртка над @nestjs-modules/mailer (nodemailer), сконфигурированная через MailerModule.forRootAsync из SmtpConfigService (config-shared-smtp): SMTP-транспорт (host, port, auth, tls.rejectUnauthorized:false) и defaults.from.

Цепочка: EmailSenderServiceMailerClientService.send()MailerService.sendMail() → SMTP.

Env-переменные SMTP: SMTP_HOST, SMTP_PORT (default 587), SMTP_USER, SMTP_PASSWORD, SMTP_FROM (см. docs/04-shared-and-utils/configs.md).

Каждый публичный метод сервиса обёрнут в try/catch: при ошибке письмо не роняет бизнес-логику — ошибка лишь пишется в console.error (в коде оставлен TODO про полноценный логгер).

EmailSenderService инжектится в auth-фичи приложения auth-api:

Метод сервисаВызывающие сервисы
sendRegistryVerificationEmailcustomer-auth-verification.service, employee-auth-verification.service (верификация email при регистрации)
sendPasswordChangeCodeEmailcustomer-auth-reset-password.service, employee-auth-reset-password.service (отправка кода при сбросе пароля)
sendPasswordChangedNotificationEmailте же reset-password сервисы (уведомление после смены пароля)
sendAdminVerificationCodeadmin-auth.service (код подтверждения входа админа)
  • libs/apis/providers/email-sender-api/features/sender/src/lib/email-sender.service.ts — сервис с методами отправки
  • libs/apis/providers/email-sender-api/features/sender/src/lib/email-sender.module.ts — модуль (импортирует MailerClientModule)
  • libs/apis/providers/email-sender-api/features/sender/src/lib/templates/admin-verification-code.template.ts — inline-шаблон кода админа (placeholder)
  • libs/apis/providers/email-sender-api/data-access/src/lib/constants/email-types.constants.ts — реестр типов писем
  • libs/apis/providers/email-sender-api/data-access/src/lib/constants/email-lang.constants.ts — список языков
  • libs/apis/providers/email-sender-api/data-access/src/lib/utils/email-constructor.utils.ts — конструктор HTML, рендер, кэш, preload
  • apps/auth-api/src/assets/email-templates/{en,ru}/*.html — HTML-шаблоны писем
  • libs/apis/utils/mailer-client/src/lib/* — SMTP-клиент (nodemailer)
  • libs/apis/configs/shared/smtp/src/lib/* — SMTP-конфиг