SMTP, SSL and Haskell

Sending an email from the Haskell code

When writing server application there comes a time when you need to notify someone about an unexpected behavior. Or maybe you just need to report each day that the code is functioning as expected.

Email is the best and the simplest way to do that. Of course there are other ways, but usually they require more upfront setup.

One would expect that given ubiquity of email each language will have mature and easy to use solution for that purpose.

When I had to accomplish this task in Haskell I quickly run into problems, but let’s start from the beginning.

As with everything Haskell related my first step were directed to Hackage. A quick search resulted in a package which looked perfect.

smtp-email provides a simple interface:

sendMailWithLogin :: HostName ->
                     UserName ->
                     Password ->
                     Mail ->
                     IO ()

It even exposes Mail constructor, so one doesn’t have to depend on mime-mail. All very convenient.

The library works great but there is a catch. It doesn’t support SSL and nowadays that means you cannot use it with almost any SMTP server.

I had to find a way to connect to SMTP server using SSL and only then to send a message.

A lot of searching, mostly on Stack Overflow finally brought a clue that I should be using HaskellNet-SSL package. Together with HaskellNet and mime-mail, I was able to finally accomplish my goal. Here’s the code:

import Control.Monad
import Data.ByteString.Lazy (toStrict)
import Data.Text (unpack)
import Data.Text.Lazy (Text)
import Network.HaskellNet.Auth
import Network.HaskellNet.SMTP
import Network.HaskellNet.SMTP.SSL
import Network.Mail.Mime

toString :: Address -> String
toString Address { addressEmail = email } = unpack email

sendEmail :: Mail -> IO ()
senEmail msg = do
  rendered   <- renderMail' msg
  doSTTPSSL "smtp.example.com" $ \connection -> do
      succeeded  <- authenticate LOGIN
                                 "username"
                                 "password"
                                 connection
      when succeeded $
          sendMail (toString (mailFrom msg))
                   (map toString (mailTo msg))
                   (toStrict rendered) connection

There’s not a lot of code to accomplish the task. It’s basically an example how to combine those three packages together.

The HaskellNet-SSL library also exposes STARTTLS methods, so that can be used in place of SSL.