Rubyでメールの送受信をする

みなさんはメールの送受信ってどうやってますか?

普通MacだったらMailなり、ThunderbirdなりのGUIアプリケーションを使用するかと思います。
しかし、インフラをやっているエンジニアだと、telnetなどでメールサーバーにつないで、接続確認を取ることがままあります。
しかし、メールサーバーへ接続するのにtelnetでつなぐと、認証情報をbase64エンコードしたりする場面が出てきます。
これが結構面倒だし、それに加えて手動だとコマンドミスなのかサーバー側の問題かを切り分けしやすいようスクリプト化したいなぁと思ってました。

シェルスクリプトで愚直にexpectも考えましたが、もう少しスマートでメンテナンスしやすいようにできないか調べてたところRubyのmailというgemが簡単そうということを知り、メールの送受信ができるようなスクリプトを作ってみました。

参考にしたサイト

参考にしたはのはこちらのサイトです。
メソッドの使い方などがどのサイトよりも丁寧に書かれていたので、このサイトに書いてあることを参考に下記スクリプトを書きました。

mailscript.rbファイル
require 'yaml'
require 'mail'
require 'date'
require 'socket'
require 'thor'

class EmailScript < Thor

  desc 'smtp','[Usage] ruby emailscript.rb smtp SMTPPORT MAILADDRESS ENVIRONMENT'
  def smtp(port, mailaddress, mailenv)
    pwinfo = YAML.load_file("mailenv.yaml")

    Mail.defaults do
      delivery_method :smtp, :address    => pwinfo["#{mailenv}"]['hostaddress'],
                             :domain     => pwinfo["#{mailenv}"]['hostaddress'],
                             :port       => "#{port}",
                             :authentication => :login,
                             :user_name  => pwinfo["#{mailenv}"]['user_name'],
                             :password   => pwinfo["#{mailenv}"]['password']
    end

    todaydate = Time.now
    svrhostaddress = pwinfo["#{mailenv}"]['hostaddress']

    begin
      Mail.deliver do
        from pwinfo["#{mailenv}"]['from_name']
        to "#{mailaddress}"
        header["X-Mailer"] = "Ruby-EmailScript"
        subject "TEST Mail from #{svrhostaddress} Port #{port} at #{todaydate}"
        body File.read("body.txt")
      end
      puts "Success send mail to #{port} port from #{mailenv}"
    rescue => e
      puts e
      puts "Failed send mail..."
    end
  end

  desc 'popimap', '[Usage] ruby emailscript.rb POPPORTorIMAPPORT ENVIRONMENT'
  def popimap(port, mailenv)
    pwinfo = YAML.load_file("mailenv.yaml")

    case "#{port}"
    when "110", "995"
      Mail.defaults do
        retriever_method :pop3, :address    => pwinfo["#{mailenv}"]['hostaddress'],
                                :port       => "#{port}",
                                :user_name  => pwinfo["#{mailenv}"]['user_name'],
                                :password   => pwinfo["#{mailenv}"]['password'],
                                :enable_ssl => pwinfo["#{mailenv}"]['enable_ssl']
      end
    when "143", "993"
    Mail.defaults do
        retriever_method :imap, :address    => pwinfo["#{mailenv}"]['hostaddress'],
                                :port       => "#{port}",
                                :user_name  => pwinfo["#{mailenv}"]['user_name'],
                                :password   => pwinfo["#{mailenv}"]['password'],
                                :enable_ssl => pwinfo["#{mailenv}"]['enable_ssl']
      end
    end

    begin
        puts <<-EOS
### HEADER \n#{Mail.last.header}
### subject \n#{Mail.last.subject}\n
### body \n#{Mail.last.body}
EOS
      puts "---\nSuccess pop/imap mail #{port} port from #{mailenv}"
    rescue => e
      puts e
      puts "Failed pop/imap mail..."
    end
  end

end

EmailScript.start(ARGV)

mailenv.yamlファイル
docker:
  hostaddress: 接続先サーバーアドレス
  user_name: 認証用のユーザー名
  password: パスワード
  enable_ssl: false
使い方

送信

$ ruby mailscript.rb smtp 25 info@hogepiyo.com docker

受信

$ ruby mailscript.rb popimap 110 docker

※dockerでテストしながら作っていたので、dockerという環境名を例にしています。

ポイントは、認証情報をyamlで管理してることと、thorでオプション追加することでクライアントツールっぽさを出したところです。
mail gemが標準でSSLにも対応しているのと、送信と受信それぞれにとても使いやすいメソッドが用意されていたのでそれを活用してます。
mailenv.yamlに同じように環境を追加していけば、送信と受信をこれ一つで試すことが可能です。

改善余地は多々あると思いますが、ちょっと前から考えていたスクリプトがとりあえず出来たので満足です。
これでメールサーバーへの接続方法が短縮できて、生産性向上です。

rconを試してみた

弊社のmatsumotoryさんが作られたツールrconを試してみました。

cgroupを利用したワンバイナリのツールで、IOやCPU、メモリーなどのリソースを制限できます。
cgroupは過去に検証したことがあったのですが、便利だけど、やはり手間がかかるイメージでした。
しかしrconはLinuxコマンドのように扱えるので、便利そうだと思い試してみました。

試した環境

CentOS6.7
Vagrant
Ruby2.2.3

事前に入れておくと良いパッケージ

私の環境はCentOSのminimal isoを利用したイメージだったので、色々パッケージが不足してました。最低限下記は必要かと思われます。

$ yum install libcgroup gcc zlib zlib-devel bison autoconf aclocal automake c++ gcc-c++ flex pam pam-devel

導入

導入については、README.mdを見ればすぐに分かるのですが、rakeを使ってビルドすれば、OKです。

README通りにやってみた

$ yes > /dev/null

yesコマンドを実行すると、そのままCPUが100%食われてしまいます。

before_rcon_yes

rconを使って、実行してみます。

$ rcon --user inamuu --command "yes > /dev/null" --cpu 10

結果

CPU使用率が10%まで抑えられていました。明確に数字にあらわれるので感動します。

after_rcon_yes

また、下記のように既に実行されているプロセスに対しても制限をかけることができました。

$ yes > /dev/null &
$ rcon --pids "`pgrep yes`" --cpu 10

今回はテストしませんでしたが、ディスクの読み書きもサイズで制限できるため、あきらかに負荷のかかる作業(ファイルを大量に削除するなど)を実施する場合は、大変便利なツールです。
また、リソースへ負荷のかかる作業をする場合は、利用してみようと思います。

Octokitの認証

Ocotkit使うにあたって、アクセストークンを直書きしてテストしていたのだけど、例えば複数人が使うのであればそれダメじゃんってなった。
調べてみたらnetrcというのが使えるらしくて、試してみた。
ついでにgistの一覧取得するみたいなのもやった。

.netrcファイルの書き方

$ vim .netrc
machine api.github.com
  login Githubのユーザー名
  password '取得したアクセストークンをここに書く'

認証の書き方

アクセストークン直書き

Octokit::Client.new access_token: 'ここにアクセストークン直書き'

netrc使うパターン

Octokit::Client.new netrc: true

これで良かった。

おまけ:gistの一覧取得

require 'octokit'

client = Octokit::Client.new netrc: true
list = client.gists
puts list

おまけ:一番最新のgistのURLを取得

require 'octokit'

client = Octokit::Client.new netrc: true
htmlurl = client.gists[0][:html_url]
puts htmlurl

これで、昨日ブログに書いた感じでgist作って、それを↑のような感じでURL取得するみたいなのが一連の流れでできそう。

昨日のブログ

octokitを使ってみた
会社の人にoctokit使うとGHEにログインしなくても色々できるよと教えてもらったので、試してみることにした。 octokitのインストール...