Six mailboxes, one inbox
Connect Gmail, Outlook, Yahoo or any IMAP account and read all of it inside Kool, alongside your Kool address. The hard part was not the protocols. It was making very different inboxes feel like one calm list, and most of that difficulty turns out to be about ordering and about lying.
Start with the ordering, because it is not the same in both directions and the asymmetry is deliberate.
When mail arrives, we store it and then tell the app. When you send mail, we hand it to the provider and only then write the row into Sent. Those are opposite orders, and each is chosen against the failure that matters on that side.
On the receive path, a missing row loses mail. If we notify first and the write fails, a message exists in the world and not in your inbox, and nothing will ever go looking for it again. So the record comes first.
On the send path, a spurious row invents mail. A Sent row written before the provider accepted the message is one the app displays as sent, with a tick, for something that never left the building. And inventing is worse than losing here, because nobody re-sends what they can already see in Sent. The person has visual confirmation of a thing that did not happen, and the system will never correct them.
That is the rule underneath a lot of this work: when you cannot have both, decide whether this particular failure would rather lose something or invent something, and order your writes accordingly.
The other half of "one calm list" is that the seams between providers have to stop existing for the reader, without pretending to the code that they are not there.
An example we got wrong. Kool addresses are their own provider alongside Gmail, so a message id can be a row in our database or an id that belongs to Google. The Summarize feature took an id and asked Google about it. For a Gmail message that worked. For a Kool message Google quite reasonably answered 404, our route turned that into its own 404, and the app printed "Couldn't summarize this email." One feature, working on one account and failing on another, for a reason that has nothing to do with summarising.
The fix was not to add a second route and make the client choose. It was to let the lookup return null, meaning precisely "not mine, ask Google". One route serves both providers, the branch lives in one place, and the client stays ignorant of a distinction that is none of its business. A null with a documented meaning is often a better interface than a second endpoint.
The reader should never have to know which server their mail came from. Everything else is bookkeeping, done in the right order.