Project Details

  ReadmeDownload 

Download Version 0.9


Download dev snapshot
View Licence

The role of an MSA (Mail Submission Agent) is defined in RFC2476.

An MSA is like an MTA. It accepts SMTP, but on a different port. The idea is that initial submission of email to a mail relay is a different thing from inter-MTA transfer, so a different port is justified. That means that the incoming connections on port 587 can require authentication (either by source IP or by SMTP AUTH) and then have mail relay access, while incoming connections on port 25 are from the general Internet, and are only accepted for destinations we are MX for.

Many people do everything on port 25, but it complicates things - you need to set up complicated rules about which destination domains to accept mail for in different situations. Also, you often need to recompile your MTA to support SMTP AUTH, and run SASL authentication daemons, and lots of complex configuration - I gave up because I couldn't make it work.

Also, MTAs should not normally alter message headers, but an initially submitted email may have to have a message ID and/or Date etc. added to it. Making a separate MSA allows that separate program to deal with header tidying, meaning MTAs don't have to worry about doing that in the appropriate situations.

What I've done is to leave my Postfix setup alone, but have written a separate daemon to listen on port 587. This daemon has an inbuilt SASL implementation for SMTP AUTH. It implements the required subset of SMTP. It authenticates the user against a password database, then consults a list of From: addresses that user is allowed to send email with. It accepts an email, checks it is from an allowed From: address for that user, adds any missing headers, adds a Received: header (like the one on this email...), then passes the completed email to the local MTA for relaying onwards (by talking to port 25 locally, although it could just invoke "sendmail").

This now means that wherever my laptop sends email from, the email will always be routed across the Internet from one of my two mail servers, meaning I can set my SPF record to only accept email from my domains from those two machines

Since this means all my outgoing email now goes through a central choke point, I've also taken the opportunity to make it add a Hashcash header to every outgoing email.

What might be a nice next step is to make it accept a list of passphrase-less PGP private keys onto its internal keyring, such that it will automatically sign outgoing emails with a per-user PGP key.

BUGS/TODO

Right now, for some reason, when run as a daemon, it corrupts my email. But when run standalone, it doesn't. This appears to be some very low-level issue with Python socket I/O.

Also, it'd be nice to make it authenticate against a POP3 server or other backend rather than having a hardcoded list of passwords inside it.