※ 「あなたがRails触る人なら見ておきたい「体系的な」豆知識」からの派生記事です。
「mailersってデフォルトで用意生成されるけどあんま使ったことない」そう思った8月某日、RailsでAction Mailerを利用して開発環境でメール自動配信機能をつくってみました。
手順
-
development.rb
にメール送信設定を記述 - メーラーを生成
- メーラーを編集
- メール本文をデザインする
- メーラーを呼び出すためのメソッドを記述する
- 実際に表示を確認する
- (発展) 添付ファイル付きのメールを送信する
1. development.rb
にメール送信設定を記述
メールを送信する時には送信するサーバーが必要です。
今回はgmailのアカウントからメールを送れるようにしてみます。
Rails.application.configure do
#--- 中略 ---#
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
port: 587,
address: 'smtp.gmail.com',
domain: 'smtp.gmail.com',
user_name: '<YOUR EMAIL ADDRESS>',
password: '<YOUR EMAIL PASSWORD>',
authentication: 'login',
enable_starttls_auto: true
}
end
config.action_mailer
というパラメーターに様々なオプションを指定する事ができます。
上から順番に説明していきます。
-
raise_delivery_errors
メールの送信に失敗した時にエラーを発火させるか (デフォルト値:
false
) -
delivery_method
メールを送信する方法 (デフォルト値:
:smtp
) -
smtp_settings
:smtpモードでの設定情報
-
address
=> SMTPサーバーのホスト名 -
port
=> SMTPサーバーのポート番号 -
domain
=> HELOドメイン -
user_name
=> メール送信に使用するgmailのアカウント -
password
=> メール送信に使用するgmailのパスワード -
authentication
=> 認証方法 -
enable_starttls_auto
=> メールの送信にTLS認証を使用するか
-
※ 後にGmail以外のクライアントを使用する際にhostname was not match with the server certificate
というエラーが出続ける場合にはenable_starttls_auto
の項目をfalse
としてください。
2. メーラーを生成
メール送信におけるコントローラー的役割を果たすMailer
をrailsコマンド
で生成します。
$ rails g mailer SampleMailer send_when_update
# rails g mailer <メーラー名> <メソッド名>
app/mailersフォルダ
の配下にapplication_mailer
とsample_mailer
が生成されます。
app/views/sample_mailer
には同じくメールテンプレートファイルが生成されます。
以後は基本的にこれら2つをカスタムしていきます。
3. メーラーを編集
class ApplicationMailer < ActionMailer::Base
default from: "from@example.com"
layout 'mailer'
end
class SampleMailer < ApplicationMailer
def send_when_update
@greeting = "Hi"
mail to: "to@example.org"
end
end
コメント等は省いていますが、生成直後の状態はこうなっているはずです。
application_mailer
には全メーラー共通の設定を、
sample_mailer
にはメーラー個別の設定を、それぞれ記述していきます。
application_mailerの編集
class ApplicationMailer < ActionMailer::Base
default from: "メールテスト運営局",
bcc: "sample+sent@gmail.com",
reply_to: "sample+reply@gmail.com"
layout 'mailer'
end
共通の処理・設定を記述する場合にはdefaultメソッド
を使用します。
メールに関して指定可能な主なプロパティは以下のとおりです。
名前 | 概要 |
---|---|
to | 通常送信先 |
cc | 一斉送信先 |
bcc | 非表示送信先 |
from | メールの送信元名 |
subject | メールタイトル |
date | メールの送信日時 |
reply_to | 返信先アドレス |
content_type | メール本文の種類 |
今回の場合はメールの送信元名を設定しました。
アドレス以外に「メールテスト運営局」という名前が表示されるようになります。
sample_mailerの編集
class SampleMailer < ApplicationMailer
def send_when_update(user)
@user = user
mail to: user.email,
subject: '会員情報が更新されました。'
end
end
メールに関する個別の設定にはmailメソッド
を使用します。
この時設定可能なプロパティは上掲の表のとおりです。
今回の場合はsend_when_updateメソッド
を呼び出す際に渡されるユーザーの情報から、
emailアドレスだけを取り出してメールの送信先としています。
こうすることでメール送信先を動的に変更することが可能です。
またメールテンプレート内で動的な変数を使用したい場合にはここで定義します。
メーラーはコントローラー的役割を果たしていると言った意味が実感できると思います。
mailメソッド
が呼び出された後は、自動的にメール本文のテンプレートを読み込みます。
次はメールの本文を編集していきましょう。
4. メール本文をデザインする
メール本文のテンプレートはデフォルトで二種類の形式が提供されています。
<h1>SampleMailer#send_when_update</h1>
<p>
<%= @greeting %>, find me in app/views/sample_mailer/send_when_update.html.erb
</p>
SampleMailer#send_when_update
<%= @greeting %>, find me in app/views/sample_mailer/send_when_update.text.erb
「 HTMLメールが送信できない場合にはテキストベースのメールを送信する 」
といったRailsの動作を保証するために二種類とも記述してある事が望まれます。
先ほどsample_mailer
で定義したインスタンス変数を利用して、
動的にテキストの内容を表示できるようにしましょう。
<!doctype html>
<html lang="ja">
<head>
<meta content="text/html; charset=UTF-8" />
<style type="text/css">
h2 {
color: #e7454a;
}
p hr {
color: #2d2a24;
}
</style>
</head>
<body>
<h2><%= @user.name %> 様</h2>
<hr />
<p>
この度は「メールテスト運営局」を利用頂きましてありがとうございます。
</p>
<p>
ユーザー名: <%= @user.name %><br />
</p>
<hr />
</body>
</html>
===============================
<%= @user.name %>様
===============================
この度は「メールテスト運営局」を利用頂きましてありがとうございます。
ユーザー名: <%= @user.name %>
5. メーラーを呼び出すためのメソッドを記述する
メールの設定を記述しただけではメールは送信できません。
メーラーは各コントローラーのアクションからの呼び出しによって起動します。
class UsersController < ApplicationController
def update
current_user.update(update_params)
SampleMailer.send_when_update(current_user).deliver
end
end
ユーザー情報が更新された直後に、ユーザー宛にメールが送信されるよう記述した例です。
メーラーは「メーラー名
.メソッド名
」として、クラスメソッドを呼び出すかのように実行できます。
今回はメーラー側でユーザーの情報を利用して、動的に宛先や本文を変更する実装を行っています。
そのためメソッドの引数としてユーザーのインスタンスを渡しています。
実際の送信を担うのはdeliverメソッド
です。
メーラーを起動して返ってきたメールのデータを送信します。
6. 実際に表示を確認する
ユーザーの編集機能は適当にscaffoldで生成したものがあれば十分です。
実際に編集してみましょう。
自分のユーザー情報として登録したGmailに届きました。
送信元は「メールテスト運営局<sample@gmail.com>」となっています。
メール本文を開くと…
うん、きちんとHTML形式で本文が表示されていますね。
7. (発展) 添付ファイル付きのメールを送信する
ユーザーがアバター画像としてアップロードしたファイルを、メールに添付したいという欲求にかられトライした記録を残しておきます。
以下は多少見やすいように、改行を増やして表示しています。
class SampleMailer < ApplicationMailer
def send_when_update(user)
@user = user
@avatar_file = avatar_file_name(user)
# set attachment file
attachments[@avatar_file] =
File.read(Rails.root.join("public#{avatar_url(@user)}"))
# set mail header
mail to: @user.email,
subject: '会員情報が更新されました。'
end
private
def avatar_url(user)
user.avatar.url(:thumb).gsub(/\?\d*/, "")
end
def avatar_file_name(user)
"avatar#{avatar_url(user).match(/(\..+)/)[0]}"
end
end
メールにファイルを添付するにはattachmentsメソッド
を使用します。
attachmentメソッド
のキーにはファイル名を、バリューにはファイル本体を指定します。
以下、順を追って解説します。
キモはattachmentメソッド
まずアバター画像は「20150808235932.png」のようなファイル名で、
public/system/users/avatars/...
のディレクトリに保存してあります。
@avatar_file = avatar_file_name(user)
メールテンプレートでも添付ファイル名を使用できるように、インスタンス変数を定義しています。
def avatar_file_name(user)
"avatar#{avatar_url(user).match(/(..+)/)[0]}"
end
avatar_file_nameメソッドを呼び出すことで、添付ファイル名を
「avatar.jpg」や「avatar.png」といった「 avatar.拡張子
」の形に成形しています。
attachments[@avatar_file] =
File.read(Rails.root.join("public#{avatar_url(@user)}"))
ファイルの添付にはattachmentsメソッド
を使用するのでしたね。
先ほど成形したファイル名を添付ファイル名にしています。
ファイル本体を読み込むにはFile.readメソッド
の引数にファイルの絶対パスを指定すると良いです。
今回の場合はアプリケーションのルートパスに、public以下のパスをjoinメソッド
で結合しています。
def avatar_url(user)
user.avatar.url(:thumb).gsub(/?\d*/, "")
end
avatar_urlメソッド
はファイルを呼び出した際にファイル名に付与されてしまうハッシュ値を、
取り除くために定義・実行しています。
表示を確認してみる
添付できとるうううぅぅぅ
添付画像のインライン表示化
ちなみに、以下のように細工することで添付画像をインライン表示することも可能です。
attachments.inline[@avatar_file] =
File.read(Rails.root.join("public#{avatar_url(@user)}"))
<p>
ユーザー名: <%= @user.name %><br />
アバター画像:<br />
<%= image_tag attachments[@avatar_file].url %>
</p>
「attachments.inline
」とメソッド内で定義していること、
「image_tag attachments[@avatar_file].url
」とテンプレート内で呼び出していること、
この2つが必要条件です。早速動作を確認してみましょう。
先ほどとは異なり、メール本文にそのまま画像が取り込まれているため
より自然で伝わりやすい文章となっていますね。
さいごに
今回はRailsでデフォルト搭載されているメーラーを、食べず嫌いになっている方向けに書いたつもりです。
ざっとメーラーを使っていくのに必要な事項はまとめられたかなと思います。
しかしまだ課題はあります。
今のコードのままだとメールを送信する際どうしても数秒のバッファが生じてしまうのです。
理想としては、アクションを実行した後さっさとテンプレートの描画に進み、
メールの送信はバックグランドで勝手にやっていて欲しいですね。
どうすればできるようになるか、皆さんも考えてみてください!