HackerTrans
TopNewTrendsCommentsPastAskShowJobs

brongondwana

no profile record

Submissions

Email immutability matters more in a world with AI

fastmail.com
166 points·by brongondwana·9 mesi fa·111 comments

comments

brongondwana
·3 mesi fa·discuss
Tell the world you're REALLY fat without telling the world ...
brongondwana
·5 mesi fa·discuss
Damn, $2000. I wish I'd kept my copy.
brongondwana
·6 mesi fa·discuss
Did you use the 'litmus' test suite? I found it very useful when building Fastmail's (perl) WebDAV file server implementation.

There were also a bunch of fun things with quirks around unicode filename handling which made me sad (that was just a matter of testing against a ton of clients).

As for CalDAV and CardDAV - as others have said, JMAP Calendars/Contacts will make building clients a lot easier eventually... but yeah. My implementation of syncing as a client now is to look for sync-collection and fall back to collecting etags to know which URLs to fetch. Either way, sync-collection ALSO gives a set of URLs and then I multi-get those in batches; meaning both the primary and fallback codepath revert to the multi-get (or even individual GETs).
brongondwana
·9 mesi fa·discuss
The good news is, you have less time to be annoyed by it
brongondwana
·9 mesi fa·discuss
You're welcome! We're all very keen on keeping email open and something that everybody can build their own tools for.
brongondwana
·9 mesi fa·discuss
We're working on it. We still use an unholy set of earlier versions of JMAP internally for our contacts and calendars; in particular the caldav_sync code is gnarly - I wrote it over 10 years ago when I knew less about calendars than I do now! It's still using an earlier branch of what became the perl Net::CalDAVTalk library interally, even though our frontend API is an almost-up-to-date version of what will become the JMAP Calendars spec eventually.

The downsides of developing and testing this stuff as we were writing it up!

We've finished rewriting the objectid generation to give smaller sized and more sortable IDs (they're an inverse of nanosecond internaldates now, plus some extra magic on the low bits for IMAP appends to avoid clashes)... which we wanted to speed up and reduce disk usage for the offline mode.

Next up is indeed updating to the latest spec on calendars and contacts. Files might take a bit longer, I really want to do some desktop clients for the files system, we have a really nice files backend at Fastmail which is only accessible via our interface or WebDAV right now.
brongondwana
·9 mesi fa·discuss
That's not strictly true. IMAP has two things, UIDs which are mostly static (there's a UIDVALIDITY cache invalidation key to let a client know that UID information has been lost and recalculated); and message numbers.

UIDs don't change, but of course they can be deleted so it's a gappy list, meaning you can request even quite a large looking range of UIDs and get nothing back.

Message numbers change in every session, and also change every time you get an EXPUNGE. They're basically an ordered list without gaps, so you do a memmove at the offset of the EXPUNGE each time you get an expunge.

There are efforts like UIDONLY (RFC9586) to avoid having to keep that mapping at all, and there's OBJECTID (RFC8474) to let you cache a lot more even when UIDs are changed or when messages are moved between folders.
brongondwana
·9 mesi fa·discuss
JMAP is only JSON over HTTP because that's what all the libraries support. Any data format which provides hashes and arrays would work fine, over any transport. So you could use CBOR or protocol buffers or whatever, over any channel you like.
brongondwana
·10 mesi fa·discuss
Join the club, we have compulsive mouse habits.

(am a member of this select club)
brongondwana
·2 anni fa·discuss
You cite a 5 year old post. We have improved things since then. You can't spoof other people through Fastmail any more, we verify permission to send as any address - either through your account owning the domain or alias - or by authenticating the specific address by confirming you can receive an email there.

If you have your own domain, you can set whatever DMARC policy you like on it. We'll DKIM sign your email for you if your domain is configured to use the keys we create for you, or do your own outbound email as you want.

Also the whole thing about STARTTLS is bogus - that site says "Unable to determine STARTTLS status" - too right. Because we're not listening on those ports. Because that's less secure that only allowing the SSL/TLS ports.

We have written about our reasoning here: https://www.fastmail.help/hc/en-us/articles/360058753834-SSL...

The key paragraph is this:

Today, many email services, including Fastmail, now disable plain text IMAP and POP logins entirely on ports 143 and 110, leaving encrypted connections on ports 993 and 995 as the only option. This makes sure all clients use encrypted SSL/TLS connections to protect sensitive data.

(Disclosure: I'm the CEO at Fastmail)
brongondwana
·7 anni fa·discuss
Not full history as in "you can rewind back in time and see every possible past state", no. If I wanted one of those, I'd probably use git as the substrate.

The thing JMAP doesn't have, that I think you're trying to ask for, is the ability to talk to divergent endpoints and resolve the state on the client. JMAP expects to talk to a server which is merging the state into a linear world for it. That linear world view can be different from different servers.

For example, if you implemented your server as a series of git commits, complete with merges whenever you'd had changes on two different servers, then you could just use a commit hash as the state string - and if you got an oldState which was a commit that didn't happen on your server you could still use git to calculate the series of changes on your branch since the fork point plus changes on the remote branch after that commit - and you'd be able to issue a full set of changes. If you DON'T have at least that commit and its predecessors locally, you can't calculate the diff, so you have to return cannotCalculateChanges.

I think what you're wanting here is for the server to get from the client what the last fork point was, and give the client just the changes it knows about since that fork point (like a git fetch) and then the client calculates the merged changes. That's not how JMAP is designed to work. It's an interesting idea, but it does lead to very high client complexity, so it's not what we wanted JMAP to be.

The CRCs are 32 bits, but they're not the only signal. There's also modseq and uidnext, so the CRC doesn't need to be cryptographically strong - if somebody deliberately creates a replica state that comes up with the same CRC but has different content then they could make servers believe they are in sync, but in that attack vector they probably also have enough control to just make the replication layer lie.

We're also using sha1 for message content integrity, which I'd like to move away from eventually. There are plans, but we have other things to finish first. We do insert some randomness into a header on message delivery which makes it much harder for someone to calculate what will be injected when sending somebody an email via SMTP!
brongondwana
·7 anni fa·discuss
That would be a pretty massive change to the entire data model of IMAP. It's never going to happen[tm]. IMAP4rev2 is much more conservative than that.

https://datatracker.ietf.org/doc/draft-ietf-extra-imap4rev2/

Merkle tree would is great for full history - I built something like that with digital signing for tracking clinical data over 15 years ago that would have been fine for email as well - but it's way over-expensive for email.

Which leads back to the key design principle I try to use when working on protocols, which is something like "make the weird edge cases sand and possible, but don't optimise them!" You don't want to build the Merkle tree complexity into a client and have all the servers be completely independent, because it makes the protocol a pain to use for the simple case.

(What we use for IMAP replication in Cyrus is much dumber than all this - it uses a per-message CRC and XORs them together for the whole mailbox to create the sync_crc value. If those don't match, it does a resync. Fixes up split brain just fine while being cheap and dumb for the common case.
brongondwana
·7 anni fa·discuss
Well, it depends on how you architect your system - you can embed whatever you like in your state. I'd probably do something cheap and nasty like embed a modseq counter for each of the different servers into the state string, and if any of them went backwards I'd reject the /changes with a cannotCalculateChanges error.

I mean, you can do other things - but at the point where you're switching between multiple masters in a split brain from your client, all bets are off - so you're going to need to fall back resyncing any mutable data.
brongondwana
·7 anni fa·discuss
Individual unique IDs and /changes lists all the IDs that might have changed. One good thing about IMAP is that there's a fair bit of data which is immutable, and JMAP retains that - emails with the same ID must have the same content, so there's a limited amount of metadata that you need to resync.

I wrote something about how you fix UID clashes in a split brain while staying within the IMAP data model many years ago...

https://lists.andrew.cmu.edu/pipermail/cyrus-devel/2010-July...
brongondwana
·7 anni fa·discuss
Thanks! Have fixed the copy. The link was going to the right place, but somebody (possibly me) put the digits in the wrong order.

For your efforts, please enjoy a joke: https://comic.browserling.com/tag/multithreading

(that's my excuse - brain was running multithreaded output to the fingers)
brongondwana
·7 anni fa·discuss
The problem with being clever and efficient is that you wind up having to write things like:

https://tools.ietf.org/html/rfc6868

Which is the kind of horror case of trying to do everything with clever little pieces of micro-format.

Now, the argument between XML and JSON is less of a big deal, except XML gets wishy-washy with whitespace in some ways which frustrate me. JSON number handling is screwy, it's true. I'd be tempted by CBOR if there were no other considerations - and I'd love to write a JMAP-over-CBOR or JMAP-over-ASN.1 or whatever at some point.

But you can very easily structure non-binary data in and out of JSON reliably, and everyone can get a parser which works. That's a big win. It's fine to disregard edge cases if you stay away from the edges - for example if you're serialising integers between 0 and 1000 then the fact that your datatype isn't 256 bit clean isn't a big deal. Same way you can use Newtonian physics when dealing with sprinters - but I don't think that race organisers have little concern for running a race correctly because they don't factor in relativity.

So we kept JMAP in the safe subset of JSON, because it's the best format for a whole lot of other reasons.
brongondwana
·7 anni fa·discuss
I've started defining the bits necessary for storing push subscriptions: see

https://github.com/cyrusimap/cyrus-imapd/commit/7144a747267c...

But it's rudimentary - it will need sql_db and dblookup components to make it fast enough to integrate with an mboxevent reading component to do the actual pushes. At least - that's how we'll probably implement it at Fastmail, and there's a plan to extract the key parts of our non-blocking push daemon and lift them up into the Cyrus project.
brongondwana
·7 anni fa·discuss
You're very welcome to join the EXTRA working group at IETF and propose the extensions that you think would make IMAP better. Apart from working on JMAP, I have also written an extension to IMAP and may write another one next year bringing some of the push stuff from JMAP back to IMAP as well. But JMAP is based on many years of working on servers, middleware and (at least on the web) clients.

We did actually extent IMAP with some experimental stuff first (cross folder threading and thread collapsing for example) but it never solved the batching and proxying difficulties and the cost of instantiating message numbers per-session that are un-avoidable parts of the IMAP model. By the way, engineers who work on other servers have said similar things to us - IMAP is costly to implement in terms of server resources when you're doing true concurrency, high availability, etc.