Отправка писем в NestJS используя nodemailer. Публикация скриптов.
Tags: nest, nodemailer, deploy, typescript
Published: 2021-07-03 11:49:19

Мне понадобилось отправить сообщение по почте о подтверждении регистрации на сайте. На текущий момент проверенное, хорошо зарекомендовавшее себя решение это [Nodemailer](https://nodemailer.com/about/). В роли бек-сервера у меня [NestJS](https://docs.nestjs.com/). Для NestJS есть модуль [Nest JS Mailer](https://nest-modules.github.io/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
```
Написал в файле src/configs/mail.config.ts формирование настройки почтовой службы:
```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, поэтому выбран такой формат для шаблонов писем.
Завершающий шаг установки - подключение модуля почты в приложение:
```ts
import { MailerModule } from '@nestjs-modules/mailer';

@Module({
  imports: [

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

  ],
})

```

### Отправка почты
У меня уже есть шаблон почты в файле confirmReg.ejs:
```html
<main>
  Доброго дня, <%= locals.username %>!<br />
  От Вас поступила регистрация на сайте post-life.<br />
  Для окончания регистрации пройдите пожалуйста по
  <a href="<%= urlConfirmAddress %><%= id %>">ссылке</a> .
</main>
```
Вот как он используется для отправки почты:
```ts
import { MailerService } from '@nestjs-modules/mailer';
```
```ts
@Injectable()
export class UserService {
  constructor(
    // помимо всего прочего подключение сервиса отправки
    private readonly mailerService: MailerService,
  ) {}
///
}
```
```ts
  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 . Мои поиски решения привели меня вот на [эту страницу](https://github.com/nest-modules/mailer/issues/42) . Суть того, что можно оттуда вынести: у NestJS есть свои опции настройки для typescript и в них можно указать файлы, которые ts должен скопировать "как есть" в каталог назначения. Теперь nest-cli.json стал таким: 
```json
{
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      "**/*.ejs"
    ],
    "watchAssets": true
  }
}
```

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