【Ruby】メールを送信する
こんにちは、しきゆらです。
昨年に投稿した「【Ruby】メールを送受信する」のプログラムを書き直す機会があったので、改めて書いておきます。
上記の投稿に載せたスクリプトをクラスに直して、いくつかのバグを修正しました。
その結果はこれ
require 'net/smtp'
require 'json'
require 'base64'
class SendMail
def initialize(to: 'to@mail.com', from: 'from@mail.com', option: {})
# 引数を取り込む
@smtp_option = {
server: 'smtp.gmail.com',
port: 465,
authentication: :plain,
ssl: true,
}
@smtp_option.merge!(option)
# 認証情報を合わせ
@smtp_option.merge!(load_secret)
@from = from
@to = to
@date = Time.now.strftime("%a, %d %b %Y %X")
end
# パスワードとかを記しておくもの
def load_secret
File.open("./secret.json") do |file|
JSON.load(file)
end
end
def create_subject(subject)
str = ""
Base64.encode64(subject).split("\n").each do |string|
str += "=?UTF-8?B?#{string}?= "
end
return str.rstrip
end
def create_body(subject: 'sample subject', body: 'mail main body')
@message = <<EOS
Date: #{@date}
From: #{@from}
To: #{@to}
Subject: #{create_subject(subject)}
Content-Type: text/plain; charset=UTF-8
Mine-Version: 1.0
#{body}
EOS
end
def send(subject: "test mail", body: "this mail is test!")
count = 0
begin
create_body(subject: subject, body: body)
mail = Net::SMTP.new(@smtp_option[:server], @smtp_option[:port])
mail.enable_ssl if @smtp_option[:ssl]
mail.start(@smtp_option[:server], @smtp_option["mail"], @smtp_option["pass"])
mail.send_mail(@message, @from, @to)
mail.finish
rescue => e
count += 1
if count < 10 then
puts "retry"
retry
else
puts e.class
puts e.message
end
end
end
end
極力外部のライブラリを使わずにメール機能を実装してみました。
使っているのは、標準添付ライブラリのみ。
基本的な使い方
SendMailクラスのインスタンスを作るときに送信先、送信者のメールアドレスとオプションを渡します。
オプションでは、smtpサーバ名・ポート番号・SSLを使うかどうかなどを連想配列で渡します。
認証情報をsecret.jsonというファイルにJSON形式で書きます。
例えば以下のような感じ。
{"mail": "mail@mail.com","pass": "password"}これを読み込んで使うようになっています。
デフォルトでは、Gmailのsmtpサーバを利用するようになっています。
Googleで2段階認証を設定している場合は、ログインするためのパスワードでは認証できません。
これに対しては、アプリケーション用のパスワードを作成して、secret.jsonに書きます。
作成方法は以下あたりから。
送信するときは、そのままsendメソッドを使います。
引数として、subjectとbodyを文字列として渡してやります。
これだけでメールを送ることができます。
一定のタイミングで通知を送るとか、使い方はそれなりにありそう。
件名の文字化け対策
また、以前のスクリプトでは件名が文字化けしてしまいます。
これをなんとかするために、create_subjectでいい感じに変換しています。
参考としたのは、以下のサイトたち。
charsetを指定しただけでは件名が化けてしまうようです。
どうも、アスキー文字のみしか使えないようです。
これをなんとかするためには、
=?CHARSET?B?エンコードした文字列?=
という形で書かないといけないようです。
UTF-8で場合は
=?UTF-8?B?エンコードした文字列?=
とします。
エンコードはBase64というものを使ってエンコードしています。
また、一定の文字数で区切らないといけないようです。
これに関しては、Base64でエンコードするといい感じのところで区切り文字を入れてくれます。
そこでsplitして、それぞれの文字列を上記のフォーマットで囲ってやっています。
ブログを見ると、メールを書くプログラムをいつかいたのかと思ったら約1年前だったとは。
久々にこの遺産が役に立ったので、驚きました。
思いついたら書いて、保持しておくのは大事なんだなと思いました。
おわり