💌

mailpitでメール送信のテストをする with Go

2024/07/12に公開

はじめに

mailpitは、SMTPを使ったメール送信のテストを行うためのツールです。

MFAなどでシステムからメールを送る場面は多いと思います。

本番環境ではAWS SESなどメールサーバーを用意すると思いますが、ローカルでの開発やテスト環境ではメールサーバーを用意するのは大変ですよね。。

Mailpit は実際にメールを送信することなく、送信したメールを保存し、その内容を API や Web UI から確認することができます。

この記事では、mailpitを使ってメール送信のテストを行う方法について解説します!

(スターが4.9kもあるのに日本語の記事が全然なかった)

実装

インストール

go製でワンバイナリで動くので、インストールも簡単です!

# brewでinstallできます
$ brew install mailpit

# aquaでも入ります
$ aqua g -i axllent/mailpit

dockerイメージもあるのでお好きな方法で!

services:
  mailpit:
    image: axllent/mailpit:v1.19.0
    ports:
      - '8025:8025'
      - '1025:1025'
    environment:
      - MP_DATA_FILE=/data/mailpit.db # メールの内容をディスクに保存する場合のパス指定
    volumes:
      - mp-data-file:/data # 永続化する

volumes:
  mp-data-file:

余談ですが、aquaになかったので、PRをおくったら秒でマージしてリリースしてくれました!
https://github.com/aquaproj/aqua-registry/pull/24827

Thank you @suzuki-shunsukeさま !

使い方

設定なしで起動して使うことができます。

$ mailpit

http://localhost:8025 にアクセスすると、メールの一覧が表示されます。
Image from Gyazo

当たり前ですがまだメールを送信してないので、何も表示されていません。

cliにsendmailというサブコマンドがあり、メール標準入力でメールを渡すとmailpitにメールが保存されます。

もちろんSMTPでメールを送信することもできます。後ほどGoで実装してみます。

$ echo -e "To: to@example.com\r\nFrom: from@example.com\r\nSubject: Test Email\n\nThis is a test email."  | \
    mailpit sendmail

すると、、
Image from Gyazo

Image from Gyazo

こんな感じでメールが保存されているのが確認できます!

vueで書かれたUIも使いやすいです。

https://github.com/axllent/mailpit/tree/develop/server/ui-src

Apiでも送信したメールが確認できるので、やってみます。

# 本文だけ確認する
$ curl http://localhost:8025/view/latest.txt
This is a test email.

# サマリーを確認
$ curl -s http://localhost:8025/api/v1/message/latest | jq
{
  "ID": "B9q5RcacW9wdQP6MRSCmBg",
  "MessageID": "Rp8CrKXnraG5678Q8TjwWT@mailpit",
  "From": {
    "Name": "",
    "Address": "from@example.com"
  },
  "To": [
    {
      "Name": "",
      "Address": "to@example.com"
    }
  ],
  "Cc": [],
  "Bcc": [],
  "ReplyTo": [],
  "ReturnPath": "yuma@yuma-pc",
  "Subject": "Test Email",
  "ListUnsubscribe": {
    "Header": "",
    "Links": [],
    "Errors": "",
    "HeaderPost": ""
  },
  "Date": "2024-07-12T18:32:28.308+09:00",
  "Tags": [],
  "Text": "This is a test email.\r\n",
  "HTML": "",
  "Size": 318,
  "Inline": [],
  "Attachments": []
}

👇他にも色々Apiがあるので確認してみてください

Goでの実装例

Goでメールを送信して正しく送信されたか確認するためのテストを書いてみます。

雑にmailパッケージを作って、Send関数を作ります。

package mail

import (
	"fmt"
	"net/smtp"
)

func Send(to, from, body string) error {
	msg := fmt.Sprintf(
		"To: %s\r\nFrom: %s\r\nSubject: Test Email\n\n%s",
		to,
		from,
		body,
	)

	addr := "localhost:1025"
	err := smtp.SendMail(addr, nil, from, []string{to}, []byte(msg))
	if err != nil {
		return err
	}

	return nil
}

そしたらこんな感じでテストが書けます!

package mail_test

import (
	"io"
	"net/http"
	"testing"

	"mailpit-test/mail"

	"github.com/stretchr/testify/assert"
)

func Test_Main(t *testing.T) {
	t.Run("メール本文が正しいことを確認", func(t *testing.T) {
		to := "to@example"
		from := "from@example.com"
		body := "This is a test email.\r\n"
		err := mail.Send(to, from, body)
		if err != nil {
			t.Fatalf("エラーが発生しました: %v", err)
		}

		actual, err := getLatestMailFromMailpit()
		if err != nil {
			t.Fatalf("エラーが発生しました: %v", err)
		}
		assert.Equal(t, body, actual, "Should be the same.")
	})
}

func getLatestMailFromMailpit() (string, error) {
	resp, err := http.Get("http://localhost:8025/view/latest.txt")
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	return string(b), nil
}

ちゃんとテストが通ることを確認できます!

$ go test ./mail -v
=== RUN   Test_Main
=== RUN   Test_Main/メール本文が正しいことを確認
--- PASS: Test_Main (0.00s)
    --- PASS: Test_Main/メール本文が正しいことを確認 (0.00s)
PASS
ok      mailpit-test/mail       0.005s

おわりに

mailpitを使うことで、ローカルでの開発やテスト環境でのメール送信のテストが簡単に行えるようになります!

ぜひメールの送信テストに使ってみてください!

GitHubで編集を提案
ispec inc.

Discussion