MailCatcherでメール送信をテスト

# MailCatcherでメール送信をテストする

## 概要
メール送信のテストって面倒ですよね。本文の確認だけならそれほど手間ではありませんが、
やはりメールなので実際に送信できたかどうかの確認は必要になります。

すると、SMTPサーバを用意して、テストなり自分なりのアドレスに実際にメールを送って確認、
面倒なのでいつかオペミスしてホントの他人のアドレスに一斉送信とか、悲しいあるあるです。

で、なんかいいものは無いかと探していると[MailCatcher](https://mailcatcher.me/)というのがあるようでした。

良い感じのライブラリだったので`docker`ファイル作ってそれで開発用簡易SMTPサーバ（実際に送るわけではないですが）にすると便利であろうと思って試してみました。

### 環境
僕の環境は`mac`なので`docker-machine`を使っています。
なので、以降docker hostのIPアドレスは`192.168.99.100`としています。
ここは適宜ご自分の環境に合わせてください。

- ruby 2.3.0
- MailCatcher 0.6.4
- docker version 1.11.1, build 5604cbe
- docker-machine version 0.7.0,
 
### MailCatcher
特徴としては

- SMTPサーバとして使えるが実際にメールを送信することはなく、送信したメールを保存してくれる。
- 保存したメールは`MailCatcher`が別途用意しているweb画面でブラウザから確認できる。
- また保存されているメールを`api`で取得することが出来る

というようなライブラリです。

#### MailCatcherのDocker化
開発時にだけ必要なので出来るだけ軽いコンテナにしたかったため`alpine`ベースの`ruby`コンテナを元に作りました。

```sh:Dockerfile
FROM ruby:2.3.0-alpine

RUN apk --no-cache --update add \
                            libstdc++ \
                            build-base \
                            openssl-dev \
                            sqlite \
                            sqlite-dev \
                            ruby-dev && \
    gem install mailcatcher && \
    apk del build-base ruby-dev && \
    rm -rf /tmp/* /var/tmp/* /var/cache/apk/*

EXPOSE 1025 1080

CMD ["mailcatcher", "-f", "--ip=0.0.0.0"]
```

この`Dockerfile`の内容で作ったイメージを[Docker hub](https://hub.docker.com/r/pocari/mailcatcher/)にあげているので、`build`しなくても、
下記コマンドで`MailCatcher`が立ち上がります。

```sh
docker run -d -p 1080:1080 -p 1025:1025 pocari/mailcatcher
```

ここでマッピングしている`1080`,`1025`はそれぞれ、web画面参照用のポート、SMTP用のポートです。

#### Web画面にアクセス
上記のコンテナ起動後、もうWeb画面も、SMTPサーバも使用可能になっているので、Web画面から確認してみます。

`http://192.168.99.100:1080`にブラウザからアクセスします。

![スクリーンショット 2016-05-20 0.19.33.png](https://qiita-image-store.s3.amazonaws.com/0/34692/dc60af5a-1d49-e0ab-70fa-c791e5404554.png)

まだメールは無いので何も表示されてませんが、シンプルで綺麗な画面ですね。
公式ページによると`WebSocket`を使っているみたいで、メール送信が発生するとページをリロードしなくてもリアルタイムで画面が更新されていきます。

### メール送信
さて、これで環境はできたので実際にメールを送信してみましょう。

やはり`rails`から送ることが多いと思うので、今回は`ActionMailer`を使ってテストしてみます。
たださすがに`rails`のアプリケーションから作ると面倒なので、`ActionMailer`単体で使用します。

今回は`plain`なメールと`HTML`メールをそれぞれ一通ずつ送信してみます。

#### Gemfile

`Gemfile`を作成してインストールします。

```sh
# Gemfile作成
$ bundle init
$ echo 'gem "actionmailer"' >> Gemfile
# インストール
$ bundle install --path=vendor/bundle
```

#### テスト用スクリプト

テスト用のスクリプトを書きます。

今回の場合`SMTP`サーバの設定のホストが`docker host`で、ポートが`docker run`時に設定した`1025`です。

またHTMLメールも送ってみたいので、テンプレートファイルの置き場も別途指定します。

それ以外は通常の`ActionMailer`の使い方と同じだと思います。

```rb:test.rb
require 'action_mailer'

#SMTP設定
ActionMailer::Base.smtp_settings.merge!(
  address: '192.168.99.100',
  port: 1025
)

#テンプレートファイルの置き場所のルートフォルダを設定
ActionMailer::Base.prepend_view_path File.dirname(File.expand_path(__FILE__))

#メール送信クラス
class TestMailer < ActionMailer::Base
  default from: 'from@example.com'

  def test_mail(to, subject, body)
    mail(to: to, subject: subject, body: body)
  end

  def test_html_mail(to, subject, arg1, arg2)
    @arg1 = arg1
    @arg2 = arg2
    mail(to: to, subject: subject)
  end
end

#普通のメールを送信
TestMailer.test_mail(
  'to_address@example.com',
  'test subject',
  'Hello, World'
).deliver_now

#HTMLメールを送信
TestMailer.test_html_mail(
  'to_address@example.com',
  'test subject',
  'World',
  'Hoge',
).deliver_now
```

テンプレートファイルも用意しておきます。
今回はテンプレートファイルのルートをスクリプトファイルのディレクトリにしたので、
テンプレートファイルは`./test_mailer/test_html_mail.html.erb`に置きます。

```html+erb:./test_mailer/test_html_mail.html.erb
<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h1>Hello, <%= @arg1 %></h1>
    <h2>This is HTML mail.</h2>
    <p>arg2 is <%= @arg2 %></p>
  </body>
</html>
```

#### 実行！

さて、上記までで準備出来たので実行してみましょう。

```sh
$ bundle exec ruby test.rb
```

先ほどのweb画面にアクセスると下記のようになっていると思います。

![スクリーンショット 2016-05-20 0.37.29.png](https://qiita-image-store.s3.amazonaws.com/0/34692/782dc569-ad89-5cb1-1eb5-8f3474aad57a.png)

HTMLメールの方も見てみましょう。
![スクリーンショット 2016-05-20 0.38.10.png](https://qiita-image-store.s3.amazonaws.com/0/34692/fc67b0e3-b479-c044-03ef-a4e78a3475cb.png)

きちんと保存されていますね。

### API

APIの方も確認してみましょう。

`192.168.99.100:1080/messages`で保存済みメールのサマリが取得できます。
（ここでは`json`の整形に`jq`を使ってます。）

```sh
$ curl -s 192.168.99.100:1080/messages | jq
[
  {
    "id": 1,
    "sender": "<from@example.com>",
    "recipients": [
      "<to_address@example.com>"
    ],
    "subject": "test subject",
    "size": "296",
    "created_at": "2016-05-19T15:31:32.000+00:00"
  },
  {
    "id": 2,
    "sender": "<from@example.com>",
    "recipients": [
      "<to_address@example.com>"
    ],
    "subject": "test subject",
    "size": "517",
    "created_at": "2016-05-19T15:31:32.000+00:00"
  }
]
```

個別メールの本文も`api`で取得できます。メールの識別は上記のサマリ結果の`id`を使い
`192.168.99.100:1080/messages/:id(.format)`
の形式で確認できます。`.format`の部分は`plain`やら`html`やらです。

今回の場合`id:1`は`plain`、`id:2`は`html`なので、そのようにして内容を確認してみます。

- テキストメールの内容

```sh
$ curl -s 192.168.99.100:1080/messages/1.plain
Hello, World
```

- HTMLメールの内容

```sh
$ curl -s 192.168.99.100:1080/messages/2.html
<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h1>Hello, World</h1>
    <h2>This is HTML mail.</h2>
    <p>arg2 is Hoge</p>
  </body>
</html>
```

きちんと取れてますね。
その他`:id.source`の形式でヘッダも含めたメール内容全体が取得できます。

```sh
$ curl -s 192.168.99.100:1080/messages/2.source
Date: Fri, 20 May 2016 00:31:32 +0900
From: from@example.com
To: to_address@example.com
Message-ID: <573ddc543bc77_8ff73fcdbe03fa18274e5@paganini.local.mail>
Subject: test subject
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: 7bit

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h1>Hello, World</h1>
    <h2>This is HTML mail.</h2>
    <p>arg2 is Hoge</p>
  </body>
</html>
```

### まとめ
これなら安心して開発環境でバンバンメール送信できますね。