Posted at

Railsでメールを扱うときに困ったこと


DKIM&SPFレコードを設定する

メールサーバの設定の問題だとは思うのですがDKIM、SPFレコードが設定されていない状態でRailsのActinoMailerでメールを送信した際にスパムだと判定されて迷惑メールフォルダに分類されてしまい、問い合わせが発生したことがあります。

Rails ActionMailer 便利小ネタ集でも書かれているんですがSPFレコードだけでは不十分なケースがあるのでどちらか、ではなくDKIM&SPFレコードの両方を設定するようにしましょう。

開発段階ではletter_openerなどで送信していて気づかず、本番やステージングに導入してから発覚&調査することになり大変だったのでメールを扱うときは事前に設定されているかどうかを確認しておくほうがよいです。

結構見落としがちであとから発覚するタイプの問題なので事前にきちんと潰しておくと安心して開発に専念できます。


ActionMailerで例外をキャッチする方法

メールアドレスにミスがあったり、そもそもの設定がおかしくてSMTPサーバに送信が行えない、あるいはタイムアウトをしたときの例外をキャッチする方法を誤認していた。

特にこの手の例外のキャッチはサンプルコードなどには記載されていないのが一般的でどう調べるかで大変困った。

結論から言うとActionMailerを継承したクラス内で例外をキャッチするのではなく、呼び出す側で以下のようにbegin~rescueを行う必要がある。

クラス内で例外をキャッチできると勘違いしていたがこれはどうにも出来ないのではないかと思うがもし実装できる方法があるなら教えてほしい。

当初mailメソッド内で発生した例外だろうと考えていたので以下のように実装していたのだがこの実装では例外がキャッチできなかった。

class UserNotifier < ActionMailer::Base

default :from => 'any_from_address@example.com'

# send a signup email to the user, pass in the user object that contains the user's email address
def send_signup_email(user)
@user = user
mail( :to => @user.email,
:subject => 'Thanks for signing up for our amazing app' )
rescue StandardError => e
# ↓が実行されると思っていたが実行されなかった、何故???
Rails.logger.error("failed send mail. #{e.message}")
end
end

その後いろいろ調べた結果、ruby-on-rails – ActionMailerでのエラー例外の捕捉方法を発見。

呼び出し元でrescueすれば良いという情報を得る。

if @user.save

begin
UserNotifier.send_signup_email(@user).deliver
rescue Net::SMTPAuthenticationError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Net::SMTPFatalError, Net::SMTPUnknownError => e
Rails.logger.error("failed send mail. #{e.message}")
end

ここからはまだ未確認なので推測を含む形になるのだが、mail()はメール送信を行っているわけではない。

これは呼び出し元でdeliver()を呼び出していることから明らか。

なので実際にSMTPサーバとのやりとりでエラーになるのはdeliver()内で発生するため上のsend_signup_emailrescueをしても絶対に実行されない、ということになる。

わかってみれば至極当たり前の話なのだがmail()内で例外が発生していると思い込んでいたため変なハマり方をしてしまった。

恐らくRailsに詳しい人がいればシュッと解決できたのだと思うが相談出来る人がいなくてドツボにハマってしまった。

ActionMailerの中のコードなども読んでいたのだがどうにも気づかず無為に時間を使ってしまったので自戒としてQiitaで供養しておく。


参考になった記事など