AWS SES を使ったメール送信機能を開発していると、次のような課題に直面します。
- Sandbox制限(検証済みメールしか送れない)
- 実AWS環境への依存
- CIでの再現性の低さ
- テスト実行時の課金リスク
そこで今回は LocalStackを使ってSESをローカルでモックする構成 を導入しました。
なぜLocalStackなのか
| 課題 | LocalStackでの解決 |
|---|---|
| Sandbox制限 | 検証不要で送信可能 |
| AWS認証が必要 | ダミークレデンシャルでOK |
| 本番依存テスト | ローカル完結 |
| CI再現が難しい | コンテナで再現可能 |
| 課金リスク | なし |
LocalStackはAWS主要サービスをローカルでエミュレートするOSSです。
全体構成
[アプリ]
↓
[LocalStackコンテナ]
↓
(SESモック)
docker-compose.yml
version: "3.8"
services:
localstack:
image: localstack/localstack:latest
container_name: localstack
ports:
- "4566:4566"
environment:
- SERVICES=ses
- DEBUG=1
- AWS_DEFAULT_REGION=us-east-1
volumes:
- "./localstack:/var/lib/localstack"
起動:
docker compose up -d
awslocalのインストール
LocalStack利用時は awslocal を使うと便利です。
pip install awscli-local
※内部的に --endpoint-url=http://localhost:4566 を自動付与してくれます。
AWSダミー認証情報の設定
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_DEFAULT_REGION=us-east-1
LocalStackでは値は何でも構いません。
メールアドレス検証(モック)
awslocal ses verify-email-identity \
--email-address test@example.com
メール送信テスト
awslocal ses send-email \
--from test@example.com \
--destination ToAddresses=test@example.com \
--message "Subject={Data=Test},Body={Text={Data=Hello LocalStack}}"
成功レスポンスが返れば送信成功です。
送信確認方法
LocalStackログを確認します。
docker logs localstack
アプリから接続する場合
Python(boto3)
import boto3
ses = boto3.client(
"ses",
endpoint_url="http://localhost:4566",
region_name="us-east-1",
aws_access_key_id="test",
aws_secret_access_key="test"
)
Laravelの場合(.env)
MAIL_MAILER=ses
AWS_ACCESS_KEY_ID=test
AWS_SECRET_ACCESS_KEY=test
AWS_DEFAULT_REGION=us-east-1
AWS_ENDPOINT=http://localstack:4566
config/mail.php に endpoint を追加することで接続可能です。
CIで利用する場合
GitHub Actions例:
services:
localstack:
image: localstack/localstack
ports:
- 4566:4566
env:
SERVICES: ses
テスト実行時に awslocal を使うことで簡潔に操作できます。
注意点
LocalStackのSESは完全再現ではありません。
- IAMポリシー検証は簡易的
- 実配信は行われない
- バウンス / SNS連携は制限あり
あくまでアプリケーションロジックの検証用途です。
まとめ
SESを使う機能を開発するなら、
LocalStack + awslocal でローカル検証環境を作るのがおすすめ
本番AWSに依存せず、
ローカル完結でメール送信テストが可能になります。
CIとの相性も良く、課金リスクもありません。
AWSサービスを使うなら、まずはLocalStackでのモック構成を検討してみてください。