👋

Vercelでメール送信フォームを作る

に公開

概要

Webサイトからメールを送信するには、どのような方法があるでしょうか?
一般的にはサーバーを構築したり、メール送信ライブラリを利用したりするケースが多いと思います。
今回はVercelの「サーバーレス関数」機能を使って、Node.jsでメールを送信する方法をご紹介します。

サーバーレス関数とは

サーバーレス関数とは、サーバー構築や管理を気にせずにAPIエンドポイントを簡単に作成できる仕組みです。
この機能を活用して、Node.jsのnodemailerライブラリを使ってメール送信を行います。

セットアップ

今回はフレームワークなどは使わず、素のHTMLとJavaScriptで実装をします。
もちろんReactやNext.jsなどのフレームワークでも同様の構成が可能ですので、必要に応じて調整してください。

nodemailerのインストール

nodemailerは、Node.jsでメールを送信するためのライブラリで、広く利用されています。

npm init -y
npm install nodemailer

メールサーバーの用意

メールの送信には、SMTPサーバーの設定が必要です。
手軽な方法としては、GmailのSMTPサーバー(smtp.gmail.com)を利用するのが一般的です。
この方法なら、自前でメールサーバーを構築する必要はなく、nodemailerで簡単に送信できます。
アプリパスワードの生成はこちら

サーバーレス関数の用意

Vercelでは、プロジェクト直下にapiフォルダを作成することで、サーバーレス関数を定義できます。

雛形

例として、api/contact.jsに以下のように記述します。

api/contact.js
const nodemailer = require("nodemailer");

export default async function handler(req, res) {
    if(req.method !== "POST") return res.status(405).end();

    // フォームから送信されたデータを取得
    const { name, email, message } = req.body;

    if (!message) return res.status(400).json({ error: "不正なリクエストです。" });

    // nodemailerの設定はこの下に記述します。
}

トランスポートの設定

メール送信に使用するSMTPサーバーの情報を設定します。

const transporter = nodemailer.createTransport({
    host: process.env.SMTP_HOST, // どのホストを使うか
    port: Number(process.env.SMTP_PORT), // どのポートを使うか
    secure: true, // ポート465を使用する場合はtrue
    auth: {
      user: process.env.SMTP_USER, // 認証元のアカウント
      pass: process.env.SMTP_PASS, // アプリパスワード
    },
});

メール送信処理

try {
    await transporter.sendMail({
      from: `"${name}"`, // 送り主の名前
      to: process.env.RECEIVER_EMAIL, // どこに送るか
      subject: `お問い合わせ`, // 件名
      text: email + "\n\n" + message, // 本文
    });
    res.status(200).send("送信完了");
  } catch (err) {
    console.log(err);
    res.status(500).send("送信失敗");
  }

これでapi/contactにPOSTリクエストを送ることで、メール送信が可能になります。

.envの内容

パスワードなどの機密情報は、.envファイルに記述して環境変数として管理します。

SMTP_HOST=smtp.gmail.com // メールサーバーのホスト
SMTP_PORT=465 // サーバーのポート
SMTP_USER=xxxx@gmail.com // 認証元のアカウント
SMTP_PASS=xxxx // 生成したアプリパスワード
RECEIVER_EMAIL=xxxx@gmail.com // 受け取るアカウント

SMTP_USERとRECEIVER_EMAILは同じでも構いませんが、役割が異なるため分けるのが望ましいです。 Gmailでは「+記法」を使うことで、同じ受信箱に届きつつラベル管理がしやすくなります。

RECEIVER_EMAIL=xxxx+contact@gmail.com

この場合、SMTP_USERも同じアドレス(xxxx@gmail.com)を使用してください。

フロントエンドの実装

例として以下のようなフォームを用意しました。必要に応じてスタイルを調整してください。

contct.html
<form id="contactForm">
      <label for="name">お名前</label>
      <input type="text" name="name" placeholder="お名前" />
      <label for="email">メールアドレス</label>
      <input type="email" name="email" placeholder="メールアドレス" />
      <label for="message">お問い合わせ内容</label>
      <textarea name="message" placeholder="お問い合わせ内容" required></textarea>
      <button type="submit" class="form-btn">送信</button>
</form>

JavaScriptでフォーム送信処理をします。

document.getElementById("contactForm").addEventListener("submit", async (e) => {
    e.preventDefault(); // ページリロードを防止
    const formData = new FormData(e.target);
    const data = Object.fromEntries(formData.entries());

    // APIにPOSTリクエストを送信
    const res = await fetch("/api/contact", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });

    // レスポンスに応じてアラート表示
    if (res.ok) {
      alert("送信完了しました!");
    } else {
      alert("送信に失敗しました。");
    }
});

まとめ

以上でVercel上で完結するメール送信機能の実装ができました。
外部サービスに依存しないため、未使用時にサービスが停止して使えなくなる心配もありません。
apiフォルダに配置するだけで簡単なので、小規模なプロジェクトでも手軽に導入ができます。
管理の手間やコストがほとんどかからないのも大きなメリットです。

本記事では基本的な構成について紹介しましたが、セキュリティ対策や送信ログの保存など、より高度な実装については各自で試行錯誤してみてください。

ではまた。

Discussion