Sending email with Erlang, gen_smtp and Google Mail

λ July 17, 2020
Tags: erlang

I recently decided to roll a blog comment engine -for this very site- and I decided to use Erlang to do it! This page documents how I used an old and venerable module (gen_smtp) to not only work, but to use my Google mail account as the gateway to the universe.

Adding gen_smtp to a rebar3 project

A lot of Erlang projects these days use rebar3 which really really takes most of the grunt work out of managing the daily grind of running, testing and deploying. I haven’t needed to come up with e relx profile yet but the day is looming: an Erlang product can be deployed to a single folder as a totally self-contained VM and application code and assets. Awesome.

Here is my rebar.config as it stands:

{erl_opts, [debug_info]}.
{deps, [
    {epgsql,   {git, "https://github.com/epgsql/epgsql.git"},     {tag, "4.4.0"}},
    {cowboy,   {git, "https://github.com/ninenines/cowboy.git"},  {tag, "2.9.1"}},
    {jsone,    {git, "https://github.com/sile/jsone.git"},        {tag, "v0.3.3"}},
    {gen_smtp, {git, "https://github.com/gen-smtp/gen_smtp.git"}, {tag, "0.15.0"}}
]}.

{shell, [
  % {config, "config/sys.config"},
    {apps, [scofblog]}
]}.

As you can see, I am also using:

  • Cowboy (HTTP framework)
  • Epgsql for connecting to Postgres
  • JSOne for JSON encoder/decoding
  • gen_smtp for sending the mails

Cowboy was almost psycho_server, as I had just recently watched this video on YouTube but decided to go with Cowboy as I once used Chicago Boss, which is where I first encountered gen_smtp actually. I wrote a bingo caller called BingoBoss on my Mac that used say to talk the numbers and words!

The invocation to gen_smtp

The github page for gen_smtp contains a ‘trivial’ example of using the client library to send an email, except it isn’t too clear and I had some trouble with it. After some fiddling and trial and error, I now have this is the operational part of the email sending code.

    gen_smtp_client:send(
      {
       "the perceived from address goes in here",
       [Recipient_Email_Address_Goes_Here],
       Message_Body_I_Used_Plain_Text
      },

      [ {relay, "smtp.gmail.com"}
      , {username, "your gmail login name"}
      , {password, "you application password"}
      ]
     ).

The Application Password

In order to let gen_smtp send mails via your google gmail account, you need to set up an application password. You do this by logging into your google account, click on the “Security” options, then choosing the Applications menu, it should be at this location, if you are currently logged in to your gmail account it opens at the page for you!

https://myaccount.google.com/apppasswords

I selected “Other” from the left hand drop-down and was then prompted for a name, which I gave, and then this dialog appear. The blurred out value on the right is what you must COPY and then use as the password in the gen_smtp_client:send/2 call as shown further down the page. That tells google that your application is pre-authorised and it won’t send back a challenge response but instead carry on as “you”. Simple, but I confess to not getting it right a few times!

The google application password screen

Using the above configuration and now knowing the call format for the sender , I rolled out a small module I called mails, currently it only generates one email but I plan to fork this project and add in an email handler for my contact page which currently is pretty static!

A handy module: mails

Being a fan of dependency injection within reason, I decided that my simple wrapper would take a fair few parameters in order to make it more usable for me (and you?!) in the future:

-module(mails).
-export([
         send/3
        ]).

send(Username, Email, Url) ->
    Message =
        io_lib:format(
          "Subject: Your comment activation link for seancharles.xyz\r\n\r\n
Hi ~s~n~nYou recently left a comment on seancharles.xyz and as I have never
seen you email address before, I ask politely that you click this link to
verify your email address and also make your comment visible.~n~n
This is the first and last time you will have to do this, any more comments
will only require moderation by me!~n~n
THE LINK: ~s",
          [Username, Url]
         ),
    gen_smtp_client:send(
      {
       "comments@seancharles.xyz",
       [Email],
       Message
      },

      [ {relay, "smtp.gmail.com"}
      , {username, "objitsu@gmail.com"}
      , {password, "not-doxing-myself-ever"}
      ]
     ).

The password of course isn’t the real one ;) Note the use of \r\n at the end of the subject line. Don’t forget that or your mileage may vary as they say. For full details about why, you could do worse than read the SMTP RFC docs for a better understanding of the whole email process in general.

Summing Up

Sending email with Erlang using the gen_smtp module is pretty simple once you understand what the parameters are. The full library also contains the beginnings of a mail server application as well but I didn’t need to use that.

Happy hacking!

Comments