How To Send Emails From An Erlang Web Application

Do you want to quickly be able to send an email from your Erlang web application to one or more email addresses?

In this post I will show you an easy two steps method to achieve that goal:

  1. We are going to make our Ubuntu box (See how to install Erlang on Ubutntu) capable of sending emails to the outside world … and only that, nothing more (no mailbox configuration, spam assassin, etc …).
  2. Write an Erlang function responsible for building the message and sending it.

Step 1 – Install Postfix

Pre-requisite:
In the case you want to setup a dedicated server,  you will need to:

  • Associate a valid domain name with it (beebole.com in our example)
  • Install ‘Bind9′, the domain name server
  • Configure it

I invite you to read the section ‘Bind9′ at the end of this post for further information.

First, we are going to install Postfix and the mail utilities.

For that, just go to the command prompt of your Ubuntu server and type:

sudo apt-get install postfix mailutils

You will then face a post-installation screen (Note that you can always re-configure Postfix by using the following command : sudo dpkg-reconfigure postfix ).

In the case of a ‘Dedicated server’:

Choose ‘Internet’ and fill in your mail domain.  Just go with the default value for the rest.

Next, by editing the mailname config file (This file – /etc/mailname – is Debian specific and must be in a fully qualified domain name form, FQDN), we will tell our system what is the correct domain name for email addresses.  This name must be a valid domain name (MX record in the Bind9 section).

sudo vi /etc/mailname

Modify the domain name with your own:

mail.beebole.com

In the case of a ‘Home Station’:

Choose ‘Internet with smarthost’ and enter the relayhost info (= smarthost = the smtp of your ASP), i.e. relay.myasp.com

sudo vi /etc/mailname
relay.myasp.com

Now we need to refresh the Postfix configuration (we don’t need to restart the process with sudo /etc/postfix restart):

sudo postfix reload

Done? Great, we are ready now to check our setup!

An easy way to test it is to directly send an email. In this example, we are going to send a message titled “hello” to the address foo@mail.com with “hello me” as the body text.

Here are two examples, one in HTML, the other one in text format:

HTML:

echo "<strong>hello</strong> me" | mail -a "Content-type: text/html;" -s "hello" foo@mail.com

TEXT:

echo -e "hello n me" | mail -a "Content-type: text/plain" -s "hello" foo@mail.com

Just change the email address in the example by your own email address and check if you have received anything.

The answer is yes ? Congratulations, the first step is a success: you can send emails.

If it doesn’t work, have a look at your mail log file located in /var/log/mail.log (don’t forget to check your junk box … you never know).

Step 2 – Erlang Function

Here is the Erlang function responsible for sending emails using the ‘cmd’ function of the ‘os’ module.

This function issues a normal bash command. As simple as it is.

-module(mymailer).

-compile(export_all).

%% Destination: list of binaries
%% [<<"marc.liesen@example.net">>, <<"john.helbo@exmple.org">>, ...]
%%
%% Subject: binary
%% <<"A mail example">>
%%
%% Body: binary
%% <<"Once upon a time ... ">>
%%
%% ContentType: binary
%% <<"text/html">>

send(Destination, Subject, Body, ContentType) ->
D = string:join( lists:map( fun(Addr) -> binary_to_list(Addr) end, Destination ), " " ),
S = io_lib:format("~p",[binary_to_list(Subject)]),
B = io_lib:format("~p",[binary_to_list(Body)]),
CT = binary_to_list(ContentType),
os:cmd("echo " ++ B ++ " | mail -a "Content-type: " ++ CT ++ ";" -s " ++ S ++ " " ++ D).

Depending on how you have designed your web application (look at our video tutorial), you can call this function from within your web app. For example, you can call it like this:

mymailer:send([<<"foo@mail.org">>, <<"bar@mail.org">>], <<"hello">>, <<"Hello guys">>, <<"text/html">>)

At this point, I have to comment something. As you may have noticed, the function is accepting binaries as arguments.

When I started to learn Erlang, I knew that the language was playing with strings in a different way (list of integers). I also knew that the language was juggling with binaries pretty well.

So I decided to forget everything about strings and to keep going with binaries as long as possible. As soon as a request hits the server, mochijson parses the data into a binaries Erlang structure.

I can ensure you that you can do a lot with binaries … even applying regular expressions to it (have a look at this module, which provide you with functions for regular expression matching for strings and binaries).

Basically, the send function joins all the ‘stringified’ (hum … ‘listified’ should be more accurate) addresses, subject, body and the content type into one string, representing the command line we have just seen in the step ‘ONE’, and launch it with the ‘cmd’ function.

That’s it.

In the next post, I’ll use the os:cmd again, but this time to launch an ImageMagick script in order to create a CAPTCHA on the fly for your Erlang web application.

Bind9

Pre-requisite: You have a dedicated server and you just have associated your brand new domain name with that box (normally it takes around 24-48 hours to propagate this new association).

First, we start by installing the Domain Name System server:

sudo apt-get install bind9

Secondly, we configure it by adding a new zone in the named.conf.local file.

In this example host.dedicated.com is your server and beebole.com the domain you have associated with it.

sudo vi /etc/bind/named.conf.local
zone "beebole.com" {
type master;
file "/etc/bind/db.beebole.com";
};
sudo vi db.beebole.com
$TTL 3h
@ IN SOA host.dedicated.com. www.beebole.com. (
2008082501
8H
2H
1W
1D )

@ IN NS host.dedicted.com.
@ IN NS ns.dedicated.com.
@ IN MX 10 mail.beebole.com.
ns.dedicated.com. IN A 213.187.31.195
host.dedicated.com. IN A 91.120.121.95
www IN A 91.120.121.95
mail IN A 91.120.121.95
*.beebole.com. IN CNAME www.beebole.com.

sudo /etc/init.d/bind9 restart

Links

10 thoughts on “How To Send Emails From An Erlang Web Application

  1. Great post! I also use binaries over strings where possible… Mostly since strings are internally represented as two words-per-character and for most operations I perform, that’s wasteful (although I have absolutely no qualms about Erlang string handling in general).

    Have you considered Joe Armstrong’s email library for Erlang? His Send method is similar in that it calls cmd, but I believe it uses sendmail… See http://www.erlang.org/user.html#email-1.0

  2. Pingback: BeeBole creates a sample Mochikit Erlang Web Application with Video Tutorial – Erlang Inside

  3. your solution is OK for relatively small systems, however its not applicable for “enterprise” applications. Execution of external programs from the code is a bad technique thus you should use any of Erlang SMTP client libraries instead.

  4. I love seeing nice erlang articles like this in the wild! I think it would be a little prettier if you used io:format instead of just concatenating the strings together, though.

  5. @Jason

    No, I haven’t considered Joe’s email library yet. Thanks for the info, I will check it out.

    @eugen32

    The solution I propose is just a quick and handy way of sending emails from an application for which managing emails is not the core business. Using an external program might not seem so “elegant” but in some cases it’s more than enough.
    Are you aware of any Erlang smtp libraries in use at an “enterprise” level?

  6. @Matt

    Indeed, we could have coded :

    os:cmd(io_lib:format("echo ~s | mail -a 'Content-type: ~s;' -s ~s ~s", [B, CT, S, D])).

  7. This is a really, really bad idea.

    Even if this does manage to escape shell characters (say, subject:`rm -rf ~`) you are still possibly opening yourself up to header injection. I think the modern implementations of ‘mail’ are ok, but every one might not be…

  8. @Justin

    I partly agree with you about the risk of an header injection when calling dynamically external app. But we don’t give the user the possibility of editing and sending an email, in other words, we are in total control of the entire mail flow (signup notification, password forgotten, …). That might not be such a bad idea ; )

  9. Pingback: pozycjonowanie wroclaw