概要
Nest.jsとMailCatcherを使ってメール送信機能を実装する方法について解説します
今回は招待メールを送信するAPIを作成します
前提
- Nest.jsのアプリケーションを作成済み
ディレクトリ構成
tree
.
├── .eslintrc.js
├── .gitignore
├── .prettierrc
├── nest-cli.json
├── package-lock.json
├── package.json
├── prisma
│ ├── migrations
│ ├── schema.prisma
│ └── seed.ts
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── email
│ │ ├── email.module.ts
│ │ ├── email.service.ts
│ │ └── templates
│ │ └── welcome.hbs
│ ├── main.ts
│ ├── prisma
│ │ ├── prisma.module.ts
│ │ └── prisma.service.ts
│ └── user
│ ├── dto
│ │ └── inviteUser.dto.ts
│ ├── user.controller.ts
│ ├── user.module.ts
│ └── user.service.ts
├── tsconfig.build.json
└── tsconfig.json
以下のファイルを実装します
- docker-compose.yml
- email.module.ts
- email.service.ts
- welcome.hbs
- nest-cli.json
- inviteUser.dto.ts
- main.ts
- user.service.ts
- user.controller.ts
実装
docker-compose.yml
Mailサーバ用のコンテナを作成する際にMailCatcherを使用します
mailcatcherとは
MailCatcher runs a super simple SMTP server which catches any message sent to it to display in a web interface.
公式ドキュメントに記載されている通り簡易的なSMTPサーバでMailCatcherに送信されたメールをWebインターフェイス(Webブラウザ)に表示させることができます
本番環境ではAWSのSESを使うのでローカルでメール送信テストを行いたいときはMailCatcherを使ってみましょう
Run mailcatcher, set your favourite app to deliver to smtp://127.0.0.1:1025 instead of your default SMTP server, then check out http://127.0.0.1:1080 to see the mail that's arrived so far.
公式ドキュメントに記載されている通り
MailCatcherのイメージを指定して
- SMTP用の1025番ポート
- Webブラウザで閲覧する用の1080番ポート
の2種類のポートを解放します
version: '3.9'
services:
mail:
container_name: mail
image: schickling/mailcatcher
ports:
- "1080:1080"
- "1025:1025"
email.module.ts
メール送信機能用のModuleの設定を行います
今回はMailCatcherを使用しているのでホストはlocalhost、portがMailCatcherのSMTP用のポートである1025を使用します
import { Module } from '@nestjs/common';
import { EmailService } from './email.service';
import { MailerModule } from '@nestjs-modules/mailer';
import { join } from 'path';
import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';
@Module({
imports: [
MailerModule.forRoot({
transport: {
host: 'localhost',
port: Number('1025'),
secure: false,
},
defaults: {
from: '"No Reply" <no-reply@example.com>',
},
template: {
dir: join(__dirname, 'templates'),
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
}),
],
providers: [EmailService],
exports: [EmailService],
})
export class EmailModule {}
email.service.ts
招待メールを送信する用のメソッドを作成します
宛先はリクエスト内のメールアドレス、テンプレートは後述するwelcome.hbsを使用します
import { MailerService } from '@nestjs-modules/mailer';
import { Injectable } from '@nestjs/common';
import { InviteUserDto } from 'src/user/dto/inviteUser.dto';
@Injectable()
export class EmailService {
constructor(private readonly mailerService: MailerService) {}
async welcomeEmail(data: InviteUserDto) {
const subject = `ようこそ`;
await this.mailerService.sendMail({
to: data.email,
subject,
template: './welcome',
});
}
}
welcome.hbs
招待メール用のテンプレートを作成します
<p>ようこそ</p>
nest-cli.json
このままだとhbsファイルはコンパイルされた際、distフォルダ内に格納されません
メールが送信されなくなってしまうので以下のように設定します
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [
{
"include": "**/email/templates/**/*",
"outDir": "dist/src",
"watchAssets": true
}
]
}
}
inviteUser.dto.ts
リクエスト内の入れたメールアドレスのバリデーションを行います
今回は
- Emailの形式なのか
- 最大値が254文字
のバリデーションを適用させます
import { IsEmail, MaxLength } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class InviteUserDto {
@ApiProperty()
@IsEmail()
@MaxLength(254)
email: string;
}
main.ts
先ほど作成した
- EmailModule
- EmailService
をimportします
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { UserService } from './user/user.service';
import { UserController } from './user/user.controller';
import { UserModule } from './user/user.module';
import { EmailModule } from './email/email.module';
import { EmailService } from './email/email.service';
@Module({
imports: [
ConfigModule.forRoot({ envFilePath: '../.env' }),
UserModule,
EmailModule,
],
controllers: [AppController, UserController],
providers: [AppService, UserService, EmailService],
})
export class AppModule {}
user.service.ts
emailServiceを使ってメールを送信します
import { Injectable } from '@nestjs/common';
import { EmailService } from '../email/email.service';
import { InviteUserDto } from './dto/inviteUser.dto';
@Injectable()
export class UserService {
constructor(
private readonly emailService: EmailService,
) {}
async send_invite_user_email(data: InviteUserDto) {
this.emailService.welcomeEmail(data);
}
}
user.controller.ts
UserService内のメール送信メソッドを実行できるようコントローラの設定を行います
import { Controller, HttpCode, HttpStatus } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
import { InviteUserDto } from './dto/inviteUser.dto';
@ApiTags('users')
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Post('send_invite_user_email')
@HttpCode(HttpStatus.OK)
send_invite_user_email(@Body() inviteUserDto: InviteUserDto) {
return this.userService.send_invite_user_email(inviteUserDto);
}
}
実際にメールを送信してみよう!
メールを送信します
リクエスト内にメールアドレスを入力し、リクエストを送信します
127.0.0.1:1080へアクセスし、以下のようにメールが送信されたら成功です
参考