【コード付】Firebase FunctionsでGmailを使ってメールを送信する方法

今回は、Firebase Functionsを用いて、Gmailを使って特定のメールアドレスに送信するための方法を紹介します。

トマトソース

スタックはTypeScriptとFirebase Functionsです。

Firebase Functionsのプロジェクトのセットアップ周りは、親切に解説してくださっているので以下の記事をご参考ください。(若干古いですが、だいたい今でも使えるはずです)

Qiita
Firebase で Cloud Functions を簡単にはじめよう - Qiita Cloud Functions for Firebase とはCloud Functions のラップのようなもので Firebase の各機能との連携が取りやすくなっているらしい。Fireba…

今回は、「nodemailer」を用いてのGmailの送信なので、Firebase Functionsのセットアップと合わせて、npmなりyarnなりでnodemailerもインストールしておいてください。

目次

実装コード

まず、今回実装したコードの全貌からお見せしておきます。

解説とかいらず、とりあえず動くものが欲しいという方は、ぜひコピペして適宜修正してください。

import { onRequest } from "firebase-functions/v2/https";
import { createTransport } from "nodemailer";

type EmailBodyParams = {
	subject: string;
	name: string;
	email: string;
	message: string;
};

const config = {
	FROM: "myEmail@gmail.com", // メール送信元
	TO: "receiver@email.com", // メール送信先
	SUBJECT: "HPにお問い合わせがありました", // メールタイトル
	MAIL_ACCOUNT: process.env.MAIL_ACCOUNT, // 後ほど説明
	MAIL_PASSWORD: process.env.MAIL_PASSWORD, // 後ほど説明
};

// corsのオリジン設定に使用
const ORIGIN = process.env.ORIGIN || "";

// メール本文用にリクエストボディを整形
const createEmailBody = ({
	subject,
	name,
	companyName,
	email,
	message,
}: EmailBodyParams): string => `
    お問い合わせ項目: ${subject}
    お名前: ${name}
    メールアドレス: ${email}
    お問い合わせ内容:
    ${message}
`;

// nodemailerでメール送信処理
const sendEmail = async (emailBody: string) => {
	const transporter = createTransport({
		service: "Gmail",
		auth: {
			user: config.MAIL_ACCOUNT,
			pass: config.MAIL_PASSWORD,
		},
	});

	const mailOptions = {
		from: config.FROM,
		to: config.TO,
		subject: config.SUBJECT,
		text: emailBody,
	};

	try {
		await transporter.sendMail(mailOptions);
		return "Sent";
	} catch (error: unknown) {
		if (error instanceof Error) {
			throw new Error(`Failed to send email: ${error.toString()}`);
		}
		throw new Error("Something went wrong...");
	}
};

// Firebase Functionsにデプロイする関数
export const sendMail = onRequest({ cors: ORIGIN }, async (req, res) => {

	const origin = req.headers.origin;
	if (origin !== ORIGIN) {
		res.status(403).send("Forbidden");
		return;
	}

	try {
		const emailBody = createEmailBody(req.body);
		const responseMessage = await sendEmail(emailBody);
		res.status(200).send(responseMessage);
	} catch (error) {
		if (error instanceof Error) {
			res.status(500).send(error.message);
		}
	}
});

では以下で、簡単にポイントを解説していきます。

コードの解説

ポイントと言ってもそこまでないんですが、コードだけでは若干わかりづらい部分を解説していきます。

環境変数

まずは環境変数の以下の部分です。

	MAIL_ACCOUNT: process.env.MAIL_ACCOUNT
	MAIL_PASSWORD: process.env.MAIL_PASSWORD

これはnodemailerでのGmail送信に必要なキーで、GoogleのアカウントのメールアドレスとAppパスワードを設定しておきます。

ここで注意なのは、Googleアカウントのログインパスワードではなく、Appパスワードという少し特殊なパスワードを用いる点です。「rfds gdsa yuei ohgs」みたいな感じのやつです。

アプリパスワードをどこから見つけて良いかわからない方は、以下をご参考ください。

Qiita
Googleのアプリパスワード(App passwords)が見つからない時の対処法 - Qiita TypeScriptのNodemailerモジュールを使ってGmailを送る処理を実装する際にGoogleアカウントのアプリパスワードなるものが必要になりました。でも、一般的な方法(こことか...
トマトソース

環境変数の置き場所などは、.envファイルを作るなりして、対応してください。

nodemailerの初期化

以下の部分でnodemailerの初期化を行なっています。

const transporter = createTransport({
		service: "Gmail",
		auth: {
			user: config.MAIL_ACCOUNT,
			pass: config.MAIL_PASSWORD,
		},
	});

serviceにGmailを指定し、authには上記で解説したGoogleのアカウントとAppパスワードを設定します。

トマトソース

Gmail以外にもYahooやiCloudなどもあるようなので、場合によって使い分けできそうですね。

Nodemailer
Well-known services Nodemailer knows SMTP connection details for several well known providers. If your provider is listed here you do not need to set the connection details yoursel...

メール本文の整形

以下で、メール本文として送信する内容をきれいに整えています。

const createEmailBody = ({
	subject,
	name,
	email,
	message,
}: EmailBodyParams): string => `
    お問い合わせ項目: ${subject}
    お名前: ${name}
    メールアドレス: ${email}
    お問い合わせ内容:
    ${message}
`;

自分の場合、req.bodyとして以下の4つをJSON形式で送信してきています。

  • subject:お問い合わせ項目
  • name:お問い合わせ者の名前
  • email:お問い合わせ者のメールアドレス
  • message:お問い合わせ内容
トマトソース

そのままだと、味気ないのでcreateEmailBody関数でメールで表示される際にきれいになるようにしています。

メール送信

メールの送信は、以下のように初期化したnodemailerを使って行えます。

const mailOptions = {
		from: config.FROM,
		to: config.TO,
		subject: config.SUBJECT,
		text: emailBody,
};
await transporter.sendMail(mailOptions);
トマトソース

簡単ですね。

解説は以上になります。

私が記述したやり方以外にも、エラーハンドリングを足したり、セキュリティを高めたりする方法はあるかと思いますので、必要に応じて修正してみてください。

フロント側でCORSの問題が出る場合

上記の実装で作ったお問い合わせ送信機能をフロントエンドから呼び出した場合に、CORSエラーが出ることがあります。

結論、レスポンスにset('Access-Control-Allow-Origin', '*')をセットするか、ブラウザのキャッシュをクリアすれば、解決します。

詳しくは以下をご覧ください。

Qiita
Firebase FunctionsとGatsbyのCORS問題 - Qiita Gatsbyで作った静的サイトでのお問い合わせフォーム送信にFirebase Functionsを用いて実装した際に、CORSエラーが出て無駄に詰まったので、解決策を残しておこうと思います...

まとめ

今回は、Firebase Functionsを用いてGmailでメール送信をする実装についてお伝えしました。

Firebase Functionsだとかなり楽にそして無料(無料枠の範囲内であれば)なので、サイトのお問い合わせフォームをちゃちゃっと実装したい時なんかには、良いかもしれませんね。

ご参考になれば幸いです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次