How to send email via Gmail using Erlang

21st Century Code WorksBest of Erlang - noreply@blogger.com (Benjamin Nortier) - May 19, 2009

One of my pet projects, www.dayfindr.com, integrates with email to send notifications to users.

I use Google Apps for email infrastructure, so you need an SMTP client that supports TLS. At the time, I couldn’t find a simple Erlang SMTP client that could handle TLS, so I used a command-line SMTP client.

For my new pet project, for want of a better name temporarily called The Isabelle Project, I need to add some email functionality. This time I would prefer to use an Erlang solution with proper error handling and logging.

I looked at the SMTP protocol on Wikipedia, and it didn’t seem to difficult. Erlang’s built-in ssl module also seemed to support TLS. So, with a bit of trial and error, here’s the result:


-module(smtp).
-export([connect/0]).

connect() ->
{ok, Socket} = ssl:connect("smtp.gmail.com", 465, [{active, false}], 1000),
recv(Socket),
send(Socket, "HELO localhost"),
send(Socket, "AUTH LOGIN"),
send(Socket, binary_to_list(base64:encode("___@gmail.com"))),
send(Socket, binary_to_list(base64:encode("johngalt"))),
send(Socket, "MAIL FROM: <___@gmail.com>"),
send(Socket, "RCPT TO:<___@gmail.com>"),
send(Socket, "DATA"),
send_no_receive(Socket, "From: <___@gmail.com>"),
send_no_receive(Socket, "To: <___@gmail.com>"),
send_no_receive(Socket, "Date: Tue, 15 Jan 2008 16:02:43 +0000"),
send_no_receive(Socket, "Subject: Test message"),
send_no_receive(Socket, ""),
send_no_receive(Socket, "This is a test"),
send_no_receive(Socket, ""),
send(Socket, "."),
send(Socket, "QUIT"),
ssl:close(Socket).

send_no_receive(Socket, Data) ->
ssl:send(Socket, Data ++ "rn").


send(Socket, Data) ->
ssl:send(Socket, Data ++ "rn"),
recv(Socket).

recv(Socket) ->
case ssl:recv(Socket, 0, 1000) of
{ok, Return} -> io:format("~p~n", [Return]);
{error, Reason} -> io:format("ERROR: ~p~n", [Reason])
end.


And the output from the Erlang shell:


3> application:start(ssl).
ok
4> smtp:connect().
"220 mx.google.com ESMTP y37sm613282mug.19rn"
"250 mx.google.com at your servicern"
"334 VXNlcm5hbWU6rn"
"334 UGFzc3dvcmQ6rn"
"235 2.7.0 Acceptedrn"
"250 2.1.0 OK y37sm613282mug.19rn"
"250 2.1.5 OK y37sm613282mug.19rn"
"354 Go ahead y37sm613282mug.19rn"
"250 2.0.0 OK 1242683885 y37sm613282mug.19rn"
"221 2.0.0 closing connection y37sm613282mug.19rn"
ok


The only tricky bit is that for the AUTO LOGIN, the received text and the username and password you send is base-64 encoded. By default the connect is active=false, which means the responses are send to the creating process directly. Using passive mode requires explicit receiving of the response using ssl:recv/2

You’ll have to handle errors better if you use this in production, but the basic protocol is pretty straightforward…

Categories: Blogs  21st Century Code Works  Best of Erlang  

Comments

anonymous avatar

I use R13B & winXP
when I use the up,And the output from the Erlang shell:
1>application:start(ssl).
ok
2>smtp:connect().
***exception exit:no_ssl_server

What’s wrong coudle you tell me?
THX

Posted by tt0786 on 20 May 2009 at 08:11



 
anonymous avatar

@tt0786
You probably need to have open ssl. See this tutorial on CouchDB for more links and info.

http://www.hiveminds.co.uk/?p=35807

Posted by Carl McDade on 23 May 2009 at 09:38



 
anonymous avatar

hi! just tried this code with .(JavaScript must be enabled to view this email address) set up as my address and recipient address (can it be different from gmail?) anyway i used my pwd instead of johngalt and it works til

220 mx.google.com ESMTP y37sm613282mug.19rn”

then i got an error: {error, timeout} any clues?

this topic rules!

Posted by necromoncer on 27 May 2009 at 18:34



 
anonymous avatar

@necromoncer

Make sure to replace ++ “rn” by ++ “\r\n” in send and send_no_recv.

Posted by Dominique Boucher on 10 Jun 2009 at 14:31



 
anonymous avatar

great!thanx a lot man!

Posted by necromoncer on 08 Jul 2009 at 13:18



 
anonymous avatar

seeing erlang do some good job makes me happy, thanks a lot dude
gelinlik
yarış oyunları

Posted by haven on 01 Sep 2009 at 16:18



 
anonymous avatar

Türkiye’nin en büyük anne -bebek & aile yaşam platformu e-bebek ve Anadolu Ulaşım’ın işbirliğinde 1 Eylül 2009 tarihinde başlatılan, “çağrı merkezinden bilet alanlara çocuk koltuğu sağlanması”na yönelik uygulamaya olan ilgi artarak devam ediyor.

1 Haziran 2010 tarihinde yürürlüğe giren, ülkemizde oto koltuğu kullanımını zorunlu hale getiren yasa ile birlikte, seyahatlerde çocuk oto koltuğuna yönelik taleplerde ciddi artış yaşandığına dikkati çeken çocuk oto koltuğu Genel Müdürü Halil Erdoğmuş, ilerleyen dönemde bu talebin daha da artacağını öngördüklerinin altını çiziyor. admin yeah toto :)

Posted by çocuk on 23 Jun 2010 at 21:57



 
anonymous avatar

Do you acquisition Gmail so great, admirable and affected that you wish to handle all your email in it, pass4sure 640-816 not just letters you accept at your gmail address! It’s apparently simple to advanced your plan mail, pass4sure 640-822 for example, to your Gmail account, but the replies with your Gmail abode in band do not attending too good, pass4sure 350-030 do they.

Posted by Foana21 on 11 Feb 2011 at 09:02



 
anonymous avatar

I really love using gmail thanks for the great code
passive niche profits

Posted by jim on 05 Jun 2011 at 23:33



 
anonymous avatar

In case you had some problems with this code (such as closed socket error): add recv(Socket) after the send(Socket, “HELO localhost”) line. Gmail sends additional action complete status (250 code) that needs to be received before sending login and password.

All in all great piece of code, very helpful. With aforementioned fix still works after 2 years. Thanks!

Posted by gregorej on 06 Jun 2011 at 14:18



 


Add comment

Name:

Email:

URL:

Smileys

Remember my personal information

Notify me of follow-up comments?