Getting Started


Install Salmon from PyPI:

$ pip install [--user] salmon-mail

Now run the gen command to create the basic layout of your first project:

$ salmon gen myproject

Then change directory to myproject


Users of older versions of Salmon should note that the project template now uses LMPTReceiver as its default


Handlers are how your application will process incoming mail. Open app/handlers/ and you’ll see the following:

from salmon.routing import route, route_like

@route("(address)@(host)", address=".+")
def START(message, address=None, host=None):
    return NEW_USER

def NEW_USER(message, address=None, host=None):
    return NEW_USER

def END(message, address=None, host=None):
    return START

Each handler returns the next handler for that sender. START is the default handler for senders that Salmon doesn’t know about. This state is stored in memory by default.

Let’s start up a server and see how it all works:

$ salmon start
$ salmon status
Salmon running with PID 4557

If you look at logs/salmon.log, you’ll see various start-up messages from Salmon.

Now send an email to our server:

$ telnet localhost 8823
Connected to localhost.
Escape character is '^]'.
220 localhost Salmon Mail router LMTPD, version 3
250 Ok
250 Ok
354 End data with <CR><LF>.<CR><LF>
250 Ok
221 Bye
Connection closed by foreign host.

Check logs/salmon.log and you’ll see the following lines:

2016-01-11 00:49:49,947 - root - DEBUG - Message received from Peer: ('', 38150), From: '', to To [''].
2016-01-11 01:00:49,949 - routing - DEBUG - Matched '' against START.
2016-01-11 01:00:49,949 - sample_app - INFO - START:
2016-01-11 01:00:49,950 - routing - DEBUG - Message to was handled by app.handlers.sample.START

If you send the message again you’ll see this:

2016-01-11 01:01:36,486 - root - DEBUG - Message received from Peer: ('', 54628), From: '', to To [''].
2016-01-11 01:01:36,487 - routing - DEBUG - Matched '' against NEW_USER.
2016-01-11 01:01:36,488 - routing - DEBUG - Message to was handled by app.handlers.sample.NEW_USER

As the NEW_USER handler returns itself, every message from “sender@example” will now be processed by NEW_USER

Once you’re done, stop the server:

$ salmon stop
Stopping processes with the following PID files: ['./run/']
Attempting to stop salmon at pid 4557


By deafult, all configuration happens in config/

This file is used by Salmon during start-up to configure the daemon with various things, such as starting the LMTPReceiver. It’s a bit like the file that Python web apps have. If you want to use a different boot module, you can specify it with the --boot argument. E.g. to use myapp/, do:

salmon start --boot myapp.othermodule

Just like, except for testing. You can specify --boot config.testing when starting Salmon to try it out.

logging.conf and test_logging.conf

Standard Python logging configuration files. See Python’s documentation for more details.

This file contains generic settings used by the rest of your application, e.g. which port the receiver should listen to. The default settings module is config.settings

You can specify a different settings module via the environment variable SALMON_SETTINGS_MODULE:

SALMON_SETTINGS_MODULE="myapp.othersettings" salmon start


Salmon is best deployed behind another mailserver such as Postfix or Sendmail - much in the same way as you host a WSGI application behind Apache or Nginx.

As seen above, a new Salmon project will start a LMTP server that listens on localhost:8823. You can go into config/ and change the host and port Salmon uses. You can also switch out LMTPReceiver for SMTPReceiver if you require Salmon to use SMTP instead.


Due to the way Salmon has been implemented it is better suited as a LMTP server than a SMTP server. SMTPReceiver is unable to handle multiple recipients in one transaction as it doesn’t implement the nessessary features to properly implement this part of the SMTP protocol. This is a compromise SMTPReceiver makes in order to allow users more freedom in what they do in their handlers.

LMTPReceiver is unaffected by this issue and implements the LMTP protocol fully.