Railsでメール受信をトリガーとした処理(postfix + rails runner)
背景
メール送信や空メールからのユーザ登録やサービス申込を実装したい. しかし,Railsにはメール送信機能はあるが,受信機能はない. そこで,メール受信にpostfixを使用し,Railsと連携して機能を実装する.
前提
アプリ(Rails)サーバ:aws EC2
メールサーバ:さくらメールサーバ(レンタル)
やりたいこと
ユーザが「register@xxxxx.com」にメール
↓
sakuraのメールサーバがアプリサーバ「ec2-user@ec2-00-000-00-000.ap-northeast-1.compute.amazonaws.com」に転送
↓
アプリサーバでpostfixがメールを受信する
↓
postfixがrailsのメソッドを呼び出す
メールサーバの設定
- 「register@xxxxx.com」を追加
- 「register@xxxxx.com」へのメールを「ec2-user@ec2-00-000-00-000.ap-northeast-1.compute.amazonaws.com」への転送設定を行う
アプリサーバの設定
EC2のポート設定
EC2のSecurity GroupsにてSMTP(ポート25)を許可する
postfixのインストール
sudo yum install postfix -y
postfixの設定ファイル
cd /etc/postfix/
sudo mv main.cf main.cf.org
sudo vim main.cf
次を記述
myhostname = mail.ec2-00-000-00-000.ap-northeast-1.compute.amazonaws.com #AWSのドメイン
mydomain = ec2-00-000-00-000.ap-northeast-1.compute.amazonaws.com #AWSのドメイン
myorigin = $mydomain
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
# 下記はセキュリティ系の設定
smtpd_banner = $myhostname ESMTP unknown
disable_vrfy_command = yes
smtpd_helo_required = yes
default_privs = ec2-user #これでaliasesの実行ユーザを設定する
sendmailからpostfixへ切り替え
sudo /etc/rc.d/init.d/sendmail stop
sudo chkconfig sendmail off
sudo alternatives --config mta
# => postfixを選択
sudo /etc/rc.d/init.d/postfix start
sudo chkconfig postfix on
postfix aliases設定
postfixではaliasesの設定ができる. これはメール受信をトリガーにメール転送,shellコマンド実行等が出来る仕組みだ. 今回はこれを利用して,アプリサーバがメールを受信したらシェルスクリプト経由でRailsのコマンドを実行するようにする. メールの内容はシェルスクリプトに標準入力として与えられる.
sudo vim /etc/aliases
下記を最終行に追加
ec2-user: "| /var/www/railsアプリフォルダ/current/script/runner/transfer_mail_process"
最後に
sudo newaliases
シェルスクリプト作成
sudo mkdir /config
cd /config
sudo vim transfer_mail_process
下記内容を記述
#! /usr/bin/env bash
# 環境パス設定
cd /var/www/railsアプリフォルダ/current
# railsコマンドのパスを一応通す
PATH=$PATH:/home/ec2-user/.rbenv/shims
export PATH
# 標準入力があればメールの内容をファイルに書き出し,railsコマンドを実行
if [ -p /dev/stdin ] ; then
nowtime=`date "+%Y%m%d%H%M%S"`
cat - > tmp/${nowtime}_mail.txt
rails runner -e production "User.mail_parse("$nowtime")"
fi
最後に
chmod 777 transfer_mail_process
railsに直接メールの内容を渡さずにファイル経由で行っている. これは,引数経由でrailsにメールを渡すと改行等が削除されて渡され,gemのmailではメール内容を上手くparseできなかったためだ.
ログファイル大きすぎで怒られたので一時的な対処
エラー内容
line 12: tmp/${nowtime}_mail.txt: ambiguous redirect log writing failed.
File too large -
対処
cd /var/www/railsアプリフォルダ/current/log/
mv production.log production.log.org
touch production.log
chmod 666 production.log
capistranoにてdeploy時にシェルスクリプトをrailsフォルダに配置
producitonとstagingにてシェルスクリプト内容を変えたかったので,capistranoのdeploy時にコピーするようにした. railsのdeployファイルを書き換える.
namespace :deploy do
# beforeの使い方 before taskの指定, 実行する関数名
before :migrate, :config_database do
on roles(:app) do
execute "ln -s /config/database.yml #{release_path}/config/"
execute "cp -f -p /config/transfer_mail_process #{release_path}/script/runner/" #ここ
end
end
# taskで元のタスク deploy:restartを上書きしてる unicounで立ち上げるので上書きでok
desc 'Restart application'
task :restart do
invoke 'unicorn:restart'
end
end
おしまい
これらの設定で一応完了する. ちょっとでもミスがあると動かなくなるし,デバッグがやり辛いので大変でした. Rails自体にメール受信機能つけてくれたらうれしいな.
デバッグ系コマンド
postfixログ確認
sudo tail /var/log/maillog
nobodyユーザでログインし,実行を確認
sudo su -s /bin/bash nobody
参考にさせていただきました
- https://github.com/mechamogera/MyTips/wiki/AWS%E4%B8%8A%E3%81%AEpostfix%E3%81%A7%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E5%8F%97%E4%BF%A1%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B
- http://d.hatena.ne.jp/kusakari/20090420/1240229003
- http://qiita.com/zaru/items/11a5692723b99740d4d4
- http://blog.falconsrv.net/articles/16