【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】

【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】 開発ツール(Dev Tools)
【初心者向け】Mailpitで開発中のメール送信を安全にテストする方法【Docker + Next.js対応】
この記事は約16分で読めます。
てんハロ運営者
てんハロ運営者

どもども
今回は「Mailpit」について解説します。

バグヲ
バグヲ

Dockerのイメージのひとつだっけ?

てんハロ運営者
てんハロ運営者

こんなあなたにピッタリな記事👇

  • 開発環境でメール送信処理をテストしたい
  • GmailやSendGridの実アカウントは使いたくない
  • MailpitをDockerで簡単に立ち上げたい

がまぁまぁわかります!

IT/Webエンジニア専門の転職エージェント【ユニゾンキャリア】

困ってた自分に届けたい話

これまでずっと、メール送信のテストは自分のアドレスに送って確認していました。
それでもなんとかなってはいたのですが、複数のメールアドレスで挙動を確認したいときなど、とにかく手間がかかる…

「みんなどうやってるんだろう?」と疑問に思っていたときに、たまたま見つけたのがMailpitというツールでした。

最初は「送信したメールをWeb画面で見るってどういうこと?」と、正直よくわかりませんでした。
ですが、実際に使ってみると「こんな便利なものがあったのか!」と衝撃を受けました。

それ以来、開発中のメール送信テストはMailpit一択です。

てんハロ運営者
てんハロ運営者

この記事は、同じように困っていた方への備忘録兼シェアとして書いています。

Mailpitとは?

Mailpit は、開発環境向けの「ローカルメール受信サーバー」です。
実際のメールサーバー(Gmailなど)を使わず、開発中のフォーム送信や通知メールがきちんと送られているかを、ブラウザ上で確認できます。

メリット

  • ✅ ローカルでメール受信ができる
  • ✅ ブラウザでメールの中身をすぐ確認できる(Web GUI)
  • ✅ SendGridや本物のメールアドレスは不要

DockerでMailpitを起動する手順

STEP1:docker-compose.yml の記載

まずは、以下のように docker-compose.yml を記述します。

 mailpit:
    image: axllent/mailpit:latest
    container_name: 任意のコンテナ名
    ports:
      - "1025:1025" # SMTP受信用
      - "8025:8025" # 管理画面GUI

STEP2:コンテナを起動

docker compose up -d

STEP3:正常にコンテナができたか確認

docker compose ps

ブラウザで http://localhost:8025 にアクセスすると、下記のMailpitの管理画面が表示されます。

nodemailer + Mailpit の実装(Next.js)

STEP1:パッケージをインストール

# メール送信用のライブラリ
npm install nodemailer
npm install nodemailer-sendgrid
npm install @sendgrid/mail

# 入力バリデーションライブラリ
npm install zod

# nodemailer 用の TypeScript 型定義ファイル
npm install --save-dev @types/nodemailer

STEP2:APIエンドポイントを作成(/api/mail/route.ts)

import { NextResponse } from "next/server";
import { getTransporter } from "@/lib/mailer";

export async function POST(req: Request) {
  const { email } = await req.json();
  const transporter = getTransporter();

  try {
    await transporter.sendMail({
      from: process.env.MAIL_FROM,
      to: email,
      subject: "自動返信テスト",
      text: "こちらは自動返信メールです。",
    });

    return NextResponse.json({ success: true });
  } catch (err) {
    console.error("メール送信エラー:", err);
    return NextResponse.json({ success: false }, { status: 500 });
  }
}

STEP3:メール送信フォームを作る(components/mailer/form.tsx)

"use client";

import { useState } from "react";
import { z } from "zod";

const schema = z.object({
  email: z.string().email("正しいメールアドレスを入力してください"),
});

export default function MailForm() {
  const [email, setEmail] = useState("");
  const [error, setError] = useState("");
  const [sent, setSent] = useState(false);

  const handleSubmit = async () => {
    const result = schema.safeParse({ email });
    if (!result.success) {
      setError(result.error.errors[0].message);
      return;
    }

    try {
      const res = await fetch("/api/mail", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email }),
      });
      if (res.ok) {
        setSent(true);
        setError("");
      } else {
        setError("送信に失敗しました");
      }
    } catch (err) {
      console.error(err);
      setError("通信エラーが発生しました");
    }
  };

  return (
    <div className="p-4 border rounded bg-gray-50 max-w-2xl mx-auto mt-10">
      <div className="flex flex-col gap-4 mt-10">
        <input
          type="email"
          placeholder="メールアドレスを入力"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          className="p-3 border border-gray-300 rounded"
        />

        <div className="text-center">
          <button
            type="button"
            onClick={handleSubmit}
            className="bg-blue-600 text-white px-6 py-2 rounded"
          >
            送信
          </button>
        </div>

        {error && <p className="text-red-600 text-sm text-center">{error}</p>}
        {sent && (
          <p className="text-green-600 text-sm text-center">
            自動返信を送信しました
          </p>
        )}
      </div>
    </div>
  );
}

STEP4:nodemailerの設定(lib/mailer.ts)

開発/本番 切り替え対応の内容を記載します。

開発環境と本番環境でメール送信先や処理を切り替える処理は、lib/ 配下の共通関数モジュールにまとめておくのが一般的のようです。

こうすることで、環境ごとの処理分岐を1か所に集約でき、APIエンドポイントやフロントエンド側からは毎回同じ関数を呼び出すだけで済むようになります。
結果として、コードが見やすくなり、保守性も高まります。

// src/lib/mailer.tsx

import { createTransport } from "nodemailer";
// @ts-expect-error 型定義がないため無視
import sgTransport from "nodemailer-sendgrid";

// 環境切り替え
export const getTransporter = () => {
  if (process.env.NODE_ENV === "production") {
    // 本番:例 SendGrid を使用
    return createTransport(
      sgTransport({
        apiKey: process.env.SENDGRID_API_KEY!,
      })
    );
  } else {
    // 開発:Mailpit を使用
    return createTransport({
      host: process.env.MAIL_HOST,
      port: Number(process.env.MAIL_PORT),
      secure: process.env.MAIL_SECURE === "true",
    });
  }
};

STEP5:環境変数設定

.env.local :開発用.envのこと。mailpitの環境変数設定を記載します。

# mailpit設定
MAIL_HOST=
MAIL_PORT=
MAIL_SECURE=

.env.production :本番環境用.envのこと。今回はSendGridの環境変数設定を記載しています。

# SendGrid設定
SENDGRID_API_KEY=

.env :開発・本番で共通使用.envのこと。今回は、送信者のメールアドレスが該当します。

FROM_EMAIL=

STEP6:実行

npm run dev で開発環境のNext.jsを起動

http://localhost:3000 からフォームにアクセス

下記のinputタグにメールアドレスを入力する

STEP7:実行結果

メールを送信すると http://localhost:8025 のMailpitにメールが表示される!

まとめ|Mailpitは開発中のメール送信テストに最適

  • 開発中にメールを安全・手軽に確認したいなら、Mailpitは超便利
  • Dockerだけで立ち上がるから環境構築も簡単
  • Next.js + nodemailerでも問題なく動作確認が可能

Dockerもっと勉強したい!と思われた方は、こちらの記事もおすすめです。

てんハロ運営者
てんハロ運営者

おつかれさまでした!

更新をF5連打で待つの、そろそろやめませんか?
( ブログ更新をメールでそっとお知らせします🙇‍♂️ )

スパムはしません!詳細については、プライバシーポリシーをご覧ください。

コメント