Provide a generic Erlang SMTP server framework that can be extended via
callback modules in the OTP style. A pure Erlang SMTP client is also included.
The goal is to make it easy to send and receive email in Erlang without the
hassle of POP/IMAP. This is *not* a complete mailserver - although it includes
most of the parts you'd need to build one.

The SMTP server/client supports PLAIN, LOGIN, CRAM-MD5 authentication as well
as STARTTLS and SSL (port 465).

Also included is a MIME encoder/decoder, sorta according to RFC204{5,6,7}.

IPv6 is also supported (at least serverside).

I (Vagabond) have had a simple gen_smtp based SMTP server receiving and parsing
copies of all my email for several months and its been able to handle over 100
thousand emails without leaking any RAM or crashing the erlang virtual machine.

Current Participants

+ Andrew Thompson (andrew AT
+ Jack Danger Canty (code AT
+ Micah Warren (micahw AT

Who is using it?

+ gen_smtp is used to provide the email functionality of [OpenACD](
+ gen_smtp will be used as both the SMTP server and SMTP client for [Zotonic]( as of version 0.7
+ [Chicago Boss]( uses gen_smtp for its mail API.
+ [Gmailbox]( uses gen_smtp to provide a free email forwarding service.

If you'd like to share your usage of gen_smtp, please contact me.

Client Example

Here's an example usage of the client:

gen_smtp_client:send({"", [""],
 "Subject: testing\r\nFrom: Andrew Thompson <>\r\nTo: Some Dude <>\r\n\r\nThis is the email body"},
  [{relay, ""}, {username, ""}, {password, "mypassword"}]).

The From and To addresses will be wrapped in &lt;&gt;s if they aren't already,
TLS will be auto-negotiated if available (unless you pass `{tls, never}`) and
authentication will by attempted by default since a username/password were
specified (`{auth, never}` overrides this).

If you want to mandate tls or auth, you can pass `{tls, always}` or `{auth,
always}` as one of the options. You can specify an alternate port with `{port,
2525}` (default is 25) or you can indicate that the server is listening for SSL
connections using `{ssl, true}` (port defaults to 465 with this option).

    send(Email, Options)
    send(Email, Options, Callback)
    send_blocking(Email, Options)

The `send` method variants `send/2, send/3, send_blocking/2` take an `Options` argument.
`Options` must be a proplist with the following valid values:

  * **relay** the smtp relay, e.g. `""`
  * **username** the username of the smtp relay e.g. `""`
  * **password** the password of the smtp relay e.g. `"mypassword"`
  * **auth** whether the smtp server needs authentication, valid values are `if_available` and `always`, Defaults to `if_available`. If your smtp relay requires authentication set it to `always`
  * **ssl** whether to connect on 465 in ssl mode, Defaults to `false`
  * **tls** valid values are `always`, `never`, `if_available`. Most modern smtp relays use tls, so set this to `always`, Defaults to `if_available`
  * **tls_options** used in `ssl:connect`, More info at , Defaults to `[{versions , ['tlsv1', 'tlsv1.1', 'tlsv1.2']}]`, This is merged with options listed at: . Any options not present in this list will be ignored.
  * **hostname** the hostname to be used by the smtp relay, Defaults to: `smtp_util:guess_FQDN()`. The hostname on your computer might not be correct, so set this to a valid value.
  * **retries** how many retries per smtp host on temporary failure, Defaults to 1, which means it will retry once if there is a failure.

DKIM signing of outgoing emails

You may wish to configure DKIM signing [RFC6376]( of outgoing emails
for better security. To do that you need public and private RSA keys, which can be generated by
following commands:
openssl genrsa -out private-key.pem 1024
openssl rsa -in private-key.pem -out public-key.pem -pubout
To send DKIM-signed email:
{ok, PrivKey} = file:read_file("private-key.pem"),
DKIMOptions = [
    {s, <<"">>},
    {d, <<"">>},
	{private_key, {pem_plain, PrivKey}}]}
    %{private_key, {pem_encrypted, EncryptedPrivKey, "password"}}
SignedMailBody = \
 mimemail:encode({<<"text">>, <<"plain">>,
                  [{<<"Subject">>, <<"DKIM testing">>},
                   {<<"From">>, <<"Andrew Thompson <>">>},
                   {<<"To">>, <<"Some Dude <>">>}],
                  <<"This is the email body">>},
                  [{dkim, DKIMOptions}]),
gen_smtp_client:send({"", [""], SignedMailBody}, []).
Don't forget to put your public key to `` TXT DNS record as smth like
v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBA......
See RFC6376 for more details.

Server Example

gen_smtp ships with a simple callback server example, smtp_server_example. To start the SMTP server with this as the callback module, issue the following command:

gen_smtp_server starting at nonode@nohost
listening on {0,0,0,0}:2525 via tcp

By default it listens on port 2525. You can telnet to it and test it:

^andrew@orz-dashes:: telnet localhost 2525                                                      [~]
Connected to localhost.
Escape character is '^]'.
220 localhost ESMTP smtp_server_example
250-SIZE 10485670
250 WTF
250 sender Ok
250 recipient Ok
354 enter mail, end with line containing only '.'
Good evening gentlemen, all your base are belong to us.
250 queued as #Ref<>
221 Bye
Connection closed by foreign host.

You can configure the server in general, each SMTP session, and the callback module, for example:

gen_smtp_server:start(smtp_server_example, [[{sessionoptions, [{allow_bare_newlines, fix}, {callbackoptions, [{parse, true}]}]}]]).

This configures the session to fix bare newlines (other options are 'strip', 'true' and 'false', false rejects emails with bare newlines, true passes them through unmodified and strip removes them) and tells the callback module to run the MIME decoder on the email once its been received. The example callback module also supports the following options; relay - whether to relay email on, auth - whether to do SMTP authentication and parse - whether to invoke the MIME parser. The example callback module is included mainly as an example and are not intended for serious usage. You could easily create your own callback options.

You can also start multiple SMTP listeners at once by passing more than 1 configuration:

gen_smtp_server:start(smtp_server_example, [[], [{protocol, ssl}, {port, 1465}]]).

This starts 2 listeners, one with the default config, and one with the default config except that its running in SSL mode on port 1465.

You can connect and test this using the gen_smtp_client via something like:

gen_smtp_client:send({"", [""], "Subject: testing\r\nFrom: Andrew Thompson \r\nTo: Some Dude \r\n\r\nThis is the email body"}, [{relay, "localhost"}, {port, 1465}, {ssl, true}]).

If you want to listen on IPv6, you can use the {family, inet6} and {address, "::"} options to enable listening on IPv6.

Live Instance

If you want, you can connect to a live instance at (its also the MX record for Its listening on both IPv4 and v6.