🤖

ActionMailerのSMTP設定を動的に変更する

2020/11/30に公開

この記事について

Rails からメールを送る際、ActionMailerを使ってメールを送るケースが多いと思だろう。
しかし メールを送るサーバーを動的に設定したい場合はどうすればいいかについて解説している記事は少ないため、この記事で解説する。

一般的にRailsからActionMailerを使ってSMTP経由でメールを送る場合、下記の記事が参考になる。

この場合、SMTPサーバーの設定を config/environment.rbconfig/environments/production.rbconfig.action_mailer.smtp_settings = { ... }として設定することになる。

これは、1つのアプリケーションから1つのメールサービスしか使用しない場合は問題なく動作するが、ユーザーやグループによってアプリケーションが使用するメールサーバーを変えたい場合は意図したように機能しないだろう。

この記事ではユーザーやグループによってアプリケーションが使用するメールサーバーを変えたい場合、つまりは1つのアプリケーションから複数のメールサーバーを使用する場合について1つの解法を示していく。

定石

Railsでメールを送る場合、Railsガイド / Action Mailer の基礎 / Action Mailerを設定する に沿ってメールサーバーの設定を config/environment.rbconfig/environments/production.rb に対して config.action_mailer.smtp_settings = { ... }として設定することになる。

config/environment.rb
ActionMailer::Base.smtp_settings = {
  :user_name => 'your_sendgrid_username',
  :password => 'your_sendgrid_password',
  :domain => 'yourdomain.com',
  :address => 'smtp.sendgrid.net',
  :port => 587,
  :authentication => :plain,
  :enable_starttls_auto => true
}

この場合はActionMailer経由の全てのメールがこのSMTP設定を用いて配信されることになる。

カスタマイズ

しかし実際のところはユーザーやグループによっては特定のメールサーバーにSMTPで接続してメールの配信を行いたいといったケースが出てくる事が多い。

上記のように ActionMailer::Base.smtp_settings = {} で設定してしまう場合、適用した瞬間から次に上書きされるまでの間はそのSMTP接続を使用してメール送信を行なってしまうため、タイミング次第では意図しないSMTPサーバーの使用・・・古い言葉を使うと『混線』を起こすことになる。

これに対する1つの解法としては、ユーザーやグループといったメールサーバー毎にコンテナ化したアプリを配置することで解決する方法もあるが、今回は1つのRailsアプリ(コンテナ)で複数のメールサーバー話を使用するカスタマイズを行うやり方の1つを紹介する。

やり方

カスタマイズといってもそう大したことをするわけではなく、 ActionMailer::Base#mail の引数である delivery_method_options:を利用する。

delivery_method_options については Railsガイドで解説されているが、実際に認知されているケースは多くないように感じる。

Railsガイドではuser_namepasswordaddressを上書きしている例が書かれているが、実はこの delivery_method_options:は同様に他のsmtp_settingsの値についても設定する事ができる

実際にやってみる

はじめに、ActionMailer::Baseモジュールに設定されたデフォルトのsmtp_settingsを取得してみる

ActionMailer::Base.smtp_settings
 => {:address=>"localhost", :port=>25, :domain=>"localhost.localdomain", :user_name=>nil, :password=>nil, :authentication=>nil, :enable_starttls_auto=>true} 

何も設定されない場合は上記のような設定になっている。

ここでSaaS経由でのメール送信について実行してみる。

SendGridでAPIキーを使ったメール送信を行う場合、SMTP接続設定パラメータは下記のようになる。

ActionMailerの設定項目 設定値
user_name apikey
password APIキーの値 (仮に {APIキー} とする)
address smtp.sendgrid.net
domain メール送信元ドメイン (仮に {送信元ドメイン}とする)
authentication login
enable_starttls_auto true
port 587

これをActonMailerで動的に使用する場合、下記のようにdelivery_method_options:を使って、メール毎のSMTPサーバーの設定を上書きする。
(送信先アドレスは、仮に{YOUR_TEST@MAIL.ADDRESS}として設定)

ActionMailer::Base.mail(
  to:      '{YOUR_TEST@MAIL.ADDRESS}',
  from:    'from@{送信元ドメイン}',
  subject: 'テストメール',
  body:    'メール本文',
  delivery_method_options: {
    user_name: 'apikey',
    password:  '{APIキー}',
    address:   'smtp.sendgrid.net',
    domain:    '{送信元ドメイン}',
    authentication: 'login',
    enable_starttls_auto: true,
    port: 587,
  }
).deliver_later

上記の例では ActionMailer::Base に対して上書きを行っているが、app/mailers配下の各クラスに対しても同様の処理を行ってメール配信を行う事ができる。

ex)HogeNotifyが存在している場合
HogeNotify.mail(
  to:      '{YOUR_TEST@MAIL.ADDRESS}',
  from:    'from@{送信元ドメイン}',
  subject: 'テストメール',
  body:    'メール本文',
  delivery_method_options: {
    user_name: 'apikey',
    password:  '{APIキー}',
    address:   'smtp.sendgrid.net',
    domain:    '{送信元ドメイン}',
    authentication: 'login',
    enable_starttls_auto: true,
    port: 587,
  }
).deliver_later

また、rails consoleから確認する場合は deliver_later ではなく deliver を使う事で同期的にメールを送って確認する事ができる。

1. consoleを起動する

bundle exec rails c
Running via Spring preloader in process 2509
Loading development environment (Rails 6.0.3.4)

2. メールを送信する

ActionMailer::Base.mail(
  to:      '{YOUR_TEST@MAIL.ADDRESS}',
  from:    'from@{送信元ドメイン}',
  subject: 'テストメール',
  body:    'メール本文',
  delivery_method_options: {
    user_name: 'apikey',
    password:  '{APIキー}',
    address:   'smtp.sendgrid.net',
    domain:    '{送信元ドメイン}',
    authentication: 'login',
    enable_starttls_auto: true,
    port: 587,
  }
).deliver

まとめ

以上のように ActionMailerが利用するメールサーバーは、 config/environment.rbconfig/environments/production.rb に対して設定する以外に、ActionMailer::Base#mail の引数である delivery_method_options: を使って設定する事で、動的なSMTPサーバー設定を施す事ができる。

これはサービスを利用するユーザーやグループ単位でのメールサーバの切替等に活用できる仕組みであり、Railsの高い汎用性を表している一面であるとも言えるのではないだろうか。

Discussion