SMSを送信するためにActionMailerを拡張した話
今日は、みてねコールドクターでエンジニアマネージャーをしている遠藤です。
今日は、RailsでSMSを送信するためにActionMailerを拡張した話をします。
背景
弊社では、ユーザー認証や各種通知にSMSを利用しています。
開発にあたり、SMS周りでいくつか問題・要望がありました。
具体的には、
- 開発環境などが用意されていないので、生きている番号を使うと、実際にSMSが届いてしまい、使えない
- しかし使えない番号はバリデーションでチェックしたい
- 番号もランダムで使いたい
- 本番環境以外ではSMSを送信したくない
- でも開発時などで確認したいときは送信したい
- 本番環境では非同期処理で送信したいが、それ以外の環境では同期的に処理をしたい
- 自動テストではSMSを送信せず、実行したことは確認したい
- 本文の管理を簡単にしたい
- 特別なことを気にしなくても内容を実装できるようにしたい
などです。
これらを解決するために、ActionMailerを拡張して、SMSを送信するためのクラスを作りました。
実装
SMSをActionMailerで送信するためには、3クラス必要になります。
- SMSのAPIを使うためのクラス
- ActionMailerから呼び出して、上記クラスを実行するクラス
- SMSを送信するためのActionMailer
SMSのAPIを使うクラスは省略します(各々必要なクラスを作成してください)。
ActionMailerから呼び出されるクラスは、以下のように実装します。
class SMSDelivery
def initialize(settings)
@settings = settings
end
def deliver!(mail)
message = mail.body.raw_source.strip
SMSUtil.new(mail.to).send_message(message)
end
end
基本的にはinitializeとdeliver!を実装すればOKです。
deliver!は、ActionMailerから呼び出されるメソッドです。
mail.body.raw_source
でviewファイルの内容を取得できるので、末尾の改行等を削って渡します(SMSは文字数制限がきついので)。
SMSUtil
は内部で使っているSMSを扱うクラスなので、各自書き換えてください。
ActionMailerのクラスは通常通りの実装で大丈夫ですが、to
には電話番号を渡すようにしてください。
このままだと、普通のMailerと同じDeliveryMethodがよばれてしまうので、delivery_method
を指定します。
ActionMailer::Base.add_delivery_method :sms_delviery, SMSDelivery
if Rails.env.production? || ENV['SMS_SEND'] == 'true'
SMSMailer.delivery_method = :sms_delviery
end
環境変数でSMSを送信するかどうかを切り替えるようにしています。
それ以外は、config/environments/*.rb
などで規定したActionMailerのクラスと同じように動作します。
メリット
ActionMailerに則った実装なので、特に意識せずともSMS送信を実装できるようになりました。
また、letter_openerなどの開発環境でのメール送信を確認するためのGemを使うこともできます。
自動テスト時には ActionMailer::Base.deliveries
で内容を取得することもできます。
それ以外にも、deliver_now
, deliver_later
などActionMailer由来の同期・非同期の調整ができるようになりました。
まとめ
簡単な実装で、ActionMailerを拡張することで、SMS送信を実装できました。
他の記事では、ActionMailerにdelivery_method
を指定するケースがありましたが、それだと他の送信方法が使えなくなってしまうので、個別のクラスに指定しています。
弊社では、Railsの基本機能を拡張したいエンジニアを募集中です。
参考
Discussion