みずぎわブログ

技術系のことや日々に考えたことを書き連ねます

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がメールを受信する

postfixrailsメソッドを呼び出す

メールサーバの設定

  1. 「register@xxxxx.com」を追加
  2. 「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

参考にさせていただきました