Action Mailerを利用したMailer Jobがエンキューされるまでの流れ
初めに
ポート株式会社 サービス開発部 Advent Calendar 2023 17日目の記事です。

ポート株式会社サービス開発部に所属している原です。業務では、Railsを用いてバックエンド開発を行なっています。
調査動機
業務でメール送信周りでバグが起こり、Action Mailerでのメール送信周りの処理が気になったので、今回コードリーディングをしてみました。
Railsでメール送信する場合の流れ
Railsはメール送信する場合は、Action Mailerを利用します。また、非同期でメールを送信する場合は、Active Jobも利用されるので今回は、Action MailerとActive Jobそれぞれコードリーディングしていこうと思います。
Action Mailerとは?
Action MailerはRailsに含まれているライブラリであり、メール送信に関する機能が実装されています。
基本的な使い方は下記Railsガイドを参照してください。
Active Jobとは?
Active JobはRailsに含まれているライブラリであり、Job操作に関する機能が実装されています。実際にエンキューする場合はアダプタ経由でエンキューします。
基本的な使い方は下記Railsガイドを参照してください。
コードリーディング編
Action Mailer部分
自分が普段開発しているプロダクトのRailsのバージョンが7.0.8なので、同様のバージョンをコードリーディングしていこうと思います。また、実際のプロジェクトのメイラー名などは使用せず、RailsガイドからMailer名やメソッド名などを拝借させていただいています。
UserMailerMailer.welcome_email.deliver_later
上記のようにメール送信処理を行なったときは、まず下記部分が呼ばれます。
早速エンキューしようとしてますね。UserMailerMailer.welcome_email.deliver_later(wait: 1.minute)などを渡した場合は変数optionsに{:wait=>1 minute}が入るようです。
正常にメールが送信される場合は、下記のelse句の内容が呼ばれます。
コード内の@mailer_class.delivery_jobはActionMailer::MailDeliveryJobのようでした。このJobに対して、mailerのクラスやアクション、mailerに渡した引数などを渡しています。
下記から#perform_later以降の処理はActive Jobを読みにいく必要があることはわかったのですが、一旦ActionMailer::MailDeliveryJob内のコードを読みにいきます。
@mailer_class.delivery_job.set(options).method(:perform_later).source_location
=> ["/app/rails/activejob/lib/active_job/configured_job.rb", 14]
ActionMailer::MailDeliveryJobのコードは下記になります。
ActionMailer::MailDeliveryJobは、ActiveJob::Baseを継承して作成されたJobになってますね。
Active Job部分
今度はActive Jobの中を見にいきます。上述したようにメールを非同期で送信するようにした場合は、下記コードが参照されます。
実際のエンキューの処理は下記で行われてます。
開発しているプロジェクトではActive JobのアダプタはSidekiqが使用されていますので、下記部分でActiveJob::QueueAdapters::SidekiqAdapter内の#enqueueが呼ばれます。
ActiveJob::QueueAdapters::SidekiqAdapter#enqueueでは、Sidekiq::Clientがpushしてますね。
ここからredisなどにエンキューする処理を見にいくには、Sidekiq内のコードを見にいく必要がありますが、そこはまた次回にしようと思います!
終わりに
今回Rails内のコードを読んでみて、普段何気なく使用している機能が裏でどのように動いているか知ることができました。
これからもRailsなどのOSSのコードは積極的に読んで行くようにしたいです。
Discussion