Edited at

Rubyでメールを送る

More than 5 years have passed since last update.

ウェブサイトの会員登録なんかでメール送信をプログラムで書く機会は結構あると思います。

基本的に他所に書かれてある物を集めただけですが紹介したいと思います。主に自分参照用に。


Mailライブラリーを使う

TMailには伝統がありますが、使い方が結構難しかった記憶があるので、今のRailsで使っているというMailというライブラリーを使ってみます。

gem install mail でインストールできます。


1. メールを作る

メール本文のオブジェクトを作ります。


mail.rb

require 'mail'

mail = Mail.new do
from 'KitaitiMakoto@example.net'
to 'KitaitiMakoto@example.net'
subject 'Mail from Mail'
body 'There is a body.'
end



2. メールを送る

SMTPの設定をした後で、#deliver!を呼び出します。


mail.rb

mail.delivery_method :smtp, { address:   'smtp.example.net',

port: 587,
domain: 'example',
user_name: 'KitaitiMakoto',
password: ($stderr.print 'password> '; gets.chomp) }
mail.deliver!

これを実行すると、メールが送れます。

ruby ./mail.rb

パスワードをエコーバックしないとか、環境変数や設定ファイルで設定するとか、そういう処理くらいは入れたほうがいいですかね?


3. クラスメソッドを使う

クラスメソッドだけで送信処理をすることもできます。


mail.rb

require 'mail'

Mail.defaults do
delivery_method :smtp, { address: 'smtp.example.net',
port: 587,
domain: 'example',
user_name: 'KitaitiMakoto',
password: ($stderr.print 'password> '; gets.chomp) }
end

Mail.deliver do
from 'KitaitiMakoto@example.net'
to 'KitaitiMakoto@example.net'
subject 'Mail from Mail'
body 'There is a body.'
end



4. オフラインで確認する

僕はオフラインで開発をすることが多いので、また、そうではなくても一々メールサーバーに接続したくないことも多いでしょう。テストの時など。

そういう時には、メールメッセージの送り先や内容だけを確認できます。


mail.rb

puts mail.to

puts mail.body

変数を使ってtoやbodyを指定している場合に便利でしょう。


ActionMailerを使う

RailsではMail gemを直接触ることはなくて、実際にはActionMailerを触ることになると思います。

これは、勿論Railsを使っていなくても便利な物です。

gem install actionmailer

でインストールします。


1. 環境の設定

設定はActionMailer::Baseのクラスメソッドを通して行います。


actionmailer.rb

require 'action_mailer'

ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
address: 'smtp.example.net',
port: 587,
domain: 'example',
user_name: 'KitaitiMakoto',
password: ($stderr.print 'password> '; gets.chomp)
}



2. メール送信用クラスの作成

メール送信内容はActionMailer::Baseの子クラスを通じて組み立てます。


actionmailer.rb

class SampleMailer < ActionMailer::Base

def first_example(body)
mail(
to: 'KitaitiMakoto@example.net',
from: 'KitaitiMakoto@example.net',
subject: 'Mail from SampleMailer',
body: body.to_s
)
end
end


3. メールを送る

mailメソッドを呼んでいるだけですが)メール送信処理はインスタンスメソッドとして定義していますが、呼び出す時にはクラスメソッドを使います。


actionmailer.rb

require 'English'

if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
SampleMailer.first_example('There is a body.').deliver
end


ruby ./actionmailer.rb

でメールを送ります。


テンプレートファイルを使う

メール本文をプログラムにハードコードするのはあり得ないので、テンプレートを使いたいですよね(送信先等の管理は特別なことが無いので省略)。


1. テンプレートファイルの場所を指定

ActionMailer::Baseのクラスメソッドを使って、テンプレートファイル(を探す起点)の場所を指定します。


template.rb

require 'action_mailer'

ActionMailer::Base.prepend_view_path File.expand_path('../templates', __FILE__)
# (その他設定)



2. メール送信メソッドをテンプレート版に対応させる

RailsのActionControllerのrespond_toのようにして「テンプレートを使う」ということを指定できます。

これもRailsのビューテンプレートと同じように、インスタンス変数をテンプレート側でも使えます。


template.rb

class TemplateMailer < ActionMailer::Base

def template_example(name)
@name = name
mail(
to: 'KitaitiMakoto@example.net',
from: 'KitaitiMakoto@example.net',
subject: 'Mail from TemplateMailer',
) do |format|
format.text
end
end
end

format.html

と書くとHTMLメールを送ってくれるようです。


3. テンプレートファイルを作る

1.で指定したように、テンプレートファイルは(ここでは)templatesディレクトリー以下に作ります。

ディレクトリー名にはクラス名をスネークケースにした物、ファイル名にはメソッド名を使います。テキストメールには.text.erbを、HTMLメールには.html.erbを付けます。

上の例だと

templates/template_mailer/template_example.text.erb

というファイル名になります。


templates/template_mailer/template_example.text.erb

There is <%= @name %>'s body.



4. メールを送る

メールの送信方法は変わりません。ので、送信せずに内容だけ確認するようにする、ということに挑戦してみましょう。

こうすればテストもしやすくなります。


template.rb

require 'English'

if File.basename($PROGRAM_NAME) == File.basename(__FILE__)
mail = TemplateMailer.template_example('北市真')
puts mail.body
end


deliver を呼ばずに body 属性を確認します。

ruby ./template.rb

で実行できます。

password> 

There is 北市真's body.

あ、SMTP関係の設定はいりませんね。


ネストしたモジュールでのテンプレートファイル

さて、バッチ処理でメールを送る場合など、クラスがモジュールの中にあることも多いと思います。


nested.rb

# ActionMailerの設定色々

# ActionMailer::Base...

module Batch
class Aggregate
# ...
# 色々のバッチ処理
# ...

def report_done
Mailer.done.deliver
end

def report_error(exception)
# 例外情報からエラーメッセージを作る
# error_message = ...
Mailer.error(error_message).deliver
end

class Mailer < ActionMailer::Base
def done
# 正常終了を報告するメールを送る
end

def error(error_message)
# エラーを報告するメールを送る
end
end
end
end


こういう時のテンプレートの場所は、モジュールのネスト分だけディレクトリーを掘った物になります。上の例だと、


  • templates/batch/aggregate/mailer/done.text.erb

  • templates/batch/aggregate/mailer/error.text.erb

の二つのファイルを使うことになります。


参考


Mail

Mailライブラリーについてはライブラリーその物のREADMEが充分わかり易い物です。


ActionMailer

ActionMailerについては、日記「発狂する近況」の記事(「RubyからGMailにメールを送る テキスト編」と「html編」)がとても参考になりました。

テンプレートファイルを置く場所については、ActionMailerのエラーメッセージを見て理解しました。