Email is the hardest easy problem, and I built a business in it

andris91 pts0 comments

Email is the hardest easy problem, and I built a business in it

Two and a half years ago, I wrote a post here called “How I turned my open source project into a business.” It did better than anything else I had published, and since then, people have kept asking what happened next.<br>That first post was about the change itself: dropping the permissive license, going commercial, and learning to sell to companies instead of hoping for donations. By the time I wrote it, that part had already happened. I had already made the jump.<br>What I did not yet know was what came after. It turns out that changing the license and charging money was not the hard part. The hard part was running the thing afterwards.<br>This is that post.<br>The numbers, since you’ll ask<br>Let me get the interesting part out of the way first.<br>When I wrote the first post, EmailEngine, was doing about €6,100 a month in recurring revenue, or around $6,600 at the exchange rate back then. Today, Stripe tells me that EmailEngine is doing $15,991 a month, an annual run rate just shy of $200,000, across 204 paying companies.<br>So, in two and a half years, revenue has grown about two and a half times. A nice symmetry, even if it did not feel that neat from the inside.<br>Customers are now on every continent except Antarctica. I keep checking. Still nothing from Antarctica.<br>There is still exactly one employee. Me. No funding, no co-founder, no team. I do have a desk in a co-working office now, so technically I can no longer claim “no office.” In the two and a half years since that post, I have pushed around 1,100 commits and cut 123 releases. That is roughly a release a week, every week, for two and a half years.<br>This is not because I am especially disciplined. It is because email is a swamp, and the swamp keeps moving.<br>That is the actual subject of this post.<br>I thought the hard part was the business model<br>When I wrote the first post, I genuinely thought the hard part had been the business side: the license change, the pricing, the decision to sell to companies instead of hoping that random users would sponsor me.<br>That part felt like the big puzzle.<br>In hindsight, it was not.<br>The pricing was a weekend of agonising followed by two years of barely touching it. The license change was scary, but once it was done, it was done. The hard part, the part that never stops, is that EmailEngine sits between customers and other people’s mail systems.<br>And other people’s mail systems are a mess.<br>On paper, EmailEngine is simple. It connects to email accounts using IMAP, Gmail API, or Microsoft Graph API, keeps these accounts in sync, and exposes a clean REST API and webhooks. This means that customers do not have to deal with IMAP commands, Gmail API quirks, Graph subscriptions, OAuth flows, and all the other details themselves.<br>Someone might say that EmailEngine is “just an IMAP client with an API.”<br>Sure. And a submarine is just a boat with a lid.<br>Here is what the work actually looks like.<br>A connection that drops every 3.5 minutes, on purpose, silently<br>A customer in China reported that their 163.com accounts kept dropping. Sync would start, run fine for a few minutes, and then die. Every time. Like clockwork, at about the three-and-a-half-minute mark.<br>163.com runs Coremail and does not support IMAP IDLE, the command that lets the server push changes to the client. That is not unusual. Many IMAP servers do not support IDLE properly, or at all, so the fallback is to send a periodic NOOP command to keep the connection alive.<br>The NOOPs were going out. The server was responding to them. The logs looked fine.<br>The connection still died.<br>It turned out that 163.com keeps its own internal idle timer, and NOOP does not reset it. The server happily responds to the keepalive command and then disconnects the client anyway because, from its point of view, the connection was still idle.<br>The fix was to stop using NOOP as the keepalive command for that server and use STATUS instead, because STATUS counts as real activity.<br>Seven lines of code. Several hours of staring at packet logs that claimed nothing was wrong.<br>Multiply this by every weird mail server on earth. Yahoo cuts IDLE connections aggressively. Rambler breaks them constantly. Each server has some specific undocumented behaviour, and the only way to learn about it is when someone’s accounts stop syncing, and I have to figure out why.<br>The bug where nothing happened, so we missed everything<br>Here is another one. This is my favourite kind of bug: the kind where the code is doing exactly what it was told to do, and that is the problem.<br>To notice new mail efficiently, you do not want to re-scan the entire mailbox every time. You keep some state: how many messages were in the mailbox last time, what the next UID should be, and so on. When the server says that something changed, you compare the old state with the new state.<br>If the message count went up, you fetch the new messages.<br>Simple.<br>Except, what happens if one message arrives and one message...

part post server half business years

Related Articles