Webサービスの開発において、切っても切り離せないのが「メール送信機能」です。
しかし、多くのエンジニアにとってHTMLメール開発はできれば避けて通りたい苦行の筆頭ではないでしょうか。
- 「20年前のホームページか?」と思うような
<table>タグのネスト地獄 - インラインで地道に書き込むCSS
- OutlookやGmailアプリで容赦なく崩れるデザイン
- 本番送信するまで仕上がりがわからない開発フィードバックの遅さ
本記事では、これらの悪夢をすべて過去のものにする Next.js + React Email + SendGrid を組み合わせた「コンポーネント指向」の超高速メール開発環境の構築方法を解説します。
さらに、この記事では実際の運用で直面した「メーラーごとの表示崩れ」とその解決策についても余すことなくシェアします。
メール開発を支える3つの柱
今回構築するアーキテクチャの主役たちです。
- React Email: ReactコンポーネントでHTMLメールを記述できるライブラリ。Tailwind CSSも使え、ローカルで爆速のプレビュー環境が立ち上がります。
- SendGrid: 高い到達率と信頼性を誇る、世界最大級のメール配信プラットフォーム。豊富なAPIと強力なWebhook機能を備え、本番環境の配信インフラとして盤石の選択肢です。
- Next.js (App Router): Route Handlerを使って、React Emailで生成したHTMLをSendGrid API経由で送信するサーバーサイドの配信処理を構築します。
開発・送信のアーキテクチャ
Step 1: React Emailの導入と爆速プレビュー環境の構築
まずは既存のNext.jsプロジェクト、あるいは新規プロジェクトにReact Emailを導入します。
1. インストール
プロジェクトのルートディレクトリで以下のコマンドを実行します。
npm install @react-email/components @react-email/render -S
npm install react-email -D
2. 初期化とプレビューサーバーの起動
package.jsonの scripts にプレビュー用のコマンドを追加します。
{
"scripts": {
"dev:email": "email dev -p 3001"
}
}
コマンドを実行して、プレビュー環境を起動します。
npm run dev:email
ブラウザで http://localhost:3001 にアクセスすると、React Emailのダッシュボードが表示されます。デフォルトで emails ディレクトリが自動作成され、そこにサンプルコードが生成されます。
Step 2: Reactコンポーネントでメールをデザインする
では、実際にコンポーネントを作成してみましょう。React Emailでは、@react-email/components から提供される専用のラッパーコンポーネントを使用します。また、Tailwind CSSも標準サポートされています。
emails/WelcomeEmail.tsx を以下のように作成します。
import {
Body,
Button,
Container,
Head,
Heading,
Hr,
Html,
Img,
Preview,
Section,
Text,
Tailwind,
} from "@react-email/components";
import * as React from "react";
interface WelcomeEmailProps {
username: string;
}
export const WelcomeEmail = ({ username = "ゲスト" }: WelcomeEmailProps) => {
return (
<Html>
<Head />
<Preview>サービスへようこそ!アカウント登録が完了しました</Preview>
<Tailwind
config={{
theme: {
extend: {
colors: {
brand: "#4F46E5",
},
},
},
}}
>
<Body className="bg-gray-50 my-auto mx-auto font-sans">
<Container className="border border-solid border-[#e8e8e8] rounded my-[40px] mx-auto p-[20px] max-w-[465px] bg-white shadow-sm">
<Section className="mt-[32px] text-center">
<Img
src="https://your-domain.com/static/logo.png" // 本番環境のアセットURL
width="40"
height="40"
alt="Logo"
className="my-0 mx-auto"
/>
</Section>
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
Welcome to <strong>Our Platform</strong>!
</Heading>
<Text className="text-black text-[14px] leading-[24px]">
こんにちは、{username} 様
</Text>
<Text className="text-gray-600 text-[14px] leading-[24px]">
アカウントのご登録ありがとうございます。私たちはあなたのビジネスを加速させるための最適なツールを提供します。さっそくダッシュボードにアクセスして始めましょう!
</Text>
<Section className="text-center mt-[32px] mb-[32px]">
<Button
className="bg-brand rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
href="https://your-domain.com/dashboard"
>
ダッシュボードを開く
</Button>
</Section>
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
<Text className="text-[#666666] text-[12px] leading-[24px]">
このメールに心当たりがない場合は、お手数ですが無視してください。
</Text>
</Container>
</Body>
</Tailwind>
</Html>
);
};
export default WelcomeEmail;
React Emailの何が革新なのか?
-
Hot Reload: コードを書き換えた瞬間、
localhost:3001のプレビューに即座にで反映されます。 -
Propsの書き換えテスト: ダッシュボードの右側パネルから、
usernameなどのPropsをブラウザ上で自由に入力して、表示の変化をテストできます。 - HTML/プレーンテキスト両対応: 自動的にテキスト版のメールも生成・確認できます。
Step 3: Next.js + SendGrid API で送信APIを構築する
次に、作成したReactコンポーネントを本番環境から送信するサーバーサイドの実装を行います。メール配信には、信頼の SendGrid を使用します。
1. SendGrid SDKのインストール
npm install @sendgrid/mail
2. 環境変数の設定
SendGridダッシュボードでAPIキーを作成し、.env.local に追加します。また、送信元ドメインの認証(Sender Authentication)を事前に済ませておきます。
SENDGRID_API_KEY=SG.xxxxxxxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3. Route Handlerの実装 (Next.js)
app/api/send/route.ts を作成します。
React Emailのコンポーネントを @react-email/render の render 関数を使ってHTML文字列に変換し、それを SendGrid の html プロパティに渡して送信します。
import { NextResponse } from "next/server";
import sgMail from "@sendgrid/mail";
import { render } from "@react-email/render";
import { WelcomeEmail } from "@/emails/WelcomeEmail";
import React from "react";
// APIキーを設定
sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
export async function POST(request: Request) {
try {
const { email, username } = await request.json();
// 1. React Email コンポーネントを HTML 文字列にレンダリング
const emailHtml = await render(
React.createElement(WelcomeEmail, { username })
);
// 2. SendGridの送信パラメータを設定
const msg = {
to: email,
from: "info@yourdomain.com", // SendGridで認証済みの送信元アドレス
subject: "アカウント登録完了のお知らせ",
html: emailHtml,
// 必要に応じてテキストのフォールバックも設定可能
text: `こんにちは、${username}様。アカウント登録が完了しました。`,
};
// 3. 送信実行
await sgMail.send(msg);
return NextResponse.json({ message: "Email sent successfully via SendGrid" });
} catch (err: any) {
console.error("SendGrid Error:", err.response?.body || err.message);
return NextResponse.json(
{ error: err.response?.body || err.message },
{ status: 500 }
);
}
}
これでNext.jsとSendGridが完全に繋がりました!React Emailによる最高の開発体験(DX)を維持しながら、本番配信はSendGridの堅牢なインフラに委ねる、理想的な設計です。
運用で直面した「表示崩れ」と、その回避策
「React Emailでローカルプレビューもバッチリだし、これでHTMLメール開発は完全勝利だ!」
...そう思った時期が私にもありました。
いざ本番運用を開始し、様々なデバイス・メーラーで受信テストを行うと、ローカルプレビュー(ブラウザ)では完璧だったデザインが容責なく崩れました。
ここからは、「メーラーごとの表示崩れ」の具体的な原因とハックを共有します。
1. Outlook(Windowsデスクトップ版)の「Wordレンダリングエンジン」
Windowsのデスクトップ版Outlookは、HTMLのレンダリングにブラウザエンジンではなく Microsoft Word を使用しています。このため、CSSの近代的な機能がほぼ全滅します。
-
バグ①:
border-radius(角丸)が無視され、ボタンが角張る- 対策: Outlookで完全に角丸を再現するには、VML(Vector Markup Language)という太古のマークアップを埋め込む必要があります。しかし複雑になるため、多くの場合は「丸みのない四角いボタンになる仕様」として割り切るか、ボタン自体を「画像」として配置するかのトレードオフになります。
-
バグ②:
flexやgridが一切効かない-
対策: 2カラムレイアウト(画像を左、説明文を右)などを組む際、安易に
flexを使うと縦並びになって崩れます。React Emailの<Section>と<Column>コンポーネントを使用してください。これは内部的にクラシックな<td>テーブル構造を出力するため、Outlookでも正しく横並びになります。
-
対策: 2カラムレイアウト(画像を左、説明文を右)などを組む際、安易に
// ❌ flexを使うとOutlookで崩れる
<div className="flex justify-between">
<div>左側のコンテンツ</div>
<div>右側のコンテンツ</div>
</div>
// ⭕ Columnコンポーネントを使う(テーブルタグにコンパイルされる)
<Section>
<Column>左側のコンテンツ</Column>
<Column>右側のコンテンツ</Column>
</Section>
2. Gmail(特にモバイルアプリ)の「Tailwind クラス一部無視」問題
Gmailはセキュリティ上の理由から、受信したHTMLメールの <style> タグやインラインCSSをかなり強力にクレンジング(削除・変更)します。
-
バグ①: Tailwindの
my-autoやmx-auto(マージン自動)が効かない- Gmailでは、
margin: 0 auto;による要素の中央寄せが高確率で無視され、メール全体が左寄せになってしまいます。 -
対策: 外側のコンポーネントで明示的にピクセル指定のマージン(例:
margin-left: auto; margin-right: auto;)をインラインスタイルで指定するか、<Container>の幅を固定してテーブル要素のalign="center"を使います。
- Gmailでは、
-
バグ②: Webフォント(Google Fontsなど)が一切適用されない
- 対策: GmailはWebフォントの読み込みを拒絶します。そのため、必ず標準のシステムフォント(サンセリフ体など)を第一フォールバックに指定してください。
// フォントファミリーは安全なシステムフォントスタックを必ず指定する const fontSans = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif';
3. Dark Mode(ダークモード)時の「背景・文字色の強制自動反転」
iOS MailやGmailなどのモダンなメーラーには、OSがダークモードの際に「メールの色を自動で反転させる」機能があります。これがデザインを最悪にします。
- バグ: 白いロゴ画像が、背景が黒になったことで見えなくなる
-
対策:
- 透過PNG + 境界線(アウトライン)の付与: ロゴ画像は必ず背景を透過したPNGにし、ロゴの文字自体に薄い白やグレーのアウトライン(光彩)をつけておくことで、背景が黒になっても視認性を維持できるようにします。
-
メタタグによるダークモードの明示的な制御:
メールの<Head>にダークモード用のメタタグを埋め込み、自動反転を部分的に制御します(※ただし、すべてのメーラーで完全に制御できるわけではありません)。
4. 画像アセットの「ホットリンク無効」とCORSキャッシュ
メール内の <img> に指定する画像URLは、絶対パス(https://...)である必要があります。
- バグ: 開発用・テスト用のローカルURLのまま送信してしまい、本番で画像が表示されない
-
対策:
画像は Vercel Blob、Cloudflare R2、または AWS S3 などの信頼できるCDN(本番環境のオブジェクトストレージ)にアップロードし、その絶対パスを使用します。また、メーラーによってはプロキシ経由で画像を表示するため、CORSの設定で画像へのGETアクセスがパブリックに許可されていることを確認してください。
なぜ本番配信に SendGrid を選ぶべきなのか?
開発体験(DX)を React Email で劇的に向上させた後、「本番運用の安定性」を支えるのが SendGrid です。実際に運用して感じたSendGridの強みを共有します。
-
極めて強固なドメイン認証(SPF/DKIM/DMARC)の設定と維持:
SendGridのダッシュボードに表示されるCNAMEレコードをDNSに追加するだけで、自動的にDKIM署名やSPFが適切に設定されます。これにより、2024年以降に厳格化されたGmailの「送信者ガイドライン」も簡単にクリアできます。 -
Event Webhookによる「バウンス(不達)ログ」の自動ハンドリング:
メールが届かなかった際(一時的・永続的バウンス)、SendGridは即座にWebhookでイベントをNext.jsのAPIエンドポイントに通知してくれます。これを受け取り、DBのユーザーのメールステータスを自動更新することで、届かないアドレスにメールを送り続けてレピュテーション(ドメインの信頼性)が低下するのを防ぐことができます。 -
アクティビティフィードによる配信追跡の容易さ:
「ユーザーからメールが届かないと言われた」際、SendGridの管理画面から送信先アドレスで検索するだけで、送信完了・配信完了・またはエラーになった理由(バウンスなど)が秒単位で確認できます。
まとめ:Next.js + React Email + SendGrid は現代の最強スタック
表示崩れとの格闘は依然として存在しますが、それでも従来の「ローカルにHTMLファイルを置いて、手動でテスト送信を繰り返す」手法に比べれば、開発スピードと堅牢性は10倍以上に向上します。
メリットのおさらい
- TypeScriptの恩恵: メール送信時の変数(Props)に型定義があるため、「本番で名前の埋め込みが漏れて空白になっていた」というバグがコンパイル段階で防げます。
- プレビュー環境でのデザイン品質: ブラウザ幅での見え方や、テキスト抽出時の内容が即座に確認できます。
- SendGridの圧倒的な堅牢性: 送信信頼性、認証の手軽さ、ログハンドリングの容易さは他の追随を許しません。
これから新しくメール送信機能を実装する方、あるいは古いHTMLテンプレートの維持管理に限界を感じている方は、ぜひこのモダンスタック(Next.js + React Email + SendGrid)に挑戦してみてください。あなたの開発体験が劇的に変わること間違いありません。
この記事が役に立ちましたら、ぜひ「いいね」と「ストック」をお願いします!メール開発の苦労話や「こんなハックもあるよ!」という知見があれば、コメント欄で教えていただけると嬉しいです。
