4,501 karma · joined January 9, 2012
co-chair of IETF CALEXT, EXTRA, JMAP and SEDATE working groups
Cyrus IMAP developer
Parent, Group Fitness Instructor, Chorister, Human
There are a lot of delays and cross-checks built into our process for re-enabling access to your account, because it would be catastrophic to let the wrong person into an account because they claimed to be that person and to have "lost their password". So a "don't give access" failure is generally less costly than a "give access incorrectly" failure.
It sure sucks to be on the wrong side of one of those failures though. If you ever do give us another try, I hope it goes much more smoothly for you.
Re-launching might be costly, but dropping millions more on a second location and splitting our systems more would hav been much riskier (note: many of our customers with 'fastmail.com' addresses have chosen the EU region, we can't segment MX records at a tighter boundary than domain level).
So we do what we can - when you login with username and password, the password is only sent to your region's server (based on a lookup from the username which MUST be global, so it works regardless of which of our servers you hit). If you send a username which doesn't exist, we distribute you to a random region in the same percentage, so you can't use it as an existence oracle.
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).
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.
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.
(am a member of this select club)
[TIL - it's not even as old as me!] https://australianfoodtimeline.com.au/1978-launch-of-big-m/
You can see all the code for that in a handful of merge requests in the public cyrus-imapd repository on github at https://github.com/cyrusimap/cyrus-imapd/
Over the past few weeks, I've been helping out with the last bits of code modification, largely the changes on https://github.com/cyrusimap/cyrus-imapd/pull/5539 if you're interested.
This morning we rolled out a build which we'd tested extensively on our staging and staff servers, but missed that for older v19 mailboxes which hadn't been upgraded to v20, the code to check if messages belonged in a thread incorrectly marked them all as missing.
This made MOST emails appear missing for most customers, clearly a very bad situation.
We immediately rolled back, but in the hurry missed that an unrelated change to correct subject matching for some languages (Japanese users had reported the issue, but possibly others as well) had changed the thread version, so new threads then had failed reads (making some, though many fewer, messages appear blank in the UI). There were about 50 million attempts to read those values over 15,000 users, because our UI was keeping on retrying thinking it was just a temporary synchronisation issue because the previous request told it there was a Thread to fetch data for. Ouch. https://github.com/cyrusimap/cyrus-imapd/pull/5527 contains those changes.
Anyway, since the only difference between the old and new records was normalisation of subjects, I wrote a tiny patch to let the old code read the newer records and just deployed that, which made all the emails re-appear for everyone again. This is the one bit of code from all this which isn't in a public repo, but it's two lines of: if (version == 2) version = 1;
Meanwhile, the real bug is fixed https://github.com/cyrusimap/cyrus-imapd/pull/5553 And a test has been written to prove it: https://github.com/cyrusimap/cyrus-imapd/pull/5554
But we'll wait until Monday to upgrade again, when we have fresh eyes available to watch that it's OK.
...
P.S. this is almost entirely unrelated to the UI changes. The underlying reason we're doing these changes IS related to UI changes, it's there to make offline mode use storage more efficiently on your device because the IDs are smaller and provide better data locality, but the timing is purely coincidental. The Cyrus changes have been done almost exclusively by the team in the USA and the UI changes by the team in Australia, and our deploy timelines were not synchronised.
The larger context is that we're making a major change to how we create IDs for email and mailboxes over the JMAP protocol. The old IDs are a UUID for mailboxId and the first 25 chars of the sha1 of the message for the emailId, prefixed by an 'M'. The new IDs are the createdmodseq for the mailbox prefixed by a 'P' (these are pretty short for most users) and a reverse counter of nanoseconds of the message internaldate (delivery time) for the emailId. This gives good storage density for offline and good data locality in databases for the email listings.
You can see all the code for that in a handful of merge requests in the public cyrus-imapd repository on github at https://github.com/cyrusimap/cyrus-imapd/
Over the past few weeks, I've been helping out with the last bits of code modification, largely the changes on https://github.com/cyrusimap/cyrus-imapd/pull/5539 if you're interested.
This morning we rolled out a build which we'd tested extensively on our staging and staff servers, but missed that for older v19 mailboxes which hadn't been upgraded to v20, the code to check if messages belonged in a thread incorrectly marked them all as missing.
This made MOST emails appear missing for most customers, clearly a very bad situation.
We immediately rolled back, but in the hurry missed that an unrelated change to correct subject matching for some languages (Japanese users had reported the issue, but possibly others as well) had changed the thread version, so new threads then had failed reads (making some, though many fewer, messages appear blank in the UI). There were about 50 million attempts to read those values over 15,000 users, because our UI was keeping on retrying thinking it was just a temporary synchronisation issue because the previous request told it there was a Thread to fetch data for. Ouch. https://github.com/cyrusimap/cyrus-imapd/pull/5527 contains those changes.
Anyway, since the only difference between the old and new records was normalisation of subjects, I wrote a tiny patch to let the old code read the newer records and just deployed that, which made all the emails re-appear for everyone again. This is the one bit of code from all this which isn't in a public repo, but it's two lines of: if (version == 2) version = 1;
Meanwhile, the real bug is fixed https://github.com/cyrusimap/cyrus-imapd/pull/5553 And a test has been written to prove it: https://github.com/cyrusimap/cyrus-imapd/pull/5554
But we'll wait until Monday to upgrade again, when we have fresh eyes available to watch that it's OK.
...
P.S. this is almost entirely unrelated to the UI changes. The underlying reason we're doing these changes IS related to UI changes, it's there to make offline mode use storage more efficiently on your device because the IDs are smaller and provide better data locality, but the timing is purely coincidental. The Cyrus changes have been done almost exclusively by the team in the USA and the UI changes by the team in Australia, and our deploy timelines were not synchronised.
So you'd have something like:
DKIM2: i=1; mf=sender@trusted.com; rt=accounts-payable@example.com; d=trusted.com
DKIM2: i=2; mf=bounce@example.com; rt=me@mydomain.com; d=example.com
So I could tell that the message came through example.com, and verify their signature on the message, as well as verify that trusted.com had intended the message to go to example.com in the previous hop.
https://datatracker.ietf.org/doc/draft-chuang-dkim2-dns/
https://datatracker.ietf.org/doc/draft-gondwana-dkim2-header...
https://datatracker.ietf.org/doc/draft-gondwana-dkim2-modifi...
https://datatracker.ietf.org/doc/draft-robinson-dkim2-bounce...
https://datatracker.ietf.org/doc/draft-robinson-dkim2-messag...
https://datatracker.ietf.org/doc/draft-gondwana-dkim2-motiva...
Note that it doesn't help avoid Google actually sending out a message with user-provided text in it, but it does stop it being replayed to you without Google intending it, because the SMTP FROM/TO are protected.
The motivation draft doesn't include technical detail, see early drafts of the technical detail in the various related docs at:
(I guess a hotel which had children allowed and non-children allowed sections far enough apart that you could have a child-free area would be a possible workaround; in the same way that not EVERY room needs to be handicap-friendly even if you need a certain number which are)
That definitely is an extract challenge with JMAP, keeping enough tombstone information to accurately calculate the `destroyed` ids.
(and thanks for the Fastmail plug)
Fastmail had to implement this a few years ago ourselves, after 20 years of allowing whatever, we had to start by auto-whitelisting all the addresses people were sending from for a while, then slowly start introducing a requirement to prove control of the sending address to add new sending addresses over time! Obviously hosting your domain with us gets you auto-approved for any address on that domain, but otherwise you either need to confirm that you can receive email at an address to send from it now.
But SPF by itself is pretty flawed. I'm keen to write more about DKIM2 when it gets chartered at IETF (hopefully) and we can post more public documents, but it should supersede SPF/DKIM for most uses.
(and visit Les Mills in Auckland again of course... always nice to get to the place where my OTHER job came from)