SNSメール通知が届かない原因と対処法:サブスクリプション確認を忘れていませんか?

SNSトピックを作成してメールアドレスを登録したのに、アラートが一切届かない——本番環境の監視を設定した直後にこの状況に陥ると、「SNSが壊れているのか、IAMが間違っているのか」と疑い始めてしまう。ほとんどの場合、原因はずっとシンプルだ。サブスクリプション確認メールのリンクをクリックしていない、それだけである。

TL;DR:SNSメール通知が届かない場合の確認ポイント

確認順序確認内容期待される状態
1サブスクリプションのステータスconfirmedPendingConfirmationは未確認)
2確認メールの受信(迷惑メールフォルダ含む)件名「AWS Notification - Subscription Confirmation」
3SNSトピックのアクセスポリシーパブリッシュ権限が正しく設定されている
4送信元サービスのIAMロールSNSトピックへのsns:Publish権限を保持
5CloudWatchアラームのアクション設定正しいSNSトピックARNが指定されている

SNSメール通知の仕組み:なぜ確認が必要なのか

Amazon SNSのEmailサブスクリプションは、スパム防止のためにダブルオプトイン方式を採用している。エンドポイント(メールアドレス)を登録した時点では、サブスクリプションはPendingConfirmation状態になる。この状態では、トピックにメッセージがパブリッシュされても、そのエンドポイントには配信されない。確認リンクをクリックして初めてconfirmed状態に遷移し、通知が届くようになる。

graph TD A["sns:Subscribe 呼び出し"] --> B["PendingConfirmation 確認メール送信"] B --> C{"確認リンクを クリックしたか?"} C -- "No(期限切れ含む)" --> D["メッセージ配信されない 再サブスクライブが必要"] C -- "Yes" --> E["Confirmed サブスクリプション有効"] E --> F["Publish 呼び出し"] F --> G["メール配信成功"]
  1. Subscribe呼び出し:メールアドレスをエンドポイントとしてSNSトピックに登録する
  2. PendingConfirmation:SNSが確認メールを送信し、サブスクリプションは保留状態になる
  3. 確認リンクのクリック:メール内のリンクをクリックすることでSNSに確認を通知する
  4. Confirmed:サブスクリプションが有効化され、以降のパブリッシュが配信される
  5. Publish → 配信:CloudWatchアラームなどからのメッセージが実際にメールとして届く
確認リンクには有効期限がある。SNSの確認トークンは3日間有効で、期限切れ後は再サブスクライブが必要になる。「確認メールが来ていたけど後で見ようと思っていた」というケースで期限切れになっていることが多い。

SNSサブスクリプション確認:ステップバイステップの診断と修正

ステップ1:サブスクリプションのステータスを確認する

まず現在のサブスクリプション状態を確認する。PendingConfirmationが表示されていれば、確認リンクのクリックが完了していないことが確定する。IAMやトピックポリシーを疑う前に、ここを見るだけで原因が判明することがほとんどだ。

aws sns list-subscriptions-by-topic \
  --topic-arn arn:aws:sns:us-east-1:123456789012:MyAlertTopic \
  --region us-east-1

出力のSubscriptionArnフィールドがPendingConfirmationになっていれば、確認が未完了である。confirmed状態の場合は、別の原因(ステップ3以降)を調査する。

ステップ2:サブスクリプションを再作成して確認メールを再送する

確認メールが見つからない、または有効期限が切れている場合は、既存のサブスクリプションを削除して再作成する。再作成することで新しい確認メールが送信される。今度は迷惑メールフォルダも含めて即座に確認すること。

# 既存のPendingConfirmationサブスクリプションを削除(ARNがPendingConfirmationの場合は削除不要なケースもあるため確認)
aws sns unsubscribe \
  --subscription-arn arn:aws:sns:us-east-1:123456789012:MyAlertTopic:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
  --region us-east-1

# メールアドレスを再登録
aws sns subscribe \
  --topic-arn arn:aws:sns:us-east-1:123456789012:MyAlertTopic \
  --protocol email \
  --notification-endpoint your-email@example.com \
  --region us-east-1

受信した確認メールの件名は「AWS Notification - Subscription Confirmation」となる。メール本文内の「Confirm subscription」リンクをクリックすることで確認が完了する。

ステップ3:SNSトピックのアクセスポリシーを確認する

サブスクリプションがconfirmed状態なのに通知が届かない場合、トピックポリシーがパブリッシュを拒否している可能性がある。特にCloudWatchやEventBridgeなど他のAWSサービスからSNSにパブリッシュする場合、サービスプリンシパルへの許可が必要になる。

aws sns get-topic-attributes \
  --topic-arn arn:aws:sns:us-east-1:123456789012:MyAlertTopic \
  --region us-east-1 \
  --query 'Attributes.Policy'

CloudWatchアラームからパブリッシュする場合、トピックポリシーに以下のステートメントが含まれている必要がある。

🔽 CloudWatch用SNSトピックポリシー例(クリックして展開)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudWatchPublish",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudwatch.amazonaws.com"
      },
      "Action": "sns:Publish",
      "Resource": "arn:aws:sns:us-east-1:123456789012:MyAlertTopic",
      "Condition": {
        "ArnLike": {
          "aws:SourceArn": "arn:aws:cloudwatch:us-east-1:123456789012:alarm:*"
        }
      }
    }
  ]
}

ステップ4:CloudWatchアラームのアクション設定を確認する

サブスクリプションもポリシーも問題ないのに通知が来ない場合、CloudWatchアラームが正しいSNSトピックARNを参照しているか確認する。アラームのアクションにSNSトピックが設定されていない、またはARNが誤っているケースが意外と多い。

aws cloudwatch describe-alarms \
  --alarm-names "MyAlarmName" \
  --region us-east-1 \
  --query 'MetricAlarms[*].{AlarmName:AlarmName,AlarmActions:AlarmActions,StateValue:StateValue}'

AlarmActions配列に対象のSNSトピックARNが含まれていることを確認する。空配列または別のARNが設定されている場合は、アラームを更新する必要がある。

aws cloudwatch put-metric-alarm \
  --alarm-name "MyAlarmName" \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:MyAlertTopic \
  --region us-east-1 \
  --metric-name CPUUtilization \
  --namespace AWS/EC2 \
  --statistic Average \
  --period 300 \
  --threshold 80 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --dimensions Name=InstanceId,Value=i-1234567890abcdef0

ステップ5:テストメッセージを手動パブリッシュして疎通確認する

CloudWatchアラームの状態遷移を待たずに、SNSトピックへ直接メッセージをパブリッシュして配信経路を検証する。これにより、SNS→メール配信の経路自体が機能しているかをアラームとは独立して確認できる。

aws sns publish \
  --topic-arn arn:aws:sns:us-east-1:123456789012:MyAlertTopic \
  --subject "SNS疎通テスト" \
  --message "このメッセージが届けば、SNSからメールへの配信は正常に機能しています。" \
  --region us-east-1

このコマンドでメールが届けば、SNSとサブスクリプションは正常だ。届かなければ、サブスクリプションのステータスに戻って再確認する。届いた場合にCloudWatchからの通知だけが来ないなら、アラームのアクション設定またはトピックポリシーの問題に絞り込める。

graph TD Start["メール通知が届かない"] --> S1["ステップ1: サブスクリプション ステータス確認"] S1 --> Q1{"PendingConfirmation?"} Q1 -- "Yes" --> Fix1["ステップ2: 再サブスクライブ 確認リンクをクリック"] Fix1 --> Done["解決"] Q1 -- "No(confirmed)" --> S3["ステップ3: トピックポリシー確認"] S3 --> Q2{"Publishが許可 されているか?"} Q2 -- "No" --> Fix2["ポリシーにサービス プリンシパルを追加"] Fix2 --> Done Q2 -- "Yes" --> S4["ステップ4: CloudWatchアラーム アクション確認"] S4 --> Q3{"正しいSNS ARNが 設定されているか?"} Q3 -- "No" --> Fix3["put-metric-alarmで アクションを修正"] Fix3 --> Done Q3 -- "Yes" --> S5["ステップ5: 手動Publishで 疎通確認"] S5 --> Q4{"テストメールが 届いたか?"} Q4 -- "Yes" --> Inv["アラーム状態遷移を 調査"] Q4 -- "No" --> Back["ステップ1に戻り 再確認"] Inv --> Done

実際の現場で起きた誤診パターン

「SNSのパブリッシュが失敗しているはずだ」と思い込んで、IAMロールのポリシーを1時間かけて見直したことがある。CloudTrailでSNS:Publishのイベントを検索しても見つからない。「権限エラーだ」と確信してsns:Publishを追加しようとしたところ、すでに付与されていた。

実際の原因はサブスクリプションがPendingConfirmationのままだったことだ。SNSはパブリッシュ自体は成功させる——ただしconfirmedでないエンドポイントには配信しないだけだ。CloudTrailにはPublish成功のログが残るが、メールは届かない。この非対称な動作が誤診を引き起こす。

SNSのパブリッシュ成功とエンドポイントへの配信成功は別の概念である。

必要なIAM権限

SNSトピックの管理とサブスクリプション操作を行うユーザーまたはロールには、以下の権限が必要になる。

🔽 SNS管理用IAMポリシー例(クリックして展開)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SNSTopicManagement",
      "Effect": "Allow",
      "Action": [
        "sns:ListSubscriptionsByTopic",
        "sns:GetTopicAttributes",
        "sns:Subscribe",
        "sns:Unsubscribe",
        "sns:Publish"
      ],
      "Resource": "arn:aws:sns:us-east-1:123456789012:MyAlertTopic"
    },
    {
      "Sid": "CloudWatchAlarmManagement",
      "Effect": "Allow",
      "Action": [
        "cloudwatch:DescribeAlarms",
        "cloudwatch:PutMetricAlarm"
      ],
      "Resource": "*"
    }
  ]
}

cloudwatch:DescribeAlarmsおよびcloudwatch:PutMetricAlarmはリソースレベルの制限をサポートしていないアクションが含まれるため、Resource: "*"が必要になる場合がある。AWS Service Authorization Referenceで最新の対応状況を確認すること。

まとめとネクストステップ:SNSメール通知の確実な運用

SNSのメール通知が届かない問題の大半は、サブスクリプションのPendingConfirmation状態、つまり確認リンクの未クリックが原因だ。診断の順序は明確で、まずサブスクリプションのステータスを確認し、confirmedであれば次にトピックポリシー、アラームのアクション設定へと進む。

本番環境では、SNSトピックの作成とサブスクリプション登録をIaC(CloudFormationやTerraform)で自動化することを検討する。ただし、Emailサブスクリプションの確認は自動化できないため、デプロイ後に必ず手動で確認ステータスを検証するプロセスを組み込むこと。

用語集

用語説明
SNSトピックメッセージの送受信を仲介するAmazon SNSのチャネル。パブリッシャーがメッセージを送り、サブスクライバーが受け取る
サブスクリプションSNSトピックとエンドポイント(メールアドレスなど)の紐付け。確認完了後に有効化される
PendingConfirmationサブスクリプション登録後、確認リンクのクリック前の保留状態。この状態ではメッセージが配信されない
トピックポリシーSNSトピックへのアクセスを制御するリソースベースのポリシー。他のAWSサービスからのパブリッシュ許可もここで設定する
sns:PublishSNSトピックにメッセージを送信するIAMアクション。CloudWatchアラームなどのサービスがこの権限を必要とする

Related Posts

コメント

このブログの人気の投稿

EC2 SSH接続タイムアウトの原因と修正方法 — セキュリティグループのインバウンドルール完全ガイド

S3パブリックアクセス拒否の原因と解決策:バケットレベルの「Block Public Access」が優先される仕組み

EC2インスタンスIDをメタデータから取得する方法 — IMDSv2が安全な理由