Hacker News new | comments | ask | show | jobs | submit login
Inbox.py: SMTP for Humans (github.com)
204 points by dshah on May 3, 2012 | hide | past | web | favorite | 51 comments

I'm guessing this is not complete? I'll review it like it is complete though, since it doesn't say anywhere if it is or not.

I hope no one uses this in production. Handling SMTP well is all about the edge cases, and this doesn't seem to handle any of them.

This is just a thin wrapper on python stdlib smtpd.SMTPServer, which is itself not production ready. It also doesn't really make it easier. The original API is better. Why are magic decorators better than inheritance again?

Also, monkey patching? Hidden side effects make sad pandas cry. Let me throw up a little in my mouth.

There are zero unit tests for this, and no functional tests.

The original API has better documentation. What are the to, sender, and body arguments?

Below seems a simpler API, and gives you the subject too. I thought humans would be interested in the subject... but I guess not.

  import inbox
  for m in inbox:
      toprint = m.to, m.from, m.subject, m.body
      print ("to:{} from:{} subject:{} body:{}".format(toprint))

You're right, it's a trivial wrapper with a subjective/opinionated usability improvement.

I think the biggest service here is

1. Education about Python's pretty decent standard smtpd lib.

2. Food for thought about making thin custom interfaces over standard libraries.

3. Perhaps inspiration to do more?

It's no Linux kernel, but I enjoyed reading through the source and I feel like I have a better understanding of Python's smtpd lib and I've some of my own ideas for future API design.

Additionally, I like your generator-based API proposal. Also inspiring. Need to think more about routing in that context, though.

It's quite production ready. I wrote some very similar that has been in production and used by thousands of people for months.

SMTP does have many edge cases, and if you're interested in handling all of them, you should use a more robust server. I am not.

It looks simple and elegant. Can you recommend something equally simple, elegant and freestanding to send email in Python?

I don't understand why the library chooses to require gevent. That's a large dependency for an API that might be useful otherwise. That should really be up to the user since it looks like it'd work fine in its own thread or standalone.

It's to monkey patch the socket code of smtpd to make it async. Apparently that nets a nifty speed bump:

> "One instance should handle over one thousand emails per second, thanks to Gevent."

Take a look at the code, it's very small.

Much easier to sneer than get stuff done, isn't it?


Seconded. Also, why re-invent the wheel? You're not DJB, an even if you were, qmail kinda sucks these days. With exim and postfix already out there...I'm struggling to see a point to this.

Want your app to send some mail? Please please please don't try delivering directly. The only people great at this are spammers. Use a real MTA and the mail() function that is built into basically every language.

This is for receiving mail.

OK. When it comes to email I'm a complete noob. The Github page indicates this is an SMTP server. SMTP is for sending email, right? The examples then goes into an example of creating an inbox, which indicates receiving email. Maybe someone who knows more about this might want to explain?

SMTP is the protocol that mail servers use to send messages between each other, both sending and receiving. POP3/IMAP are protocols that your email client will use between itself and the mail server which allow you to view messages.

edit: I should note that you're correct in that SMTP is used by the client to relay email messages to the server also.

Thanks for that. So what exactly would you be able to use this for?

For one example, this would certainly take care of a lot of the work necessary for creating a disposable email service.

One existing use-case is Facebook's 'reply to this email to post a comment' feature.

Looks like it could be used in an application that needs to send email without relying on a platform-specific SMTP server or external service.

edit: I'm wrong, listen to this guy ->

It's actually for an application that needs to receive an email.

If you run your own mail server, you can usually configure it to forward mail over SMTP to a specific port, rather than delivering it to a mailbox for a client to pick up using IMAP. If you send the mail (using SMTP) to inbox.py, you'll get callbacks as soon as the mail is received, without having to worry about mailbox management and the complexity of an IMAP client.

I think it could probably be called "outbox" instead -- it might make a bit more sense?

This library is for receiving email, new email that you get, is put in your inbox. Email that you are sending goes in your outbox before it is sent. So I think it is named correctly. :)

I've always wanted to make something with http://lamsonproject.org/, another python based SMTP server. This appears to be more bare bones.

Working with Lamson is a very good experience.

Our Lamson project has been running for 3 years. It was fun to write, it stays up when we need it to - and it’s easy to modify when we need new features.

This is the only piece of python we have running in-house - we’re a pair of coders and both of us had had very bad experiences with Python (in the distant past - 2002 for me). It’s done quite a lot to rehabilitate python’s reputation here :)

That's exactly why I made this. Lamson looks fantastic and I've heard wonderful things about it, but my use case is far simpler.

How did you evaluate Lamson if you only "heard" of it?

Non-Invenio Hic .. (bad) Latin for "Hack the good hack" ;-)

Hey really dumb questions, but I'm wondering what some use cases are for this?

Yours is the top voted comment at the moment, so dumb or not, it seems a common question.

Looking just at the two examples on the main page, it's an implementation of the SMTP protocol so you can either send mail directly to recipients' servers, or run a mail server.

Sending mail directly is often useful when you need to deliver a message to a lot of recipients. IIRC, this doesn't always work, because many servers reject messages unless they can reverse resolve the ip to the sender's domain.

A server for receiving messages is basic infrastructure. The reason for using a simple solution with clear source code, instead of established daemons, like postfix, is that you can tune it to implement filters or notifications.

As an example: some time ago I had the idea of putting a bayesian spam filter directly in the server code, eliminating the problem of false positives: the mail is either accepted or rejected, in which case the sender gets to know that the message has not arrived its recipient, instead of silently trashing it as spam.

The problem with rejecting mail as spam explicitly rather than silently dropping it into the spam bin is that it makes it really easy to tune spam so that it gets past your filter. Maybe it doesn't matter so much if it's just for a few people, but if something like that was popular there would be people figuring out how to work around it.

If this were even a tiny bit of an issue then way more spam would hit people's inboxes. Rejecting explicitly is the right thing to do. It's not always possible, but it's definitely preferred.

Source: I wrote some of the original SpamAssassin and worked in anti-spam for over 10 years.

Am I missing something? It seems that most of the functionality is provided by the smtpd lib:


Kenneth's work is always about simplifying APIs. Simple APIs lower barriers to entry, which in turn drive adoption.

Too right! I haven't touched 'urllib' since I discovered 'requests', and now I toss off helpful little scrapers and web API-consuming services without a moment's thought.

Does every single part of the standard library need to be rewritten "for humans" (read: in a certain style)? It seems that there are really better and worse cases for doing this.

Who said anything about being rewritten? These are wrappers.

kenneth, you consistently make simple, badass tools.

thank you, and keep it up.

Highest authority on user-experience for APIs and libraries.

I am puzzled as to why there is a a dispatch() method. Isn't the serve() method enough?

Also, both the Inbox constructor and the serve() method takes the listening port and address. Now I need to read the source code in order to figure out where I should put the port number and what happens if I put in two different port numbers. (insert appropriate sort of unhappy smiley)

I believe my feedback to Kenneth (if he even sees this) is that this SMTP server can be even simpler.

Thanks for the feedback :)

The dispatch method is for deferring to cli arguments for external configuration (say, a Procfile).

The constructor is used for defaults.

I made something like this a long time ago.

No dependencies on third party libraries.


I wrote an extensive C# version of this that runs as a service, includes a MIME parser, filter pipeline and WCF bridge (so you can recieve mail via a net.tcp).

I will clean it up and chuck it on bitbucket.org some time this month.

You just publish an endpoint on your app, fire up the service and emails come in as WCF messages ready parsed.

I'm interested. Will be waiting to review your code.

An interesting similar project for nodejs is haraka: https://github.com/baudehlo/Haraka

It's pretty fast. One benchmark (by the developer) clocked it at 5000 messages/s on his Macbook.

Haraka is the node.js port of the famous perl smtpd called Qpsmtpd. Haraka is developed by the authors of qpsmtpd - and it seems pretty fast: http://baudehlo.wordpress.com/2011/09/13/node-js-is-fast/

Note that Haraka does MUCH more than this simple library. It has a full outbound queue built into it which will send to appropriate MX records for outbound. It has many plugins for processing inbound mail. And yes it is fast - faster than exim or postfix.

Great. I've always wanted to have a simple SMTP server that I could integrate in my projects/unit tests without having to re-invent the wheel. fakemail.py is too old and can't be installed from PyPI.

Anyone else tired of software released with meaningless performance claims? What could it possibly mean to "handle over 1000 emails per second"? Trivial 1-recipient emails?

I'd written a python smtpd for internal use a while back (with code borrowed from tornado's ioloop, ideas from qpsmtpd, twisted etc.)... it's pretty fast (though incomplete): https://github.com/masroore/py-cyclone/blob/master/cyclone.p...


Can someone explain why this has gotten so many votes? Is it because the author is well known in the Python world? Are other Python SMTP libraries terrible?

Is there a Python-based IMAP server?

Twisted has twisted.mail.imap4.IMAP4Server

A somewhat off topic request: could the friendly people writing libraries "for humans" alter their titles to "for humans who like to write Python"?

This particular one isn't so bad, since ".py" is part of the headline, but it's fooled me so many times that it's getting boring. I'm a human. I think SMTP a big hassle. The headline made me think someone somehow reimplemented what SMTP does for us in a modern way. Instead, it's a client library for a programming language that I don't use.

It's too late, he's already got a following. I saw the headline and thought "I hope this is another awesome Python package by Kenneth Reitz!"

My only regret is that it's for receiving rather than sending. I use ugly wrapper scripts for my most common attachment mailing scenarios right now.

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact