目次
Amazon SES 完全ガイド v2.0
初心者から実務者向けの包括的解説
ドキュメントの目的
本ガイドは以下を対象としています。
- 初心者向け: Amazon SES とは何か、メール送受信の基本を学びたい方
- 開発者向け: API / SMTP でメール送信を実装したい方
- SRE・運用向け: バウンス・苦情管理、レピュテーション監視を実装したい方
- 意思決定者向け: SendGrid・Mailgun・Postmark・Resend との比較・投資判断
2025-2026 年の Amazon SES 最新動向
- Mail Manager 新機能(2026年4月):受信メール処理の強化。複雑なメールルーティング・スパムフィルタリングが標準化
- DMARC 厳格要件(2025年5月 Microsoft 要件):送信者認証(SPF・DKIM・DMARC)の必須化。SES 上での DMARC ポリシー管理
- Suppression List 自動管理:バウンス・苦情メールの自動抑制リスト登録で送信レピュテーション保護
- Account-level Reputation Metrics:アカウント全体の送信レピュテーション(バウンス率・苦情率)をリアルタイム監視
- Dedicated IP 運用最適化:複数 Dedicated IP の一括管理・ウォーミング自動化
目次
- 本質・定義
- SES が解決する課題
- 主な特徴
- アーキテクチャ
- コアコンポーネント
- ドメイン設定と認証
- メール送信(SMTP・API)
- テンプレート・バルク送信
- バウンス・苦情管理
- 受信メール処理(Mail Manager)
- Configuration Set・Event Destination
- Suppression List・レピュテーション管理
- VPC Endpoint・セキュリティ
- 類似サービス比較表
- セキュリティ・ベストプラクティス
- トラブルシューティング
- 2025-2026 最新動向
- コスト最適化
- 学習リソース・参考文献
- 実装例・チェックリスト
- まとめ
本質・定義
定義
Amazon Simple Email Service (SES) は、「$0.10/千通の低コストで大量メール送受信を実現するマネージドメールサービス」。パスワードリセット・注文確認などのトランザクションメール、ニュースレター・キャンペーンメールまで対応。AWS インフラを活用した高い到達率・配信信頼性が特徴。
初心者向けメモ: SES は「あなたのメールサーバー」を AWS が管理してくれるサービス。SMTP インターフェースか API でメール送信するだけで、AWS が配信・レピュテーション管理・バウンス・苦情対応をすべて行う。
このサービスを選ぶ理由
| 課題 | SendGrid・Mailgun | SES での解決 |
|---|---|---|
| 大量メール送信のコスト | 月額固定 + 従量課金で高額化 | $0.10/千通(EC2 から無料)で業界最安 |
| 送信レピュテーション管理 | ベンダー頼み | Dedicated IP・送信プール・自動抑制で自社管理 |
| AWS との統合 | API のみ | Lambda・SNS・S3・EventBridge とネイティブ統合 |
| 受信メール処理 | オプション(有料) | S3 保存・Lambda トリガー・Mail Manager 標準 |
| DMARC・DKIM 設定 | UI ウィザード | Route 53 と簡単統合・Easy DKIM |
| 月 100 万通以上の送信 | 割高 | SES に切り替えで 70-80% コスト削減 |
SES が解決する課題
- メール配信の信頼性:AWS の高品質インフラで 99%+ の到達率を実現
- レピュテーション管理:バウンス・苦情を自動監視。アカウント停止を防止
- 大規模メール送信:月間数億通の送信でも自動スケール
- メール受信の自動化:受信メール → S3 → Lambda で処理パイプライン構築
- 送信者認証:SPF・DKIM・DMARC 統合で詐欺・フィッシング対策
主な特徴
| 特徴 | 説明 |
|---|---|
| SMTP インターフェース | 既存のメール送信コード(Rails・Django・PHP)を最小変更で移行 |
| API(v2) | JSON ベースの REST API。バッチ送信・テンプレート変数対応 |
| Configuration Set | バウンス・苦情・開封・クリック追跡を per-email 単位で設定 |
| Event Destination | バウンス・苦情 → SNS・CloudWatch・Kinesis Firehose・Pinpoint に自動転送 |
| Suppression List | 永続的なバウンス・苦情メールを自動登録。再送信防止 |
| Dedicated IP | 自社専用 IP で送信レピュテーション独占(オプション) |
| Mail Manager | 受信メール → S3・Lambda・SNS への自動ルーティング |
| DMARC・DKIM・SPF | 送信者認証を Route 53・Easy DKIM で簡単設定 |
| テンプレート | メールテンプレート管理。変数置き換えで個人化メール送信 |
| バルク送信 | 最大数百万件のメールアドレスに一括送信 |
graph TB
subgraph Application["アプリケーション層"]
APIGateway["API Gateway"]
Lambda["Lambda 関数"]
ECS["ECS タスク"]
end
subgraph SES["Amazon SES"]
SMTPEndpoint["SMTP エンドポイント"]
APIv2["API v2"]
ConfigSet["Configuration Set"]
Templates["Email Templates"]
SuppressionList["Suppression List"]
end
subgraph Outbound["送信(Outbound)"]
DNSValidation["DNS Validation<br/>SPF / DKIM / DMARC"]
SendQueue["Send Queue<br/>Rate Limiting"]
Recipients["受信者メールサーバー"]
end
subgraph Inbound["受信(Inbound)"]
InboundMessages["受信メッセージ"]
MailManager["Mail Manager"]
Rules["処理ルール<br/>S3 / Lambda / SNS"]
end
subgraph Monitoring["監視・追跡"]
ConfigEvents["Configuration Events<br/>Bounce / Complaint / Open / Click"]
SNSNotify["SNS 通知"]
CloudWatchMetrics["CloudWatch メトリクス"]
end
APIGateway --> APIv2
Lambda --> SMTPEndpoint
ECS --> SMTPEndpoint
APIv2 --> ConfigSet
ConfigSet --> Templates
ConfigSet --> SuppressionList
SMTPEndpoint --> DNSValidation
DNSValidation --> SendQueue
SendQueue --> Recipients
InboundMessages --> MailManager
MailManager --> Rules
ConfigSet --> ConfigEvents
ConfigEvents --> SNSNotify
ConfigEvents --> CloudWatchMetrics
style SES fill:#ccffcc
style Outbound fill:#e1f5ff
style Inbound fill:#f0f4c3
アーキテクチャ
送信フロー(Outbound)
【アプリケーション層】
├── SDK / API / SMTP
│ ├── Python boto3 / boto
│ ├── Ruby aws-sdk
│ ├── Node.js AWS SDK
│ └── Rails ActionMailer / Django
【SES サービス層】
├── SMTP / API ゲートウェイ
├── 認証・認可(IAM)
├── メールキュー・レート制限
├── 送信レピュテーション管理
【DNS 認証・配信】
├── SPF レコード検証
├── DKIM 署名
├── DMARC ポリシー確認
├── TLS 暗号化送信
【イベント追跡】
├── Bounce(永続的・一時的)
├── Complaint(苦情)
├── Delivery(配信成功)
├── Open / Click(クリック追跡)
【通知・保存】
├── SNS トピック
├── CloudWatch Logs
├── Kinesis Firehose
└── Pinpoint(マーケティング統合)
受信フロー(Inbound)
【外部メールサーバー】
↓
【Amazon SES 受信エンドポイント】
├── スパム・ウイルス スキャン
├── DKIM / SPF 検証
└── メール受け入れ
【Mail Manager(新機能 2025年)】
├── 複雑なルーティングルール
├── スパム / フィッシング フィルタ
├── メール操作(転送・削除・マーク)
└── コンテンツ フィルタリング
【アクション実行】
├── S3 に .eml 形式で保存
├── Lambda トリガー(メール解析)
├── SNS 発行(通知)
├── WorkMail 転送
└── SQS キューイング
コアコンポーネント
1. SMTP インターフェース
既存の Ruby on Rails・Django・PHP のメール設定を最小変更で SES に接続可能。
Rails(ActionMailer)の例:
# config/environments/production.rb
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'email-smtp.ap-northeast-1.amazonaws.com',
port: 587,
user_name: 'your-smtp-username',
password: 'your-smtp-password',
authentication: :login,
enable_starttls_auto: true
}
2. REST API(SESv2)
JSON ベースの送信。テンプレート変数・個別ヘッダ設定・バルク送信に対応。
3. Configuration Set
バウンス・苦情・開封・クリック イベントの追跡・タグ付け。per-email 単位でイベント分類。
aws sesv2 create-configuration-set \
--configuration-set-name production-config
# イベント監視先を SNS に設定
aws sesv2 create-configuration-set-event-destination \
--configuration-set-name production-config \
--event-destination-name bounce-tracking \
--event-destination '{
"Enabled": true,
"MatchingEventTypes": ["BOUNCE", "COMPLAINT"],
"SnsDestination": {
"TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:ses-events"
}
}'
4. Email Identity(ドメイン・メールアドレス認証)
送信元ドメイン・メールアドレスの所有権確認。DKIM・SPF・DMARC 設定。
# ドメイン検証
aws sesv2 create-email-identity \
--email-identity example.com \
--dkim-signing-attributes SigningAttributesOrigin=AWS_SES
# または BYODKIM(お客さんの DKIM キー)
aws sesv2 create-email-identity \
--email-identity example.com \
--dkim-signing-attributes \
SigningAttributesOrigin=EXTERNAL,\
SigningAttributesSecretKeySelector=my-dkim-secret
5. Suppression List
バウンス・苦情メールアドレスを自動登録。再送信防止。
# 抑制リストにメールアドレスを追加
aws sesv2 put-suppressed-destination \
--email-address invalid@example.com \
--reason BOUNCE
# 抑制リストの確認
aws sesv2 get-suppressed-destination \
--email-address invalid@example.com
ドメイン設定と認証
SPF(Sender Policy Framework)
ドメインから送信できるメールサーバー IP を定義。
# Route 53 / DNS TXT レコード
example.com TXT v=spf1 include:amazonses.com ~all
DKIM(DomainKeys Identified Mail)
メールが改ざんされていないことを暗号署名で証明。
SES による Easy DKIM:
# AWS Console で自動生成される CNAME レコード
aws sesv2 get-email-identity \
--email-identity example.com \
--query 'DkimAttributes.Tokens'
# 出力:
# [
# "hzijbeyoxjf4id7qxxxxxxx.dkim.amazonses.com",
# "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.dkim.amazonses.com",
# "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.dkim.amazonses.com"
# ]
# これらを DNS CNAME として登録
DMARC(Domain-based Message Authentication, Reporting and Conformance)
SPF・DKIM の結果に基づいて配信ポリシー(Accept / Quarantine / Reject)を定義。
# Route 53 / DNS TXT レコード
_dmarc.example.com TXT v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com
# p=none : DMARC 失敗でも配信。レポートのみ受け取り(テストモード)
# p=quarantine : DMARC 失敗時にスパムフォルダへ
# p=reject : DMARC 失敗時に受け取り拒否(最も厳密)
Microsoft 新要件(2025年5月):
- 5,000 メッセージ/日以上の送信者
- DMARC p=quarantine 以上の設定が必須
- SPF・DKIM の両方有効化が必須
メール送信(SMTP・API)
Python SDK による API 送信
import boto3
from botocore.exceptions import ClientError
ses_client = boto3.client('sesv2', region_name='ap-northeast-1')
def send_order_confirmation(to_email: str, order_id: str, amount: float):
try:
response = ses_client.send_email(
FromEmailAddress='noreply@example.com',
Destination={
'ToAddresses': [to_email],
'CcAddresses': ['support@example.com'],
'BccAddresses': []
},
Content={
'Simple': {
'Subject': {
'Data': f'ご注文確認 #{order_id}',
'Charset': 'UTF-8'
},
'Body': {
'Html': {
'Data': f'''
<html>
<body>
<h1>ご注文ありがとうございます</h1>
<p>注文番号: {order_id}</p>
<p>合計金額: ¥{amount:,.0f}</p>
<p>24時間以内に発送予定です。</p>
</body>
</html>
''',
'Charset': 'UTF-8'
},
'Text': {
'Data': f'注文番号: {order_id}\n合計金額: ¥{amount:,.0f}',
'Charset': 'UTF-8'
}
}
}
},
# Configuration Set の指定
ConfigurationSetName='production-config',
# メール追跡用タグ
EmailTags=[
{'Name': 'order-id', 'Value': order_id},
{'Name': 'email-type', 'Value': 'order-confirmation'},
{'Name': 'campaign', 'Value': 'transactional'}
],
# リスト登録解除リンク(オプション)
ListManagementOptions={
'ContactListName': 'monthly-newsletter'
}
)
print(f'Email sent. Message ID: {response["MessageId"]}')
return response['MessageId']
except ClientError as e:
error_code = e.response['Error']['Code']
print(f'Error: {error_code}')
if error_code == 'MessageRejected':
print('メールが受け入れられませんでした。送信レート制限・抑制リスト確認。')
elif error_code == 'MailFromDomainNotVerified':
print('送信元ドメインが検証されていません。')
raise
SMTP による送信(既存システム互換)
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# SES SMTP エンドポイント
HOST = 'email-smtp.ap-northeast-1.amazonaws.com'
PORT = 587
USERNAME = 'your-smtp-username'
PASSWORD = 'your-smtp-password'
server = smtplib.SMTP(HOST, PORT)
server.starttls()
server.login(USERNAME, PASSWORD)
msg = MIMEMultipart('alternative')
msg['Subject'] = 'ご注文確認'
msg['From'] = 'noreply@example.com'
msg['To'] = 'customer@example.com'
text = 'ご注文ありがとうございます。'
html = '<html><body><h1>ご注文ありがとうございます</h1></body></html>'
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
msg.attach(part1)
msg.attach(part2)
server.sendmail('noreply@example.com', ['customer@example.com'], msg.as_string())
server.quit()
テンプレート・バルク送信
Email Template 定義
aws sesv2 create-email-template \
--template '{
"TemplateName": "OrderConfirmation",
"SubjectPart": "ご注文確認 {{ORDER_ID}}",
"HtmlPart": "<h1>{{CUSTOMER_NAME}} 様へ</h1><p>注文番号: {{ORDER_ID}}</p><p>合計: ¥{{TOTAL_AMOUNT}}</p>",
"TextPart": "{{CUSTOMER_NAME}} 様へ\n注文番号: {{ORDER_ID}}\n合計: ¥{{TOTAL_AMOUNT}}"
}'
バルクメール送信
import json
response = ses_client.send_bulk_templated_email(
FromEmailAddress='noreply@example.com',
DefaultTemplate='OrderConfirmation',
DefaultTemplateData=json.dumps({
'CUSTOMER_NAME': 'customer',
'ORDER_ID': 'ORD-000',
'TOTAL_AMOUNT': '0'
}),
BulkEmailEntries=[
{
'Destination': {
'ToAddresses': ['user1@example.com']
},
'ReplacementTemplateData': json.dumps({
'CUSTOMER_NAME': '田中太郎',
'ORDER_ID': 'ORD-001',
'TOTAL_AMOUNT': '10000'
})
},
{
'Destination': {
'ToAddresses': ['user2@example.com']
},
'ReplacementTemplateData': json.dumps({
'CUSTOMER_NAME': '山田花子',
'ORDER_ID': 'ORD-002',
'TOTAL_AMOUNT': '20000'
})
}
],
ConfigurationSetName='production-config'
)
print(f'Bulk email sent. Status: {response["Status"]}')
バウンス・苦情管理
Bounce・Complaint イベント処理
SES が バウンス・苦情を検知したとき、SNS 経由で Lambda が自動応答。
import json
import boto3
ses_client = boto3.client('sesv2')
def handle_bounce_complaint(event, context):
"""
SES バウンス・苦情通知(SNS → Lambda)
"""
for record in event['Records']:
message = json.loads(record['Sns']['Message'])
notification_type = message.get('notificationType')
if notification_type == 'Bounce':
bounce_type = message['bounce']['bounceType']
bounce_subtype = message['bounce'].get('bounceSubType', '')
for recipient in message['bounce']['bouncedRecipients']:
email = recipient['emailAddress']
status = recipient.get('status', 'Unknown')
print(f'Bounce - Type: {bounce_type}, Email: {email}, Status: {status}')
# 永続的なバウンス → 抑制リストに登録(再送信防止)
if bounce_type == 'Permanent':
suppress_email(email, reason='BOUNCE')
print(f'Permanently bounced email suppressed: {email}')
# 一時的なバウンス → 監視するが削除しない
elif bounce_type == 'Transient':
print(f'Temporary bounce for {email}. Will retry later.')
elif notification_type == 'Complaint':
for recipient in message['complaint']['complainedRecipients']:
email = recipient['emailAddress']
complaint_feedback_type = recipient.get('complaintFeedbackType', 'unknown')
print(f'Complaint - Email: {email}, Type: {complaint_feedback_type}')
# 苦情 → 即座に抑制リストに登録
suppress_email(email, reason='COMPLAINT')
print(f'Email suppressed due to complaint: {email}')
def suppress_email(email: str, reason: str):
"""抑制リストにメールを追加"""
try:
ses_client.put_suppressed_destination(
EmailAddress=email,
Reason=reason # 'BOUNCE' or 'COMPLAINT'
)
print(f'Successfully suppressed {email}')
except Exception as e:
print(f'Error suppressing {email}: {str(e)}')
raise
アカウント停止の防止
def monitor_reputation_metrics():
"""
SES アカウント全体のバウンス率・苦情率を監視
"""
import boto3
cloudwatch = boto3.client('cloudwatch')
# バウンス率を確認
bounce_metric = cloudwatch.get_metric_statistics(
Namespace='AWS/SES',
MetricName='Bounce',
StartTime='...',
EndTime='...',
Period=3600,
Statistics=['Sum']
)
# 苦情率を確認
complaint_metric = cloudwatch.get_metric_statistics(
Namespace='AWS/SES',
MetricName='Complaint',
StartTime='...',
EndTime='...',
Period=3600,
Statistics=['Sum']
)
# バウンス率 > 5% でアラート
# 苦情率 > 0.1% でアラート(SES アカウント停止の閾値)
print(f'Bounce rate: {bounce_rate}%')
print(f'Complaint rate: {complaint_rate}%')
受信メール処理(Mail Manager)
Mail Manager ルール(2025年新機能)
複雑なメール処理ロジックを JSON で定義。スパム・フィッシング検知、自動ルーティング。
# 受信ルールセット作成
aws ses create-receipt-rule-set \
--rule-set-name support-rules
# サポートメール → S3 + Lambda で処理
aws ses create-receipt-rule \
--rule-set-name support-rules \
--rule '{
"Name": "support-email-processing",
"Enabled": true,
"Recipients": ["support@example.com"],
"ScanEnabled": true,
"TlsPolicy": "Require",
"Actions": [
{
"S3Action": {
"BucketName": "support-emails-bucket",
"ObjectKeyPrefix": "raw/",
"KmsKeyArn": "arn:aws:kms:ap-northeast-1:123456789012:key/xxxxxxxx"
}
},
{
"LambdaAction": {
"FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:ProcessSupportEmail",
"InvocationType": "Event"
}
},
{
"SNSAction": {
"TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:support-notifications"
}
}
]
}'
# 初期化ルールセット
aws ses set-active-receipt-rule-set \
--rule-set-name support-rules
Lambda で受信メール解析
import json
import boto3
import email
from email.parser import Parser
s3 = boto3.client('s3')
dynamodb = boto3.resource('dynamodb')
def process_support_email(event, context):
"""
S3 の .eml メールファイルを解析してチケット作成
"""
# イベントから S3 メタデータを取得
message_id = event['Records'][0]['ses']['mail']['messageId']
bucket = event['Records'][0]['ses']['mail']['destination'][0].split('@')[0]
# S3 からメールを取得
obj = s3.get_object(
Bucket='support-emails-bucket',
Key=f'raw/{message_id}'
)
email_content = obj['Body'].read().decode('utf-8')
email_message = Parser().parsestr(email_content)
# メール情報を抽出
sender = email_message['From']
subject = email_message['Subject']
body = email_message.get_payload(decode=True).decode('utf-8')
# DynamoDB にチケット記録
table = dynamodb.Table('SupportTickets')
table.put_item(
Item={
'ticket_id': message_id,
'sender': sender,
'subject': subject,
'body': body,
'status': 'new',
'created_at': event['Records'][0]['ses']['mail']['timestamp']
}
)
print(f'Support ticket created: {message_id}')
return {'statusCode': 200}
Configuration Set・Event Destination
イベント追跡の有効化
# CloudWatch に送信イベントを記録
aws sesv2 create-configuration-set-event-destination \
--configuration-set-name production-config \
--event-destination-name cloudwatch-tracking \
--event-destination '{
"Enabled": true,
"MatchingEventTypes": ["SEND", "DELIVERY", "BOUNCE", "COMPLAINT", "OPEN", "CLICK"],
"CloudWatchDestination": {
"DimensionConfigurations": [
{
"DimensionName": "email-source",
"DimensionValueSource": "MESSAGE_TAG",
"DefaultDimensionValue": "unknown"
},
{
"DimensionName": "email-type",
"DimensionValueSource": "MESSAGE_TAG",
"DefaultDimensionValue": "transactional"
}
]
}
}'
CloudWatch メトリクスの確認
# 開封率を計算
aws cloudwatch get-metric-statistics \
--namespace AWS/SES \
--metric-name Open \
--dimensions Name=email-type,Value=marketing \
--start-time 2026-04-01T00:00:00Z \
--end-time 2026-04-26T23:59:59Z \
--period 86400 \
--statistics Sum
Suppression List・レピュテーション管理
抑制リスト戦略
def manage_suppression_list():
"""
Global Suppression List(AWS 内部の既知バウンスメール)と
Account-level Suppression List(あなたのアカウント固有)を管理
"""
import boto3
ses = boto3.client('sesv2')
# グローバル抑制リストの確認
global_list = ses.get_account_suppression_attributes()
print(f'Global suppression list enabled: {global_list["SuppressedReasons"]}')
# アカウント抑制リストに追加(手動)
ses.put_suppressed_destination(
EmailAddress='hardcoded@invalid.example',
Reason='BOUNCE'
)
# アカウント抑制リストから確認
account_list = ses.list_suppressed_destinations(
Reason='BOUNCE',
PageSize=50
)
print(f'Suppressed addresses: {len(account_list["SuppressedDestinationSummaries"])}')
Account-level Reputation Metrics
# アカウント全体のバウンス率・苦情率を監視
aws cloudwatch get-metric-statistics \
--namespace AWS/SES \
--metric-name Reputation.BounceRate \
--start-time 2026-04-01T00:00:00Z \
--end-time 2026-04-26T23:59:59Z \
--period 3600 \
--statistics Average
# 苦情率確認(アカウント停止の閾値: 0.1%)
aws cloudwatch get-metric-statistics \
--namespace AWS/SES \
--metric-name Reputation.ComplaintRate \
--start-time 2026-04-01T00:00:00Z \
--end-time 2026-04-26T23:59:59Z \
--period 3600 \
--statistics Average
VPC Endpoint・セキュリティ
VPC Endpoint 経由で SES 接続
プライベートサブネット内から SES へ安全にアクセス。
# VPC Endpoint 作成
aws ec2 create-vpc-endpoint \
--vpc-id vpc-xxxxxxxx \
--vpc-endpoint-type Interface \
--service-name com.amazonaws.ap-northeast-1.email-smtp \
--subnet-ids subnet-xxxxxxxx subnet-xxxxxxxx
IAM ポリシーの最小権限
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ses:SendEmail",
"ses:SendRawEmail",
"sesv2:SendEmail"
],
"Resource": "arn:aws:ses:ap-northeast-1:123456789012:identity/example.com"
},
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:ses/*"
}
]
}
類似サービス比較表
| 項目 | SES | SendGrid | Mailgun | Postmark | Resend |
|---|---|---|---|---|---|
| 価格 | `0.10/千通 | `0.10-0.50/千通 | `0.50-1.00/千通 | 月額`1500~ | 月額$20~ |
| AWS 統合 | ✅ ネイティブ | ❌ API | ❌ API | ❌ API | ❌ API |
| 受信メール | ✅(Mail Manager) | ❌ | ✅ | ❌ | ❌ |
| API | ✅ | ✅ | ✅ | ✅ | ✅ |
| SMTP | ✅ | ✅ | ✅ | ✅ | ❌ |
| テンプレート | ✅ | ✅ | ✅ | ✅ | ✅ |
| Dedicated IP | ✅ | ✅ | ✅ | ✅ | ❌ |
| 到達率監視 | ✅ | ✅ | ✅ | ✅ | ✅ |
| Analytics | 基本的 | 高度 | 中程度 | 高度 | シンプル |
| 開発者体験 | 中 | 高 | 高 | 高 | 高 |
判断基準:
- AWS を主要インフラ・コスト重視 → SES
- マーケティング自動化・高度な分析 → SendGrid
- メール受信・複雑なルーティング → SES Mail Manager
- スタートアップ・メールのみ → Resend・Postmark
セキュリティ・ベストプラクティス
✅ 推奨される設定
| 項目 | 推奨 | 理由 |
|---|---|---|
| Configuration Set | 本番 Canary で有効 | バウンス・苦情の自動追跡 |
| Suppression List 管理 | Lambda で自動登録 | バウンス・苦情メールの再送信防止 |
| DMARC p=quarantine | 本番環境必須(2025年5月) | Microsoft 要件対応 |
| Dedicated IP(大量送信) | 月 500万通以上 | 送信レピュテーション独占 |
| VPC Endpoint | プライベート環境 | ネットワーク隔離 |
| Secrets Manager | SMTP 認証情報管理 | ハードコード回避 |
| Event Destination | SNS・CloudWatch に通知 | イベント追跡・自動対応 |
| メールテンプレート | サニタイズ・HTML 検証 | XSS・インジェクション攻撃防止 |
❌ 避けるべきパターン
| アンチパターン | 問題 | 対策 |
|---|---|---|
| バウンス・苦情通知無視 | アカウント停止(>5% バウンス・0.1% 苦情) | SNS で自動監視・Lambda 自動対応 |
| サンドボックス環境で本番送信 | 送信できない | Production Access 申請 |
| メール抑制リスト未設定 | バウンス・苦情メールに再送信 | Suppression List 自動登録 |
| DMARC 未設定 | スパムフォルダ行き | DMARC p=quarantine 以上に設定 |
| 一括送信スピード無制限 | スロットル・拒否 | Rate limit(秒間 14 通)を遵守 |
トラブルシューティング
| 症状 | 原因 | 対策 |
|---|---|---|
| 「MessageRejected」エラー | 抑制リストに載っている・バウンス率超過 | 抑制リスト確認・バウンス率監視 |
| メール配信されない | DKIM・SPF・DMARC 未検証 | DNS レコード確認・Easy DKIM 設定 |
| 送信レート制限(420 エラー) | 秒間 14 通を超えた | レート制限に従う・キューイング実装 |
| 「MailFromDomainNotVerified」 | 送信元ドメイン未検証 | SES Console でドメイン検証 |
| 高い苦情率 | メール コンテンツ問題・オプトイン不足 | リスト品質確認・オプトイン強化 |
| 受信メール処理失敗 | Mail Manager ルール設定エラー | CloudWatch Logs でルール動作確認 |
2025-2026 最新動向
1. Mail Manager 新機能(2026年4月)
受信メール処理の強化。複雑なルーティング・スパムフィルタリングが標準化。
2. DMARC 厳格要件(Microsoft 2025年5月)
送信者認証(SPF・DKIM・DMARC)の必須化。p=quarantine 以上が要件。
3. Account-level Reputation Metrics
アカウント全体のバウンス率・苦情率をリアルタイムで監視。アカウント停止を予防的に対応。
4. Dedicated IP 運用最適化
複数 Dedicated IP の一括管理・ウォーミング自動化。IP ローテーション戦略が簡素化。
コスト最適化
料金体系
| 課金項目 | 価格 |
|---|---|
| メール送信(EC2 / Lambda 経由) | $0.10/千通 |
| メール送信(外部SMTP) | $0.10/千通 |
| 受信メール | $0.10/千通 + S3 保管料 |
| Dedicated IP | $24.95/月(追加 IP) |
コスト削減例
【月間 100 万通送信】
SendGrid: $500-1000/月
Mailgun: $1000/月
SES: $100/月
削減効果: 80-90% ✅
学習リソース・参考文献
AWS 公式
- Amazon SES Developer Guide
- SES Email Authentication(DMARC・DKIM・SPF)
- SES Global Suppression List
- SES Pricing
ブログ・ガイド
- AWS Messaging & Targeting Blog
- Navigate Bulk Sender Requirements with Amazon SES
- DMARC Policy and Authentication(RFC 7489)
- DKIM RFC 6376
比較ツール
実装例・チェックリスト
フェーズ 1:基本設定(1週間)
- [ ] ドメイン検証(SPF・DKIM・DMARC)
- [ ] Configuration Set 作成
- [ ] IAM ロール設定
- [ ] SMTP 認証情報生成
フェーズ 2:統合・テスト(1-2週間)
- [ ] API / SMTP 統合テスト
- [ ] Event Destination 設定(SNS)
- [ ] バウンス・苦情処理 Lambda 作成
- [ ] CloudWatch メトリクス確認
フェーズ 3:本番化(1週間)
- [ ] 抑制リスト管理自動化
- [ ] Production Access 申請・取得
- [ ] メール テンプレート定義
- [ ] アラーム設定(バウンス率・苦情率)
フェーズ 4:運用・最適化(継続)
- [ ] バウンス率・苦情率 監視
- [ ] DMARC レポート分析
- [ ] 定期的な送信レピュテーション確認
- [ ] Dedicated IP 検討(大規模送信時)
まとめ
Amazon SES は、$0.10/千通の低コストで大量メール送受信を実現するフルマネージドメールサービス。DKIM・SPF・DMARC 設定で高い到達率を実現し、バウンス・苦情の自動管理でレピュテーションを保護する。
主要なポイント:
- 低コスト:SendGrid 比で 80-90% のコスト削減
- AWS ネイティブ統合:Lambda・SNS・S3・EventBridge と深く統合
- レピュテーション管理:自動抑制リスト・バウンス・苦情追跡
- 受信メール処理:Mail Manager で複雑なルーティング実装
- 2025年対応:DMARC p=quarantine 要件への自動対応
SendGrid・Mailgun との比較で、特に 月間 100 万通以上の大量送信・AWS インフラ活用・受信メール処理が必要な場合に SES は最適選択。
最終更新:2026-04-26 バージョン:v2.0 著者:Claude (Anthropic) — i のメモ拡充プロジェクト