【Next.js】メールフォームをFirebase Functionsで実装

f:id:nekorokkekun:20191029154326p:plain:w1000
今回は、Next.jsとFirebase Functionsを用いて、お問い合わせフォームを実装していきます。

Firebase側の実装

Firebaseとの接続を行います。

lib/db.js

import firebase from 'firebase/app'
import 'firebase/firestore'
import "firebase/auth";

let db;
try {
  const config = {
        apiKey           : xxxxxxxxxxxxxxxxxxxx,
        authDomain       : xxxxxxxxxxxxxxxxxxxx,
        databaseURL      : xxxxxxxxxxxxxxxxxxxx,
        projectId        : xxxxxxxxxxxxxxxxxxxx,
        storageBucket    : xxxxxxxxxxxxxxxxxxxx,
        messagingSenderId: xxxxxxxxxxxxxxxxxxxx,
        appId            : xxxxxxxxxxxxxxxxxxxx
    };
    if (!firebase.apps.length) {
      firebase.initializeApp(config);
    }
    // Firestoreインスタンスを作成
    db = firebase.firestore();
  } catch (error) {
    console.log(error);
}

let auth = firebase.auth();
const firestore = firebase.firestore();

module.exports = {
  // 本来、initializeAppによる初期化は一度きりのため、
  // 初期化の結果のみを切り出してexportする
  db,
  auth,
  firebase,
  firestore
};

Firerbase接続に関して、詳しくは以下をご覧ください。
nekorokkekun.hatenablog.com

Firebase Functionsの設定

ルートディレクトリにfunctionsディレクトリを作成します。

次にメーラーをインストールしましょう。

$ yarn add nodemailer
$ yarn install

そして、Firebase Functionsの環境変数に、問い合わせを受信するメールアドレスやパスワード、管理者のメールアドレスを設定しましょう。

$ firebase functions:config:set gmail.email="xxxxxx@gmail.com" gmail.password="xxxxxx" admin.email="xxxxxx@gmail.com"

最後にFirebase Functionsを実装します。
functions/index.js

const nodemailer = require("nodemailer");
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;
const adminEmail = functions.config().admin.email;

// メールサーバー設定
const mailTransport = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: gmailEmail,
    pass: gmailPassword
  }
});

// 管理者用のメールテンプレート
const adminContents = data => {
  return `以下内容でホームページよりお問い合わせを受けました。

お名前:
${data.name}

メールアドレス:
${data.email}

内容:
${data.content}
`;
};

exports.sendMail = functions.https.onCall((data, context) => {
  // メール設定
  let adminMail = {
    from: gmailEmail,
    to: adminEmail,
    subject: "ホームページお問い合わせ",
    text: adminContents(data)
  };

  // 管理者へのメール送信
  mailTransport.sendMail(adminMail, (err, info) => {
    if (err) {
      return console.error(`send failed. ${err}`);
    }
    return console.log("send success.");
  });
});

最後に実装したFirebase FunctionsをFIrebaseにデプロイします。

$ yarn deploy

フロント側の実装

以下の記事からそのままお借りしました。
[firebase] Cloud Functionsを利用したお問い合わせ機能の実装 [react.js] - Qiita

import React, { Component } from 'react';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button'

import {firebase} from '../lib/db.js';
require("firebase/functions");

class ContactForm extends Component {
  constructor(){
    super()
    this.onSubmit = this.onSubmit.bind(this)
  }

  onSubmit(e){
    e.preventDefault()
    let data = {}
    data.name = e.target.name.value
    data.email = e.target.email.value
    data.content = e.target.content.value
    let sendMail = firebase.functions().httpsCallable('sendMail');
    sendMail(data)
    e.target.name.value = ""
    e.target.email.value = ""
    e.target.content.value = ""
    e.target.value = ""
  }

  render() {
    const textFieldStyle = {
      display: "flex",
      width: "300px",
    }

    const contactForm = {
      display: "flex",
      flexDirection: "column", 
      alignItems: "center",
      marginTop: "100px",
    }


    return (
      <React.Fragment>
        <div style={contactForm}>
          <h2>お問い合わせ</h2>
          <form onSubmit={this.onSubmit}>
            <TextField name="name" label="お名前" type="text" required style={textFieldStyle}  />
            <TextField name="email" label="メールアドレス" type="mail" required style={textFieldStyle}   />
            <TextField
              required
              name="content"
              label="お問い合わせ内容"
              multiline
              rows="8"
              margin="normal"
              variant="outlined"
              style={textFieldStyle} 
            />
            <Button variant="contained" color="primary" type="submit" style={textFieldStyle} >
              送信
            </Button>
          </form>
        </div>
      </React.Fragment>
    )
  }   
}

export default ContactForm

これで実際に、設定したメールアドレスへ問い合わせたメールの内容が届くはずです。

Firebase Functionsにエラーが出る場合

以下のようなエラーが出て悩まされました。

send failed. Error: Invalid login: 534-5.7.14 
<https://accounts.google.com/signin/continue?sarp=1&scc=1&plt=xxxxxxxxxxx>
Please log in via your web browser and then try again.
Learn more at
https://support.google.com/mail/answer/78754 h16sm1466164ilq.18 - gsmtp

私の場合は、以下のリンクを踏み、アクセスを有効にすることで、メールが届くようになりました。
accounts.google.com