AWS内で動かしているアプリケーションで,メールを送りたい時がある.
普通であれば自分でメールサーバーを立ててドメインを使えるようにして……と割とめんどくさい話なんだけど,AWSにはメールを送る専用のSESというサービスがある.
RailsからSESを介してメールを送る話は,このへんで触れたことがある.
http://h3poteto.hatenablog.com/entry/2014/06/26/230359
こんな感じでSESは非常にラクに自分のドメインからのメールを送ることができる.
SESで気をつけなければいけないこと
ただし,注意しなきゃいけないことがある.
SESは簡単にメールを送ってくれる.
だけど,俺が悪意を持って,例えば迷惑メール配信なんかを大量にやろうとした時,こんなに便利なサービスも他にないってことになる.
なにしろドメインは自分で取得しなきゃいけないけど,メール配信自体を行うのはAWS SESなのだから,かなり迷惑なメールも送れそうな気がしてくる.
こういう事態に対応するために,SESにはBounceとComplaintという機能がある.
Bounceはメールが送れなかった時(送信先が存在しなかったときとか),Complaintは送ったメールに対する苦情がきたとき,にそれぞれ発生する.
そして,このBounce率やComplaint率が高い場合には,SESの利用を停止されることがある.
しかも噂によると,ある日突然警告メールが届き,利用を停止されるらしい.
その後,改善報告をすれば再度使えるようになるらしいが…….
怖いので監視する
これがあまりにも怖そうなので,とりあえずBounce率やComplaint率を監視してみます.
一応WebのコンソールからでもBounce率の推移グラフを確認することはできるんだけど,そうじゃなくてアラートを上げたい.
というわけで監視用にt1.microあたりのインスタンスを一個用意しましょう.
そこにスクリプトを突っ込みます.
require 'aws-sdk' ses = AWS::SimpleEmailService.new raw_data_array = [] ses.statistics.each do |status| raw_data_array.push(status) end # timestamp順に並んでいないのでソート raw_data_array.sort! do |a,b| a[:sent] <=> b[:sent] end attempts_sum = 0 bounces_sum = 0 complaints_sum = 0 # SESのステータスは15分おきに更新されるので,とりあえず直近1時間分を取り出す raw_data_array.last(4).each do |data| attempts_sum += data[:delivery_attempts].to_i bounces_sum += data[:bounces].to_i complaints_sum += data[:complaints].to_i end cloudwatch = AWS::CloudWatch::Client.new cloudwatch.put_metric_data( :namespace => "SES-Total", :metric_data => [ {:metric_name => 'Bounce', :value => bounces_sum.to_f * 100 / attempts_sum.to_f}, {:metric_name => 'Complaint', :value => complaints_sum.to_f * 100 / attempts_sum.to_f} ] )
AWS-SDKを使います.
newするところは適宜,access_key_idとsecret_access_keyを入れてあげてください.
sesに関してはregionの指定をすると,上手く動作しない仕様になっているので,regionの指定なしでnewします.
cloudwatchについては特に調べてないのですが……region指定なしだと,us-east-1あたりに勝手に入るので,まぁそれでいいかなと思ってそのまま初期化しました.
SESのステータスを引っ張りだしてみるとわかりますが,15分おきの更新でした.
ただ並び順がぐちゃぐちゃ……だったのでsentというdatetime型の要素でソートしておきました.
で,こいつをcronで実行してやる.
例えば,上記の例だと15分おき更新のステータスを,最新4件,つまり直近1時間分を取得してBounce率等を計算するので,このスクリプトの実行間隔は1時間おき,というのが妥当である.
あとはCloudwatch側に送られてきたLogsから,適当にアラートを自作して,閾値を超えた際にSNSに通知とか作るといいんじゃないでしょうか.
ちなみにAWSのドキュメントによると,Bounce率は5%以下に維持,Complaint率は0.1%以下に維持するのを推奨されています.
その辺りを閾値にしておくと安心ですね.
参考:
http://aws.amazon.com/jp/whitepapers/amazon-ses-best-practices/