DEV Community

Stanislav Karol
Stanislav Karol

Posted on

Отправка писем в 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://useYandex@yandex.ru:password@smtp.yandex.ru
MAIL_FROM_NAME=WebWork
Enter fullscreen mode Exit fullscreen mode

Написал в файле 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,
      },
    },
  };
};
Enter fullscreen mode Exit fullscreen mode

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

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

@Module({
  imports: [

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

  ],
})

Enter fullscreen mode Exit fullscreen mode

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

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

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

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

import { MailerService } from '@nestjs-modules/mailer';
Enter fullscreen mode Exit fullscreen mode
@Injectable()
export class UserService {
  constructor(
    // помимо всего прочего подключение сервиса отправки
    private readonly mailerService: MailerService,
  ) {}
///
}
Enter fullscreen mode Exit fullscreen mode
  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,
        );
      });
  }
Enter fullscreen mode Exit fullscreen mode

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

Описываемый проект после публикации и проверки отправки почты выдал ошибку о том, что не может найти файл 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
  }
}
Enter fullscreen mode Exit fullscreen mode

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

Discussion (2)

Collapse
itsjokexd profile image
itsjokexd • Edited

 Привет! Сейчас как раз занимаюсь проектом, где нужно отправлять юзерам при регистрации письма. Делал как у вас, но столкнулся с проблемой, что Яндекс не даёт слать письма из приложения. Просит решить капчу, а у меня нет никакого интерфейса, где эта капча могла бы появиться.
Возникала ли у вас такая проблема? Если да, то как боролись?

Collapse
slkarol profile image
Stanislav Karol Author • Edited

Приветствую!
Что-то похожее было- мне бот яндекса написал, что имя отправителя должно совпадать с именем яндекс-учётки. То есть у меня там было "Бот address@yandex.ru" - пришлось изменить на соответствие рег. данным.
Второй отказ был такой: Яндекс-бот пишет мне, что почта довольно подозрительная, похоже на спам. Предлагает мне для снятия подозрений отправить письмо с этого адреса. Когда отправил, почта отправлялась без проблем, но не долго. Потом опять яндекс-бот пишет о подозрении на спам, опять нужно руками какое-то письмо отправить.
Поэтому я решил отойти от яндекса- может гугл или другой сервис попробовать.

Надеюсь мои два шага Вам помогут.