🐡

SMSを送信するためにActionMailerを拡張した話

2023/02/06に公開

今日は、みてねコールドクターでエンジニアマネージャーをしている遠藤です。
今日は、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 を指定します。

config/initilizers/mail.rb
  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の基本機能を拡張したいエンジニアを募集中です。

参考

https://tech.unifa-e.com/entry/2018/10/05/213601

みてねコールドクターテックブログ

Discussion