Over the last week I’ve been doing a huge amount of refactoring of Blackhole as well as writing dozens of additional tests. To make Blackhole more testable I needed to make a big change to how the program is launched and controlled.

setup.py scripts vs. entry_points

Whenever I’ve written Python programs that require some kind of command line script I’ve always used distutils’ scripts, this can be seen in blackhole’s setup.py on GitHub or in the three line example below.


In doing so, it allowed me to be lazy and write a lot of prodecural code in the main “binary” which made it pretty much impossible to test. You can also see that on GitHub in the main “binary”.

I’ve noticed that most people who write Python packages that have some kind of command line entry point use distutils …

Blackhole has always been able to handle unencrypted SMTP and for a long time it’s been able to handle encrypted SMTP via TLSv1.

One thing Blackhole hasn’t been able to do until the 1.7.0 release is handle STARTTLS.

In the past the STARTTLS command would cause Blackhole to return the standard 250 OK response but would continue to operate on unencrypted SMTP.

I wanted to fix this and do it properly, but this meant learning how to do so with Tornado, which itself proved to be tricky. I ended up deciding to go to my local coding spot - the pub and hash it out.


The first thing I had to do was refactor the code that created the instance of tornado.iostream.IOStream and tornado.iostream.SSLIOStream so that it didn’t actually do the ssl wrapping.

def connection_stream(connection):
    Detect which socket the connection …

As part of my effort to make Blackhole as useful and usable as possible, I needed to be able to support SSL/TLS enabled connections.

Tornado itself has two built-in IOStreams that help us do the job; the first is the standard IOStream and the second is the SSLIOStream.

With this in mind we simply need to spawn two sockets, by default these listen on port 25 for standard SMTP and port 465 for SSL/TLS encrypted SMTP. With these two sockets bound we’re then very simply able to listen for incoming connections on either socket and use socket.socket.getsockname() to figure out if the connection is to the encrypted or unencrypted socket.


def connection_stream(connection):
    Detect which socket the connection is being made on,
    create and iostream for the connection, wrapping it
    in SSL if connected over the SSL socket.

    The parameter 'connection' is an instance …

I have been a frequent audience member of DJUGL for a few years now and spend most of the time asking questions, playing devils advocate and generally being my annoying self.

I have repeatedly said I would do a talk but never got round to it until Jon basically forced me to get round to it.

My talk was on blackhole/blackhole.io and covered several topics including PyPy, SimpleMTA and moved on to talking about spamming and starting work on my honey pot suite called Nectar.

You can find the slides on Speaker Deck, sadly I ran out of time when creating them and although I was promised time to finish them at work, I got busy. So I replaced content with “Taylor Replacements(tm)”.

The event, attendees and other speakers are listen on the Lanyrd event page.

Several people took photos of the event, I don’t remember …

I have built and released an open-source email server in the past for testing send rates and speeds, this project was called SimpleMTA and is available here.

Recently I have rebuilt this project for an internal project at work using the Tornado framework. Sadly this project as a whole cannot be released but a version of this code will be released in the near future.

Until that is released I have launched a new service called blackhole.io

What is blackhole.io?

blackhole.io is a completely open mail relay that forgets anything that is sent to it, meaning there is no auth requirements and no storage of email data within the service. Literally anyone can send anything to it and have it never get delivered.

You can even send commands out of order, meaning you can call the DATA command without ever using HELO, MAIL FROM or RCPT TO …

This really should be quite a quick and simple post.

I use several tools to protect my mail servers from spam, the most effective of these I’ve found is using external lists in conjunction with reject_rbl_client and reject_rhsbl_client.

+======================+======================================================================================================+ | Service | description | +======================+======================================================================================================+ | zen.spamhaus.org | A single lookup for querying the SBL, XBL and PBL databases. | | | - SBL - Verified sources of spam, including spammers and their support services | | | - XBL - Illegal third-party exploits (e.g. open proxies and Trojan Horses) | | | - PBL - Static, dial-up & DHCP IP address space that is not meant to be initiating SMTP connections | +———————————+———————————————————————————————————————————————————+ | dnsbl.sorbs.net | Unsolicited bulk/commercial email senders | +———————————+———————————————————————————————————————————————————+ | spam.dnsbl.sorbs.net | Hosts that have allegedly sent spam to the admins of SORBS at any time | +———————————+———————————————————————————————————————————————————+ | b1.spamcop.net | IP addresses which have been used to transmit reported email to SpamCop users | +———————————+———————————————————————————————————————————————————+ | rhsbl.ahbl.org | Domains sending spam, domains owned by spammers, comment spam domains, spammed URLs …