バウンスメール対策として、Sisimaiの利用を考えていました。ここで結論です。LambdaでSisimaiによるバウンスメール解析の仕組みが作れそうでした。LambdaでSisimaiを動かすような記事は見つからなかったのでアウトプットしてみることにしました。 libsisimai.org
"SisimaiはbounceHammerの後継となるバウンスメール(エラーメール)解析ライブラリ" です。
クックパッド開発者ブログにある以下の記事を興味深く読みました。 techlife.cookpad.com
読んだ結果、わりと壮大な仕組みなので、現在であればもう少し小さく仕組みを実現できるのではないかと思って試してみた記事です。できるだけマネージドな仕組みの上で実現したいのですが、バウンスメール解析のSaaSでピンとくるものはなさそうだったのでこの記事の内容を試しています。(できればコードは書きたくないのでマネージドバウンスメール解析SaaSほしい)
Sisimaiは標準入力、変数経由などいくつかの動かし方ができるのと、依存関係が少ないのでLambdaで動くのではないか?と思って試しました。デプロイのことは考えるのが面倒だったので最小の工数でやってみています。
手順
変数f の中身はsisimai作者のazumaさんが開発・デバッグ用に提供してくれているメールの中身をブチ込んでみています。検証用なのでいかにも雑です。(ここをS3 Eventの中身にすると、SES+S3で受信している仕組みで使えそうです。 https://github.com/sisimai/set-of-emails/blob/master/maildir/bsd/lhost-sendmail-32.eml
require 'json' require 'sisimai' def lambda_handler(event:, context:) f = 'Return-Path: <MAILER-DAEMON@nyaan.example.co.jp> Received: from localhost (localhost) by nyaan.example.co.jp (V8/cf) id t91ECGic009238; Thu, 1 Oct 2015 23:12:16 +0900 Date: Thu, 1 Oct 2015 23:12:16 +0900 From: Mail Delivery Subsystem <poostmaster@example.co.jp> Message-Id: <201510011412.t91ECGic009238@nyaan.example.co.jp> To: <shironeko@example.co.jp> MIME-Version: 1.0 Content-Type: multipart/report; report-type=delivery-status; boundary="t91ECGic009238.1443708736/nyaan.example.co.jp" Subject: Returned mail: see transcript for details Auto-Submitted: auto-generated (failure) This is a MIME-encapsulated message --t91ECGic009238.1443708736/nyaan.example.co.jp The original message was received at Thu, 1 Oct 2015 23:12:15 +0900 from c135.kyoto.example.ne.jp [192.0.2.78] ----- The following addresses had permanent fatal errors ----- <nyaaan@neko.example.jp> (reason: 550 5.1.1 Requested action not taken: mailbox unavailable) ----- Transcript of session follows ----- ... while talking to inbound-smtp.us-west-2.amazonaws.com.: >>> RCPT To:<nyaaan@neko.example.jp> <<< 550 5.1.1 Requested action not taken: mailbox unavailable 550 5.1.1 <nyaaan@neko.example.jp>... User unknown >>> DATA <<< 503 Error: need RCPT command --t91ECGic009238.1443708736/nyaan.example.co.jp Content-Type: message/delivery-status Reporting-MTA: dns; nyaan.example.co.jp Received-From-MTA: DNS; c135.kyoto.example.ne.jp Arrival-Date: Thu, 1 Oct 2015 23:12:15 +0900 Final-Recipient: RFC822; nyaaan@neko.example.jp Action: failed Status: 5.1.1 Remote-MTA: DNS; inbound-smtp.us-west-2.amazonaws.com Diagnostic-Code: SMTP; 550 5.1.1 Requested action not taken: mailbox unavailable Last-Attempt-Date: Thu, 1 Oct 2015 23:12:16 +0900 --t91ECGic009238.1443708736/nyaan.example.co.jp Content-Type: message/rfc822 Return-Path: <shironeko@example.co.jp> Received: from [192.0.2.43] (c135.kyoto.example.ne.jp [192.0.2.78]) (authenticated bits=0) by nyaan.example.co.jp (V8/cf) with ESMTP id t91ECEic009234 for <nyaaan@neko.example.jp>; Thu, 1 Oct 2015 23:12:15 +0900 X-SenderID: Sendmail Sender-ID Filter v1.0.0 nyaan.example.co.jp t91ECEic009234 Authentication-Results: nyaan.example.co.jp; sender-id=pass header.from=shironeko@example.co.jp; auth=pass (CRAM-MD5); spf=pass smtp.mfrom=shironeko@example.co.jp From: "Shironeko, Nyaaan" <shironeko@example.co.jp> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Subject: Nyaaaan Message-Id: <4CB0AF09-E358-4D06-82B8-B8344B55CE02@example.co.jp> Date: Thu, 1 Oct 2015 23:12:10 +0900 To: nyaaan@neko.example.jp Mime-Version: 1.0 (Mac OS X Mail 7.3 \(1878.6\)) X-Mailer: Apple Mail (2.1878.6) nyaaan --t91ECGic009238.1443708736/nyaan.example.co.jp-- ' v = Sisimai.make(f) v.each do |e| puts e.action puts e.deliverystatus puts e.reason puts e.diagnosticcode puts e.softbounce end end
- Gemfileを書きます
# frozen_string_literal: true source "https://rubygems.org" gem 'sisimai', '~> 4.25', '>= 4.25.7'
- bundle installをします sisimaiが依存するojがNative extentionなのでAmazon Linux2上でビルドする必要があるのでこういう工夫が必要です。
docker run -v (pwd):/var/task -it lambci/lambda:build-ruby2.5 bundle install --path vendor/bundle
(かつての同僚が書いた記事に救われました。いい記事ですね。このチームでの楽しかったな~ Ruby on Lambdaで実現する、Eightの大規模画像処理基盤 - Sansan Builders Box
- Zipをアップロードする形でLambdaにデプロイします
aws lambda update-function-code --function-name sisimai-ruby-test --zip-file fileb://function.zip
- 空のeventを渡してLambdaをテスト実行します。下のJSONがSisimaiが返してくれた結果です。
[ { "catch": "", "token": "b314cc8582c5f78c3381dbaf4b5e86d706d1c505", "lhost": "c135.kyoto.example.ne.jp", "rhost": "inbound-smtp.us-west-2.amazonaws.com", "alias": "", "listid": "", "reason": "userunknown", "action": "failed", "origin": "<MEMORY>", "subject": "Nyaaaan", "messageid": "4CB0AF09-E358-4D06-82B8-B8344B55CE02@example.co.jp", "replycode": "550", "smtpagent": "Sendmail", "softbounce": 0, "smtpcommand": "DATA", "destination": "neko.example.jp", "senderdomain": "example.co.jp", "feedbacktype": "", "diagnosticcode": "550 5.1.1 Requested action not taken: mailbox unavailable 503 Error: need RCPT command", "diagnostictype": "SMTP", "deliverystatus": "5.1.1", "timezoneoffset": "+0900", "addresser": "shironeko@example.co.jp", "recipient": "nyaaan@neko.example.jp", "timestamp": 1443708736 } ]
とてもお手軽でしたね。SES+S3でメール受信して、S3 EventをトリガーにしてSisimaiが動いてバウンスメール解析するという仕組みを動かせそうな気持ちになってきました。よかったですね。