Oteto Blogのロゴ

【NestJS】React(jsx)で作成したメールをmailer serviceで送信する

やりたいこと

  • NestJSでメールを送信したい
  • 検証としてGmailアカウントから送信したい
  • メールテンプレートを作成する上で@nestjs-modules/mailerではテンプレートエンジンとしてhandlebars・pug・ejsが使えるようだが、扱いやすさを重視してjsx(React)で書きたい

1. ライブラリのインストール

npm i @nestjs-modules/mailer nodemailer @webtre/nestjs-mailer-react-adapter
npm i -D @types/nodemailer

2. Gmailパスワードの発行

Googleアカウントのセキュリティ設定から「2段階認証プロセス」を有効にし、「アプリパスワード」から16桁のパスワードを発行する。

3. メールサーバの設定

.envMAIL_HOST=smtp.gmail.com
MAIL_FROM=xxx@gmail.com
MAIL_USER=xxx@gmail.com
MAIL_PASSWORD=xxxxxxxxxxxxxxxx

今回はGmailアカウントから送信したいので、上記のように環境変数としてメールサーバのオプションを設定する。

パスワードは先ほど取得した「アプリパスワード」のものを指定。

4. MailModuleの実装

nest g module mail
nest g service mail --no-spec
mail/mail.module.tsimport { Module } from '@nestjs/common';
import { MailService } from './mail.service';
import { MailerModule } from '@nestjs-modules/mailer';
import { ReactAdapter } from '@webtre/nestjs-mailer-react-adapter';
import { ConfigService } from '@nestjs/config';
import { join } from 'path';

@Module({
  imports: [
    MailerModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => ({
        transport: {
          host: configService.get<string>('MAIL_HOST'),
          auth: {
            user: configService.get<string>('MAIL_USER'),
            pass: configService.get<string>('MAIL_PASSWORD'),
          },
        },
        defaults: {
          from: configService.get<string>('MAIL_FROM'),
        },
        template: {
          dir: join(__dirname, '/templates'),
          adapter: new ReactAdapter(),
          options: {
            strict: true,
          },
        },
      }),
    }),
  ],
  providers: [MailService],
  exports: [MailService],
})
export class MailModule {}
  • 環境変数から各オプションの値を取得し設定
  • adapter: new ReactAdapter()とすることでテンプレートをjsxで記述できる

5. メールテンプレートの作成

mkdir src/mail/templates
touch src/mail/templates/test.tsx
mail/templates/test.tsximport type { FC } from 'react';

type Props = {
  message: string;
};

export default function Test({ message }: Props): FC<Props> {
  return (
    <p>{message}</p>
  );
}

6. MailServiceの実装

mail/mail.service.tsimport { Injectable } from '@nestjs/common';
import { MailerService } from '@nestjs-modules/mailer';

@Injectable()
export class MailService {
  constructor(private readonly mailerService: MailerService) {}

  async sendTestMail(message: string) {
    await this.mailerService.sendMail({
      to: 'xxx@gmail.com',
      subject: 'テストメール',
      template: './test',
      context: { message },
    });
  }
}
  • MailerServiceをDIしsendMail()でメールを送信
  • templateにはそのメールで使用するテンプレートのパスを指定
  • contextにはtsx側に渡したい値を指定

7. 動作確認

nest-cli.json{
  "compilerOptions": {
    "deleteOutDir": true,
    "assets": ["mail/templates/**/*"]
  }
}

テンプレートファイルをビルドの対象にする。

npm run build

実際にビルドしてみるとdist下にtsxファイルが作成されている。

8. 動作確認

import { Injectable } from '@nestjs/common';
import { MailService } from '../mail/mail.service';

@Injectable()
export class SampleService {
  constructor(private readonly mailService: MailService) {
  }

  async sampleMethod(): Promise<void> {
    await this.mailService.sendTestMail('hello!');
  }
}

実装したMailServiceをDIしメソッドを呼び出し、メールが送信されていればOK。