ブログ一覧へ

Resendでお問い合わせフォームの自動返信を実装する

この記事は「WebデザイナーがAIに食われてみた」の関連記事です。

はじめに

コーポレートサイトやポートフォリオに「お問い合わせフォーム」は必須です。でも、フォームから送信されたデータをメールで受け取るのは、意外とハードルが高い作業でした。

従来は、PHPで mail() 関数を使ったり、SMTPサーバーを設定したり、SendGridのようなサービスを契約したり。

Resendを使えば、数行のコードでメール送信ができます。しかも月3,000通まで無料。

この記事では、Next.jsのお問い合わせフォームにResendを使って「自動返信メール」を実装する方法を解説します。

Resendとは

ひとことで

「APIでメールを送れるサービス」です。

なぜ普通にメールを送れないのか

ブラウザのJavaScriptから直接メールを送ることはできません。メール送信にはサーバーが必要です。

ブラウザ → JavaScriptでメール送信 ❌(できない)
ブラウザ → サーバーのAPI → Resend → メール送信 ✅

Next.jsにはAPIルートという仕組みがあり、サーバー側のコードを書けます。ここからResendのAPIを呼ぶことで、メールが送れます。


全体の仕組み

ユーザーがフォームに入力
  ↓
送信ボタンをクリック
  ↓
Next.jsのAPIルート(/api/contact)にリクエスト
  ↓
APIルート内でResend APIを呼ぶ
  ↓
① 管理者宛に通知メール(「お問い合わせがありました」)
② ユーザー宛に自動返信メール(「お問い合わせを受け付けました」)

セットアップ

1. Resendアカウントの作成

resend.com でアカウントを作成します。

2. APIキーの取得

ダッシュボードの「API Keys」からキーを発行します。このキーは一度しか表示されないので、すぐに .env.local に保存してください。

RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxx
CONTACT_EMAIL=your-email@example.com

3. ドメインの設定(本番運用時)

無料プランでも独自ドメインからメールを送れます。ダッシュボードの「Domains」からドメインを追加し、DNSレコードを設定します。

ドメイン設定前は onboarding@resend.dev からしか送信できません。

コードの実装

APIルート

// src/app/api/contact/route.js
import { Resend } from "resend";

function getResend() {
  return new Resend(process.env.RESEND_API_KEY);
}

export async function POST(request) {
  try {
    const { name, email, company, message } = await request.json();
    const resend = getResend();

    // バリデーション
    if (!name || !email || !message) {
      return Response.json(
        { error: "必須項目を入力してください。" },
        { status: 400 },
      );
    }

    // 1. 管理者への通知メール
    await resend.emails.send({
      from: "コツモ <noreply@kotsumo.com>",
      to: process.env.CONTACT_EMAIL,
      subject: `【お問い合わせ】${name}様`,
      html: `
        <h2>お問い合わせがありました</h2>
        <p><strong>お名前:</strong> ${name}</p>
        <p><strong>メール:</strong> ${email}</p>
        <p><strong>会社名:</strong> ${company || "未入力"}</p>
        <p><strong>内容:</strong></p>
        <p>${message}</p>
      `,
    });

    // 2. ユーザーへの自動返信
    await resend.emails.send({
      from: "コツモ <noreply@kotsumo.com>",
      to: email,
      subject: "【コツモ】お問い合わせを受け付けました",
      html: `
        <p>${name} 様</p>
        <p>お問い合わせいただきありがとうございます。</p>
        <p>内容を確認の上、2営業日以内にご連絡いたします。</p>
        <hr />
        <p><strong>お問い合わせ内容:</strong></p>
        <p>${message}</p>
      `,
    });

    return Response.json({ success: true });
  } catch (error) {
    console.error("Contact API error:", error);
    return Response.json(
      { error: "メールの送信に失敗しました。" },
      { status: 500 },
    );
  }
}

なぜ getResend() 関数を使うのか

// ❌ これだとビルド時にエラーになる
const resend = new Resend(process.env.RESEND_API_KEY);

// ✅ 関数にすることで、実際にAPIが呼ばれたときだけ実行される
function getResend() {
  return new Resend(process.env.RESEND_API_KEY);
}

Vercelでビルドする際、モジュールのトップレベルのコードは実行されます。ビルド環境には環境変数が設定されていないことがあるため、関数にして遅延実行させます。

実際にこのサイトでも、最初はトップレベルで書いていてビルドに失敗しました。

フォームコンポーネント(簡略版)

"use client";
import { useState } from "react";

export default function ContactForm() {
  const [status, setStatus] = useState("idle");

  const handleSubmit = async (e) => {
    e.preventDefault();
    setStatus("sending");

    const formData = new FormData(e.target);
    const data = Object.fromEntries(formData);

    const res = await fetch("/api/contact", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data),
    });

    if (res.ok) {
      setStatus("success");
    } else {
      setStatus("error");
    }
  };

  if (status === "success") {
    return <p>送信しました。自動返信メールをご確認ください。</p>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="お名前" required />
      <input name="email" type="email" placeholder="メールアドレス" required />
      <input name="company" placeholder="会社名(任意)" />
      <textarea name="message" placeholder="お問い合わせ内容" required />
      <button type="submit" disabled={status === "sending"}>
        {status === "sending" ? "送信中..." : "送信する"}
      </button>
    </form>
  );
}

"use client" はNext.jsに「このコンポーネントはブラウザで動く」と伝えるための宣言です。フォームの状態管理(useState)はブラウザ側の機能なので必要です。

無料プランの制限

項目制限
月間送信数3,000通
送信レート1日100通
ドメイン1つ

テストするには十分ですね。

まとめ

やること説明
Resendアカウント作成resend.com で登録
APIキー取得.env.local に保存
ドメイン設定DNSレコードを追加
APIルート作成/api/contact にメール送信ロジックを書く
フォーム作成fetch でAPIを呼ぶクライアントコンポーネント

少ない手間で「通知メール + 自動返信」が実現できます。

📖 メインの記事に戻る → WebデザイナーがAIに食われてみた