Ruby

Send Mail by MailCatcher Testing

Overview

Testing mail sending always contains troublesome. Even you don't waste much time checking text and grammar, it is still necessary to check whether the mail was actually sent.

So, you can check it by actually sending a mail to the address of yourself by preparing the SMTP server. But yet still there are sad things like broadcasting to another person's real address.

And if you are looking for something good to solve the problem, here goes the MailCatcher.

I tried it by making a docker file and thought it would be very convenient to make it a simple SMTP server for development (although it was not actually sent), because it was a really good library.

Environment

I am currently using docker-machine because my build environment is on mac. So the IP address of docker host is assumed to be 192.168.99.100. Please set your environment up carefully.

ruby 2.3.0
MailCatcher 0.6.4
docker version 1.11.1, build 5604cbe
docker-machine version 0.7.0,

MailCatcher

Some MailCatcher's characteristic:

  • Although it can be used as an SMTP server, it does not actually send mail, it saves the sent mail.

  • You can check the saved mail from the browser on the web screen which MailCatcher prepares separately.

  • You can also retrieve saved mails with api

Which make it closely to a library.

Dockerize the MailCatcher

Since it is only necessary at the development phase, I want to make it as simple as possible, so I made it based on alpine based on a ruby container.

  • 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"]

Since I upload the content of this Dockerfile to Docker hub, I don't have to build it

MailCatcher will be launched with the following command.

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

Here, 1080 and 1025 are ports for web screen reference and SMTP port respectively.

Access to Webscreen

Since the Web screen and the SMTP server are usable after starting the above container, check it from the Web screen.

I access from the browser at http://192.168.99.100:1080.

There is no mail yet so nothing is displayed, but it is a simple and beautiful screen.

According to the official page, it seems that you are using WebSocket, and when mail transmission occurs, the screen will be updated in real time without reloading the page.

Send mails

Well, now we had the environment, let's actually send a mail.

I think that mails are sent from rails again, I will test it with ActionMailer this time. However, it is hard to make it from an rails application, so let's use ActionMailer only.

This time I will send a blank mail and a HTML mail one by one.

Gemfile

Create and install Gemfile

// Create Gemfile
$ bundle init
$ echo 'gem "actionmailer"' >> Gemfile
// install
$ bundle install --path=vendor/bundle

Script for testing

This part is for writing a test script.

In this case, the host of the setting of the SMTP server is the docker host (1025) which was set when the docker port ran.

I also want to send HTML mails, so I specify the location of the template file separately.

Other than that I think that it is the same as how to use regular ActionMailer

  • test.rb
require 'action_mailer'

// Settings for SMTP
ActionMailer::Base.smtp_settings.merge!(
  address: '192.168.99.100',
  port: 1025
)

// Set root folder of template file location
ActionMailer::Base.prepend_view_path File.dirname(File.expand_path(__FILE__))

// send mail class
class TestMailer < ActionMailer::Base
  default from: '[email protected]'

  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

// send normal mail
TestMailer.test_mail(
  '[email protected]',
  'test subject',
  'Hello, World'
).deliver_now

#Send HTML mail
TestMailer.test_html_mail(
  '[email protected]',
  'test subject',
  'World',
  'Hoge',
).deliver_now

Don't forget we also have a template file. We made the root of the template file the script file directory this time,

Place the template file in ./test_mailer/test_html_mail.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>

Execute!

Well, let's run it!

$ bundle exec ruby test.rb

Jump in the previous web page I think that it looks like this.

Let's open the HTML mail:

All mails are saved properly!

API

Let's check the API as well.

You can get a summary of saved mails at 192.168.99.100: 1080/message. (Here We use jq to format json.)

$ curl -s 192.168.99.100:1080/messages | jq
[
  {
    "id": 1,
    "sender": "<[email protected]>",
    "recipients": [
      "<[email protected]>"
    ],
    "subject": "test subject",
    "size": "296",
    "created_at": "2016-05-19T15:31:32.000+00:00"
  },
  {
    "id": 2,
    "sender": "<[email protected]>",
    "recipients": [
      "<[email protected]>"
    ],
    "subject": "test subject",
    "size": "517",
    "created_at": "2016-05-19T15:31:32.000+00:00"
  }
]

The body of each mail can also be obtained with api. Using the id of the above summary result to identify the mail You can check it by: 192.168.99.100: 1080/messages/: id(.format)

The part of .format is plain or html .

In this case id:1 is plain and id:2 is html, so let's check the contents following that.

  • Content of the mail:
$ curl -s 192.168.99.100:1080/messages/1.plain
Hello, World
  • Content of HTML
$ 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>

Those are saved properly right?

Others: You can acquire the whole mail contents including the header by id.source.

$ curl -s 192.168.99.100:1080/messages/2.source
Date: Fri, 20 May 2016 00:31:32 +0900
From: [email protected]
To: [email protected]
Message-ID: <[email protected]>
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>

Conclusion

In this case you can send as much mails as you want with confidence in your own development environment.

Registration Login
Sign in with social account
or
Lost your Password?
Registration Login
Sign in with social account
or
A password will be send on your post
Registration Login
Registration