やりたいこと
下記の流れを滞りなく一度に済ませたい
・ユーザーのアカウントを 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本家:
日本版: