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に食われてみた