今回は、Firebase Functionsを用いて、Gmailを使って特定のメールアドレスに送信するための方法を紹介します。
スタックはTypeScriptとFirebase Functionsです。
Firebase Functionsのプロジェクトのセットアップ周りは、親切に解説してくださっているので以下の記事をご参考ください。(若干古いですが、だいたい今でも使えるはずです)
今回は、「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」みたいな感じのやつです。
アプリパスワードをどこから見つけて良いかわからない方は、以下をご参考ください。
環境変数の置き場所などは、.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などもあるようなので、場合によって使い分けできそうですね。
メール本文の整形
以下で、メール本文として送信する内容をきれいに整えています。
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', '*')
をセットするか、ブラウザのキャッシュをクリアすれば、解決します。
詳しくは以下をご覧ください。
まとめ
今回は、Firebase Functionsを用いてGmailでメール送信をする実装についてお伝えしました。
Firebase Functionsだとかなり楽にそして無料(無料枠の範囲内であれば)なので、サイトのお問い合わせフォームをちゃちゃっと実装したい時なんかには、良いかもしれませんね。
ご参考になれば幸いです。