社会人から始めたプログラミング

プログラミング、エンジニアに関することでの備忘録、シェアしたい情報などを共有するためのブログです。

firebase google functions に SendGrid を使ってメール送信設定する(Custom SMTP)

やりたいこと

下記の流れを滞りなく一度に済ませたい

 ・ユーザーのアカウントを Firebase Auth に作成
 ・ユーザー情報を realtime database にも保存
 ・認証メールを送る

課題

上記の処理をクライアント側で実装していたが、 行っている途中でネットワークが切れたり何らかの理由で処理が中断されると、 どこまで処理を行っていたかがわからず、ユーザーへの対応が適切に行えない。

解決方法

・サーバー側にログが残るように firebase cloud functions にメソッドを移行。

・クライアントの状況によって(ネット接続が切れたり、なんらかの原因で処理が止まること)処理が途中で意図せず止まることがなくなる

詳細

概要

firebase cloud functions には client側で使えてた sendEmailVerification はないので、(firebase admin adk)カスタム SMTP の設定を行う。 今回、SMTPサーバはSendGridを使用する。やりたいことの流れで他の部分は色んな所に書いてあるので、「認証メールを送る」のみ詳細をここに記述する。

SendGridの環境を準備

 ・本家、または日本版にアカウントを作成(日本語版のほうが無料でメール数が多いが、少し作るのに時間がかかった)

 ・メールテンプレートを作成

 ・アクセスするための API key を作成

 ・firebase cloud function に APIをセット

  `firebase functions:config:set sendgrid.api="作成したSendGridのAPI KEY"`

 

firebase cloud function にメソッドを準備

メソッドの例

async function sendCustomVerificationEmail (params) {
  const email = params.email || 'emailがないときになにか入れたかったら'
  const displayName = params.display_name || 'no name'
  const link = params.link || 'verification email の linkがなかったときのurlなど必要であれば'
  const funcs = functions
  const msg = {
    templateId: 'xxxxxxxx作成したメールテンプレートのIDxxxxxxxx',
    to: email,
    from: "no-reply@どこからメールが来たか",
    dynamic_template_data: {
      display_name: "メールのテンプレートに埋め込みたい値(テンプレートの{{display_name}}の部分に入る)",
      link: link
    }
  }
  const config = functions.config()
  const sendgridapi = config.sendgrid.api
  // firebase configでセットされた値を参照する。
  sgMail.setApiKey(
    sendgridapi
  )
  return new Promise(function(resolve, reject) {
    sgMail.send(msg)
      .then((result) => {
        const message = '認証確認メールが送られました。'
        funcs.logger.log('verification email sent:', message)
        resolve(message)
        return message
      })
      .catch((err) => {
        reject(new funcs.https.HttpsError('error', err))
      })
  })
}

呼んでいるところの例

// userRecordにはauth のデータが入ってくる前提。
admin.auth()
  .generateEmailVerificationLink(userRecord.email)
     .then((link) => {
       const params = {
         email: userRecord.email,
         display_name: displayName,
         link: link
       }
      sendCustomVerificationEmail(params)
        .then()
        .catch()
      return link
    })
              
おまけ

単体で呼ぶ場合 こんな感じで function を定義して

exports.sendVerificationEmail = functions.https.onCall((data, context) => {
  const email = data.email
  const password = data.password
  const displayName = data.display_name
  // ... 呼んでいるところの例 みたいにすれば認証メールが飛ばせる
})

こんな感じで呼んであげれば(web jsで呼ぶサンプル)

const sendVerificationEmail = firebase.functions().httpsCallable(`sendVerificationEmail`)
sendVerificationEmail({
  email: "実在するemailアドレス",
  password: 'パスワードを入力',
  display_name: 'テストのユーザーさん'
})
  .then(function (result) {
    console.log('done', result)
  })
  .catch(function (error) {
    console.log('error', error)
   })

テストできます。

リンク

functions:config について詳細 firebase.google.com

SnedGrid本家: 

sendgrid.com

日本版:

sendgrid.kke.co.jp