Отправка писем в NestJS используя nodemailer. Публикация скриптов.

Мне понадобилось отправить сообщение по почте о подтверждении регистрации на сайте. На текущий момент проверенное, хорошо зарекомендовавшее себя решение это Nodemailer. В роли бек-сервера у меня NestJS. Для NestJS есть модуль Nest JS Mailer, вот с ним и решил работать. Сперва установим пакеты @nestjs-modules/mailer, nodemailer и в dev-зависимость будет не лишним поставить @types/nodemailer . В качестве сервера почты я решил воспользоваться услугами яндекс.

Установка модуля

После того, как получена учётная запись от яндекса, записал в файл .env такие переменные:
MAIL_TRANSPORT строка подключения к smtp-серверу для отправки почты (см. https://nodemailer.com/smtp/)
MAIL_FROM_NAME от чьего имени будет приходить почта.

Пример:

MAIL_TRANSPORT=smtps://[email protected]:[email protected]
MAIL_FROM_NAME=WebWork

Написал в файле src/configs/mail.config.ts формирование настройки почтовой службы:

import { ConfigService } from '@nestjs/config';
import { EjsAdapter } from '@nestjs-modules/mailer/dist/adapters/ejs.adapter';

export const getMailConfig = async (
  configService: ConfigService,
): Promise<any> => {
  const transport = configService.get<string>('MAIL_TRANSPORT');
  const mailFromName = configService.get<string>('MAIL_FROM_NAME');
  const mailFromAddress = transport.split(':')[1].split('//')[1];

  return {
    transport,
    defaults: {
      from: `"${mailFromName}" <${mailFromAddress}>`,
    },
    template: {
      adapter: new EjsAdapter(),
      options: {
        strict: false,
      },
    },
  };
};

Что я здесь задаю: defaults.from - задаётся имя/адрес отправителя, template - у меня было больше практики с ejs, поэтому выбран такой формат для шаблонов писем.
Завершающий шаг установки - подключение модуля почты в приложение:

import { MailerModule } from '@nestjs-modules/mailer';

@Module({
  imports: [

    MailerModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: getMailConfig,
    }),

  ],
})

Отправка почты

У меня уже есть шаблон почты в файле confirmReg.ejs:

<main>
  Доброго дня, <%= locals.username %>!<br />
  От Вас поступила регистрация на сайте post-life.<br />
  Для окончания регистрации пройдите пожалуйста по
  <a href="<%= urlConfirmAddress %><%= id %>">ссылке</a> .
</main>

Вот как он используется для отправки почты:

import { MailerService } from '@nestjs-modules/mailer';
@Injectable()
export class UserService {
  constructor(
    // помимо всего прочего подключение сервиса отправки
    private readonly mailerService: MailerService,
  ) {}
///
}
async sendConfirmMail(user: UserEntity) {
    const urlConfirmAddress = this.configService.get<string>(
      'URL_CONFIRM_ADDRESS',
    );
    // Отправка почты
    return await this.mailerService
      .sendMail({
        to: user.email,
        subject: 'Подтверждение регистрации',
        template: join(__dirname, '/../templates', 'confirmReg'),
        context: {
          id: user.id,
          username: user.username,
          urlConfirmAddress,
        },
      })
      .catch((e) => {
        throw new HttpException(
          `Ошибка работы почты: ${JSON.stringify(e)}`,
          HttpStatus.UNPROCESSABLE_ENTITY,
        );
      });
  }

Публикация скриптов

Описываемый проект после публикации и проверки отправки почты выдал ошибку о том, что не может найти файл confirmReg.ejs . Почему шаблоны писем потерялись? - Компилятор из TS в JS "не заметил" файлы с раcширением ejs и после билда проекта каталог src/templates не оказался в папке назначения dist . Мои поиски решения привели меня вот на эту страницу . Суть того, что можно оттуда вынести: у NestJS есть свои опции настройки для typescript и в них можно указать файлы, которые ts должен скопировать "как есть" в каталог назначения. Теперь nest-cli.json стал таким:

{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      "**/*.ejs"
    ],
    "watchAssets": true
  }
}

Ссылка на проект : https://github.com/SLKarol/post-life

9