The problem is that, while digging through all of the documentation for Postfix and Sendmail, which are the programs one would typically use to set up these email backends, is that they do way more than I need and are likewise much more complicated than I need (as they should be - email is a hard thing). My project really only needs the most basic of mail processing; receive an email, figure out which account it is addressed to, and extract the subject line and actual body of the email. What I plan on doing with it once I have these things becomes quite a bit easier, so I really only want an email server which can handle the network exchange and then intelligently punt received emails to different programs to do with as they please.
Many moons ago, I happened upon the very interesting Mailinator blog. Mailinator is a rather useful service providing you with disposable email addresses, but what I most enjoy about it is Paul's very interesting technical articles on the trials of writing your own high-performance custom-application mail server. In one of his early articles, he really impressed on the fact that SMTP (Simple Mail Transfer Protocol) is actually a really simple protocol, so I figured that if I think Postfix is too complicated for what I need, why don't I just write my very own mail server from scratch?
SMTP, like the vast majority of protocols used throughout the Internet, has been freely documented in a series of documents called RFCs, or "Request for Comments." Granted, just because something exists as an RFC does not mean that it is actually used, but it's a good place to start looking for how the Internet works. The basics of SMTP happen to be documented in RFC821, which is a somewhat intimidating 67 pages long. It is a running joke that actually trying to read RFCs is a nightmare, and the jokes are mostly correct; reading 67 pages on the gripping subject of how mail is transferred between mail servers is simply not an exciting exercise. On the other hand, once I managed to get 400 lines of C to handle enough of SMTP to receive mail and print it on the screen, that was pretty cool.
How SMTP WorksSMTP really is a very simple protocol. Given an email that needs to be delivered to another server, your mail server connects to port 25 on the remote server, and then trades four letter verbs for three digit return codes. For example, when an exchange first starts, the connecting server sends a "HELO" verb, and the remote server typically responds with a "250" code indicating the completion of the verb. Once a connection is established, moving emails is nothing more than a long series of these back and forth until there's no more work to be done.
The Wikipedia article and the RFC both give simple exchange examples, and I will supplement those with one of my own, captured with my very own SMTP server:
The Source CodeNow let us be very clear here; I am not posting this 400 line SMTP server in the hopes that you find it useful as a mail server. I very much hope that I do not ever actually see a copy of this running in the wild, and here is why: this is not a good SMTP server.
It just isn't. It is a rather neat little toy to play with, and I think it is a very educational example of the basis for how SMTP works, Posix threads, and network programming. That is all I think it is good for, at this point. It isn't done yet, because I have built in almost no safe-guards with respect to remote servers doing anything naughty or unexpected. There is no limits on bandwidth usage, RAM usage, number of connections opened at once, nothing. That being said, all of those things would make this quite a bit longer, and muddle the basics of exactly how it works. I thought you may find this academic example interesting, but dear God don't treat it as anything except an academic example.
That all being said, here is 409 lines of C which can manage to receive basic SMTP transfers from other mail hosts. It does crap out on emails with attachments for some reason that I don't quite understand, but this project is not even close to finished, but simply at a good point for me to take pause for your benefit. Source code: