Fake SMTP server with Python

The other day a colleague was testing some code which relied on sending mail to a local mailserver and it was failing when the mailserver couldn't be found. Needing to install postfix seemed overkill so I decided to look into what could be done to make a fake smtp service.

All that was required was something to pretend to be a real SMTP service as we didn't need to view the messages at all.

Here's the snippet I came up with using the smtpd module in Python:

#!/usr/bin/env python
"""A noddy fake smtp server."""

import smtpd
import asyncore

class FakeSMTPServer(smtpd.SMTPServer):
    """A Fake smtp server"""

    def __init__(*args, **kwargs):
        print "Running fake smtp server on port 25"
        smtpd.SMTPServer.__init__(*args, **kwargs)

    def process_message(*args, **kwargs):
        pass

if __name__ == "__main__":
    smtp_server = FakeSMTPServer(('localhost', 25), None)
    try:
        asyncore.loop()
    except KeyboardInterrupt:
        smtp_server.close()
To use this, save the above as fake_stmp.py and:
chmod +x fake_smtp.py
sudo ./fake_smtp.py

NOTE: Running this requires sudo to bind to port 25 as binding any port < 1024 requires superuser privileges.

Clearly you could easily adapt that to do something more useful if you want to see what's in the messages sent, either by writing messages to a file or printing them to stdout.

If printing them to stdout is what you need then there's also smtpd.DebuggingServer which is a subclass of SMTPServer which prints messages out to stdout. Using that is even easier and can be done with the following one liner:

sudo python -m smtpd -n -c DebuggingServer localhost:25

Again we use sudo in this case because we're using port 25 if you don't want that you can use a port higher than 1024.

To test this out we can use telnet like so:

$ telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.
220 localhost6.localdomain6 Python SMTP proxy version 0.2
HELO localhost
250 localhost6.localdomain6
MAIL FROM: test@test.com
250 Ok
RCPT TO: test@testing.com
250 Ok
DATA
354 End data with .
subject: Hello
to: test@test.com
This is my message
.
250 Ok
QUIT
221 Bye
Connection closed by foreign host.

Over on the terminal running the debugging server you should see the following:

$ sudo python -m smtpd -n -c DebuggingServer localhost:25
[sudo] password for moo: 
---------- MESSAGE FOLLOWS ----------
subject: Hello
to: test@test.com
This is my message
------------ END MESSAGE ------------
comments powered by Disqus