Resend:Email
2026年2月12日メール
Cloudflare等ではメール専用の「MXレコード」というのを設定できるが、それだけでは足りずメール送信のためのSMTPサーバーが必要になる。
SMTPサーバーは送受信しか出来ないので受信ボックスや閲覧の役割は他のメールサーバープロトコルが必要になり、有料のメールサーバー(例:Google Workspace)はそれを備えている。
ResendはSMTPサーバーの機能、つまり配送のみできる。
仕組みとしてはアプリ側からAPIで受け取ったデータをResendがメール形式に整形し、SMTPでGmail等に配送する。
始める
Vercelの場合インテグレーションからResendを追加できる
フリープランは 3000通/月 & 1ドメイン
mail用のサブドメインを作成
Cloudflareダッシュボードから DNS/レコードの追加:
タイプ:MX
名前:サブドメイン(例:
mail、info)コンテンツ:ドメイン(
xxx.com)@と入力すると自動で
xxx.comに切り替わる
Resendに登録
SidebarのDomainsからメール用に作成したサブドメインを追加(
info.xxx.com)オンライン(緑)のリージョンを選択
Cloudflareにリダイレクトされ3つのフィールドが追加される
Resendが自動で作成したことをコメントとして残すと良い
環境変数
RESEND_API_KEY="xxxxxxxx"
RESEND_FROM="Github Actions 実行通知 <info@mail.xxx.com>"<> の左側はGmailの各メールで一番目立つ部分(メイン)に表示され、日本語が使える。この部分がないとエラーになる。
<> と左側の日本語を消しメールアドレスだけにするとエラーにはならない。その場合Gmailのメイン部分には@の手前( 例:
info)が表示される
*<>内は@より前の部分(上記の場合
info@)が無いとGmail側で受信時にフィルターに引っかかる。Postman側ではメール送信が成功しているメッセージが出るのでGmail側のフィルターの可能性が高い
info@の部分は日本語にするとエラーになる
送信関数
"use server";
import { Resend } from "resend";
export const sendNotification = async () => {
try {
const apiKey = process.env.RESEND_API_KEY!;
if (!apiKey) {
console.error("Missing RESEND_API_KEY");
return { success: false, message: "Server error." };
}
const resend = new Resend(apiKey);
await resend.emails.send({
from: process.env.RESEND_FROM!,
to: "xxxxx@gmail.com",
subject: "Resend test",
react: EmailTemplate(),
});
return { success: true, message: "通知が送信されました。" };
} catch (error) {
console.error("Delete notification error:", error);
throw new Error("Failed to send delete notification");
}
};表示するのがシンプルなテキストの場合、
react:の部分をhtml: 'message from resend',のようにする
EmailTemplate.tsx:
import React from "react";
const EmailTemplate = () => {
return (
<div>
<h1 style={{ fontSize: "24px", fontWeight: "bold", color: "green" }}>
corporis fuga dolorum quidem repudiandae, et odit ab fugit hic error.
</h1>
<hr />
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit
</p>
</div>
);
};
export default EmailTemplate;tailwindクラスは反映されないのでインラインスタイルで書く。CSSファイルはロードされない。
Nextjsの
<Image />を入れるとメール本文が白紙になる<img />のURLは絶対URLにする
実用的な例
Github Actionsの通知
route.ts:
import EmailTemplate from "@/app/EmailTemplate";
import { NextRequest, NextResponse } from "next/server";
import { Resend } from "resend";
export async function POST(req: NextRequest) {
if (req.headers.get("x-api-key") !== process.env.GITHUB_ACTIONS_CRON_KEY) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
console.log("Cron job running!");
const resend = new Resend(process.env.RESEND_API_KEY);
const data = await resend.emails.send({
from: process.env.RESEND_FROM!,
to: "xxxxx@gmail.com",
subject: "✅ Github Actions DONE",
react: EmailTemplate(),
});
return NextResponse.json({ status: "ok", data });
} catch (error) {
return NextResponse.json({ status: "ok", error }, { status: 500 });
}
}メソッドはPOST
formの通知
"use server";
import { Resend } from "resend";
export const sendEmail = async (
prev: { success: boolean | null; message: string },
formData: FormData
): Promise<{ success: boolean; message: string }> => {
try {
const apiKey = process.env.RESEND_API_KEY!;
const from = process.env.RESEND_FROM!;
if (!apiKey) {
console.error("Missing RESEND_API_KEY");
return { success: false, message: "Server error." };
}
if (!from) {
console.error("Missing RESEND_FROM");
return { success: false, message: "Server error." };
}
const resend = new Resend(apiKey);
const data = {
name: formData.get("name"),
email: formData.get("email"),
message: formData.get("message"),
};
await resend.emails.send({
from,
to: "xxxx@gmail.com", // 自分のEmail
subject: `${data.name}からのメッセージ`,
html: `
<p><strong>送信者名:</strong> ${data.name}</p>
<p><strong>メールアドレス:</strong> ${data.email}</p>
<p>${data.message}</p>
`,
});
return { success: true, message: "送信が完了しました。" };
} catch (error) {
console.error("Contact form error:", error);
return { success: false, message: "送信中にエラーが発生しました。" };
}
};