Closed2

Nest.js, Google Cloud でメール配信機能を作るときは

山本隼汰山本隼汰

メール配信機能って定番ですけど、いろんな選択肢があってちょっと迷いませんか?
メール配信サービスにもいろんな種類があるし、物によってはフレームワークがメール配信機能を対応していたりもするし、セキュリティの対応だったり、モニタリングだったりと考えることも意外と多いですよね。

今回は、少し前に実装する機会があった Nest.js と Google Cloud を用いたメール配信機能の実装事例を紹介します。検討に差し当たり調査したドキュメントなどをご紹介しながら、少し実装の中身も解説します。Nest.js でバックエンドを書かれている方の参考となれば嬉しいです。

最終的な状態

以下のような決定を最終的に行いました。

  • SendGrid をメール配信サービスとして利用しました
  • nest-modules/mailer を使ってメール配信用の Injectable なモジュールを作成し、必要な箇所でDIできるようにしました
  • メールのテンプレートは handlebars で記載し、必要な変数を呼び出し時に渡せるようにしました

技術選定の流れ

Nest.js と Google Cloud を使うところまでは確定で決定していたため、以下のような調査をすれば良い状況でした。

  1. Nest.js でどのようにメール配信機能を提供したら良いかを明らかにする
  2. Google Cloud で(手軽に)利用できるメール配信機能には何があるかを明らかにする
  3. (必要であれば)メールテンプレートを何で提供するかを決める

双方をある程度明らかにしていく過程で、Nest.js と Google Cloud のどちらにも相性の良いメール配信機能の選定が行えるという流れになります。

Nest.js でメール配信機能をどのように提供したら良いか

チームの中で一定調査がすでに行われていたこともあり、おおよそ nest-module/mailer を使うと提供が用意であろうとわかっていました。調査と言っておきながらなんですが、基本は nest-modules/mailer を使って実装していく方向で考えていくことになりました。

https://github.com/nest-modules/mailer

例えば、類似の記事で言うと以下が挙げられます。

https://zenn.dev/yuu104/articles/8b8d7363b5dd5f
https://myprg.dev/posts/nestjs-jsx-mail

他にもこの辺りで紹介されているような方法も見つけることができました。独自に Module を作って、その中でSDKを呼び出すような実装もいくつか見つけることができます。

https://zenn.dev/doshirote/articles/299796eec8ccae#nestjsで実装
https://iwaking.com/blog/how-to-send-emails-using-ejs-template-engine-with-nest-js

メールテンプレート

nest-module/mailer では3つのライブラリがテンプレート用に使えます。

こちらの選定には以下の記事を参考にし、Handlebars を選びました。Pug も魅力的でしたが、HTML が読めればわかるという点と、基本が Jinja など他のテンプレートエンジンと似ており他言語から参加される方にも容易なのではと想像されたためです。
https://gist.github.com/kazuma1989/e1a443b2ee28f012f0659594c302aa32

https://nest-modules.github.io/mailer/docs/mailer.html#configuration

Google Cloud でのメール配信機能について

一方で、Google Cloud の方は公式からメール配信について以下の3つのサービスが紹介されていました

Google Cloud で構築しているスタックは、アプリケーションを CloudRun にデプロイするだけというシンプルなものです。この機能のために追加の設定やリソースの作成を行うほど、手間をかけたくはありませんし運用もできません。ドキュメントを眺めている限りは

  • Mailjet
    • SMTPの設定をインスタンス内でする処理がCloudRunでどの程度通用するか検証が必要
  • Mailgun
    • Postfix でメールリレーとして Mailgun を利用するための設定を CloudRun でどの程度再現できるか不明
  • SendGrid
    • 公式のドキュメントを見る限りは、SendGrid のライブラリをインストールするだけですぐに使えそう

ということで、採用するメール配信サービスは SendGrid が濃厚となりました。

山本隼汰山本隼汰

実装していくにあたって

基本的には、以下の記事に紹介されているやり方を踏襲し実装されるのが一番スムーズです。nest-modules/mailer を用いた典型的な実装は網羅されており追加の説明は不要と思われます。

https://notiz.dev/blog/send-emails-with-nestjs

ここでは、上記を拡張して SendGrid を nest-module/mailer で利用する際に必要となる追加の設定を解説します。SendGrid でメールを配信するためには MailerModule の forRoot で定義する transport の host, port, auth の情報を SendGrid に対応できるよう修正する必要があります。これを行うことによって、nest-module/mailer から SendGrid を利用してメール配信ができるようになる、という流れです

https://www.twilio.com/ja-jp/blog/send-smtp-emails-node-js-sendgrid-jp

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

// jest の実行時に handlerbars の adapter が適切に動かない場合があるため対処を入れています
let adapter = null
if (!process.env.JEST_WORKER_ID) {
  import('@nestjs-modules/mailer/dist/adapters/handlebars.adapter').then(
    module => {
      adapter = module.HandlebarsAdapter
    },
  )
}

@Module({
  imports: [
    MailerModule.forRoot({
      // ↓のtransport 設定が重要
      transport: {
        host: 'smtp.sendgrid.net',
        port: 587,
        auth: {
          user: 'apikey',
          pass: process.env.SENDGRID_API_KEY,
        },
      },
      defaults: {
        from: process.env.SENDGRID_FROM_MAIL,
      },
      template: adapter
        ? {
            dir: __dirname + '/templates',
            adapter,
            options: {
              strict: true,
            },
          }
        : undefined,
    }),
  ],
})
このスクラップは2ヶ月前にクローズされました