Quantenresistente E-Mail: Wie wir verschlüsselte SQLite-Mailboxen verwenden, um Ihre E-Mail sicher zu halten

Quantum-safe encrypted email service illustration

Vorwort

Important

Unser E-Mail-Dienst ist 100% Open-Source und datenschutzorientiert durch sichere und verschlüsselte SQLite-Mailboxen.

Bis wir IMAP-Unterstützung eingeführt haben, verwendeten wir MongoDB für unsere persistenten Datenspeicheranforderungen.

Diese Technologie ist großartig und wir nutzen sie noch heute – aber um Verschlüsselung im Ruhezustand mit MongoDB zu haben, müssen Sie einen Anbieter verwenden, der MongoDB Enterprise anbietet, wie Digital Ocean oder Mongo Atlas – oder eine Enterprise-Lizenz bezahlen (und anschließend mit der Verzögerung des Vertriebsteams arbeiten).

Unser Team bei Forward Email benötigte eine entwicklerfreundliche, skalierbare, zuverlässige und verschlüsselte Speicherlösung für IMAP-Mailboxen. Als Open-Source-Entwickler war es gegen unsere Prinzipien, eine Technologie zu verwenden, für die man eine Lizenzgebühr zahlen muss, um die Verschlüsselung im Ruhezustand zu erhalten – also haben wir experimentiert, recherchiert und eine neue Lösung von Grund auf entwickelt, um diese Bedürfnisse zu erfüllen.

Anstatt eine gemeinsame Datenbank zur Speicherung Ihrer Mailboxen zu verwenden, speichern und verschlüsseln wir Ihre Mailboxen individuell mit Ihrem Passwort (das nur Sie haben). Unser E-Mail-Dienst ist so sicher, dass wenn Sie Ihr Passwort vergessen, Sie Ihre Mailbox verlieren (und mit Offline-Backups wiederherstellen oder neu anfangen müssen).

Lesen Sie weiter, während wir unten einen tiefen Einblick geben mit einem Vergleich der E-Mail-Diensteanbieter, wie unser Dienst funktioniert, unserem Technologie-Stack und mehr.

Vergleich der E-Mail-Diensteanbieter

Wir sind der einzige 100% Open-Source- und datenschutzorientierte E-Mail-Diensteanbieter, der individuell verschlüsselte SQLite-Mailboxen speichert, unbegrenzte Domains, Aliase und Benutzer anbietet und ausgehenden SMTP-, IMAP- und POP3-Support hat:

Im Gegensatz zu anderen E-Mail-Anbietern müssen Sie bei Forward Email nicht pro Domain oder Alias für Speicherplatz bezahlen. Der Speicherplatz wird über Ihr gesamtes Konto geteilt – wenn Sie also mehrere benutzerdefinierte Domainnamen und mehrere Aliase auf jeder haben, sind wir die perfekte Lösung für Sie. Beachten Sie, dass Sie bei Bedarf dennoch Speicherlimits pro Domain oder Alias durchsetzen können.

E-Mail-Dienstvergleich lesen

Wie funktioniert es

  1. Mit Ihrem E-Mail-Client wie Apple Mail, Thunderbird, Gmail oder Outlook verbinden Sie sich mit unseren sicheren IMAP-Servern unter Verwendung Ihres Benutzernamens und Passworts:

    • Ihr Benutzername ist Ihr vollständiger Alias mit Ihrer Domain, z. B. hello@example.com.
    • Ihr Passwort wird zufällig generiert und Ihnen nur 30 Sekunden lang angezeigt, wenn Sie Passwort generieren unter Mein Konto Domains Aliase anklicken.
  2. Sobald die Verbindung hergestellt ist, sendet Ihr E-Mail-Client IMAP-Protokollbefehle an unseren IMAP-Server, um Ihr Postfach synchron zu halten. Dies umfasst das Schreiben und Speichern von Entwürfen sowie andere Aktionen, die Sie durchführen könnten (z. B. eine E-Mail als Wichtig markieren oder eine E-Mail als Spam/Junk-Mail kennzeichnen).

  3. Mail-Austauschserver (allgemein bekannt als "MX"-Server) empfangen neue eingehende E-Mails und speichern sie in Ihrem Postfach. Wenn dies geschieht, wird Ihr E-Mail-Client benachrichtigt und synchronisiert Ihr Postfach. Unsere Mail-Austauschserver können Ihre E-Mails an einen oder mehrere Empfänger weiterleiten (einschließlich Webhooks), Ihre E-Mails für Sie in Ihrem verschlüsselten IMAP-Speicher bei uns speichern, oder beides!

    Tip

    Interessiert, mehr zu erfahren? Lesen Sie wie man E-Mail-Weiterleitung einrichtet, wie unser Mail-Austauschdienst funktioniert oder sehen Sie sich unsere Anleitungen an.

  4. Im Hintergrund funktioniert unser sicheres E-Mail-Speicher-Design auf zwei Arten, um Ihre Postfächer verschlüsselt und nur für Sie zugänglich zu halten:

    • Wenn neue E-Mails von einem Absender für Sie eingehen, schreiben unsere Mail-Austauschserver in ein individuelles, temporäres und verschlüsseltes Postfach für Sie.

    • Wenn Sie sich mit Ihrem E-Mail-Client an unserem IMAP-Server anmelden, wird Ihr Passwort im Speicher verschlüsselt und verwendet, um Ihr Postfach zu lesen und zu schreiben. Ihr Postfach kann nur mit diesem Passwort gelesen und beschrieben werden. Beachten Sie, dass da nur Sie dieses Passwort besitzen, nur Sie Ihr Postfach lesen und schreiben können, wenn Sie darauf zugreifen. Beim nächsten Versuch Ihres E-Mail-Clients, nach neuen Nachrichten zu suchen oder zu synchronisieren, werden Ihre neuen Nachrichten aus diesem temporären Postfach übertragen und mit Ihrem angegebenen Passwort in Ihrer tatsächlichen Postfachdatei gespeichert. Dieses temporäre Postfach wird anschließend gelöscht, sodass nur Ihr passwortgeschütztes Postfach die Nachrichten enthält.

    • Wenn Sie mit IMAP verbunden sind (z. B. mit einem E-Mail-Client wie Apple Mail oder Thunderbird), müssen wir nicht auf temporären Speicher schreiben. Ihr im Speicher verschlüsseltes IMAP-Passwort wird stattdessen abgerufen und verwendet. In Echtzeit, wenn versucht wird, eine Nachricht an Sie zuzustellen, senden wir eine WebSocket-Anfrage an alle IMAP-Server, um zu prüfen, ob eine aktive Sitzung für Sie besteht (das ist der Abrufteil), und übergeben anschließend dieses verschlüsselte Passwort im Speicher – so müssen wir nicht in ein temporäres Postfach schreiben, sondern können direkt in Ihr tatsächliches verschlüsseltes Postfach mit Ihrem verschlüsselten Passwort schreiben.

  5. Backups Ihrer verschlüsselten Postfächer werden täglich erstellt. Sie können jederzeit ein neues Backup anfordern oder das neueste Backup von Mein Konto Domains Aliase herunterladen. Wenn Sie sich entscheiden, zu einem anderen E-Mail-Dienst zu wechseln, können Sie Ihre Postfächer und Backups jederzeit einfach migrieren, herunterladen, exportieren und löschen.

Technologien

Datenbanken

Wir haben andere mögliche Datenbankspeicherschichten untersucht, jedoch erfüllte keine unsere Anforderungen so gut wie SQLite:

Datenbank Verschlüsselung im Ruhezustand Sandboxed Postfächer Lizenz Überall verwendet
SQLite ✅ Ja mit SQLite3MultipleCiphers ✅ Public Domain
MongoDB "Nur in MongoDB Enterprise verfügbar" ❌ Relationale Datenbank ❌ AGPL und SSPL-1.0
rqlite Nur Netzwerk ❌ Relationale Datenbank MIT
dqlite Ungetestet und noch nicht unterstützt? Ungetestet und noch nicht unterstützt? LGPL-3.0-only
PostgreSQL Ja ❌ Relationale Datenbank PostgreSQL (ähnlich BSD oder MIT)
MariaDB Nur für InnoDB ❌ Relationale Datenbank GPLv2 und BUSL-1.1
CockroachDB Nur Enterprise-Funktion ❌ Relationale Datenbank BUSL-1.1 und andere

Hier ist ein Blogbeitrag, der mehrere SQLite-Datenbankspeicheroptionen vergleicht in der obigen Tabelle.

Sicherheit

Wir verwenden jederzeit Verschlüsselung im Ruhezustand (AES-256), Verschlüsselung während der Übertragung (TLS), DNS über HTTPS ("DoH") mit 🍊 Tangerine und sqleet (ChaCha20-Poly1305) Verschlüsselung auf Postfächern. Zusätzlich verwenden wir tokenbasierte Zwei-Faktor-Authentifizierung (im Gegensatz zu SMS, die anfällig für Man-in-the-Middle-Angriffe ist), rotierende SSH-Schlüssel mit deaktiviertem Root-Zugang, exklusiven Zugriff auf Server über eingeschränkte IP-Adressen und mehr. Im Falle eines Evil Maid Angriffs oder eines böswilligen Mitarbeiters eines Drittanbieters kann Ihr Postfach weiterhin nur mit Ihrem generierten Passwort geöffnet werden. Seien Sie versichert, dass wir uns nicht auf Drittanbieter verlassen, außer unseren SOC Type 2 konformen Serveranbietern Cloudflare, DataPacket, Digital Ocean, GitHub und Vultr.

Unser Ziel ist es, so wenige Single Points of Failure wie möglich zu haben.

Postfächer

tldr; Unsere IMAP-Server verwenden individuell verschlüsselte SQLite-Datenbanken für jedes Ihrer Postfächer.

SQLite ist eine äußerst beliebte eingebettete Datenbank – sie läuft derzeit auf Ihrem Telefon und Computer – und wird von nahezu allen großen Technologien verwendet.

Zum Beispiel gibt es auf unseren verschlüsselten Servern eine SQLite-Datenbank-Postfachdatei für linux@example.com, info@example.com, hello@example.com und so weiter – jeweils eine als .sqlite Datenbankdatei. Wir benennen die Datenbankdateien auch nicht mit der E-Mail-Adresse – stattdessen verwenden wir BSON ObjectID und einzigartige UUIDs, die nicht verraten, wem das Postfach gehört oder unter welcher E-Mail-Adresse es geführt wird (z. B. 353a03f21e534321f5d6e267.sqlite).

Jede dieser Datenbanken ist selbst mit Ihrem Passwort (das nur Sie kennen) verschlüsselt, und zwar mit sqleet (ChaCha20-Poly1305). Das bedeutet, dass Ihre Postfächer einzeln verschlüsselt, eigenständig, sandboxed und portabel sind.

Wir haben SQLite mit den folgenden PRAGMA feinjustiert:

PRAGMA Zweck
cipher=chacha20 ChaCha20-Poly1305 SQLite Datenbankverschlüsselung. Siehe better-sqlite3-multiple-ciphers unter Projects für weitere Einblicke.
key="****************" Dies ist Ihr nur im Speicher entschlüsseltes Passwort, das über die IMAP-Verbindung Ihres E-Mail-Clients an unseren Server übergeben wird. Neue Datenbankinstanzen werden für jede Lese- und Schreibsitzung erstellt und geschlossen (um Sandbox und Isolation zu gewährleisten).
journal_mode=WAL Write-ahead-log ("WAL") das die Leistung steigert und gleichzeitigen Lesezugriff ermöglicht.
busy_timeout=5000 Verhindert Schreibsperrfehler während andere Schreibvorgänge stattfinden.
synchronous=NORMAL Erhöht die Dauerhaftigkeit von Transaktionen ohne Risiko von Datenbeschädigung.
foreign_keys=ON Erzwingt, dass Fremdschlüsselreferenzen (z. B. eine Beziehung von einer Tabelle zu einer anderen) durchgesetzt werden. Standardmäßig ist dies in SQLite nicht aktiviert, sollte aber für Validierung und Datenintegrität aktiviert sein.
encoding='UTF-8' Standardkodierung zur Sicherstellung der Entwicklerfreundlichkeit.

Alle anderen Standardwerte stammen von SQLite, wie in der offiziellen PRAGMA-Dokumentation angegeben.

Gleichzeitigkeit

kurz gesagt; Wir verwenden WebSocket für gleichzeitige Lese- und Schreibzugriffe auf Ihre verschlüsselten SQLite-Postfächer.

Lesezugriffe

Ihr E-Mail-Client auf Ihrem Telefon kann imap.forwardemail.net auf eine unserer Digital Ocean IP-Adressen auflösen – und Ihr Desktop-Client kann eine andere IP von einem anderen Anbieter auflösen.

Unabhängig davon, mit welchem IMAP-Server Ihr E-Mail-Client verbunden ist, möchten wir, dass die Verbindung Ihre Datenbank in Echtzeit mit 100 % Genauigkeit liest. Dies geschieht über WebSockets.

Schreibzugriffe

Das Schreiben in Ihre Datenbank ist etwas anders – da SQLite eine eingebettete Datenbank ist und Ihr Postfach standardmäßig in einer einzigen Datei gespeichert ist.

Wir hatten Optionen wie litestream, rqlite und dqlite unten geprüft – jedoch erfüllte keine davon unsere Anforderungen.

Um Schreibvorgänge mit aktiviertem Write-Ahead-Logging ("WAL") durchzuführen – müssen wir sicherstellen, dass nur ein Server ("Primary") dafür verantwortlich ist. WAL beschleunigt die Gleichzeitigkeit erheblich und erlaubt einen Schreiber und mehrere Leser.

Der Primary läuft auf den Datenservern mit den eingebundenen Volumes, die die verschlüsselten Postfächer enthalten. Aus Sicht der Verteilung können Sie alle einzelnen IMAP-Server hinter imap.forwardemail.net als sekundäre Server ("Secondary") betrachten.

Wir realisieren die bidirektionale Kommunikation mit WebSockets:

  • Primary-Server verwenden eine Instanz des ws WebSocketServer.
  • Secondary-Server verwenden eine Instanz des ws WebSocket Clients, der mit websocket-as-promised und reconnecting-websocket umhüllt ist. Diese beiden Wrapper sorgen dafür, dass sich der WebSocket automatisch wieder verbindet und Daten für spezifische Datenbankschreibvorgänge senden und empfangen kann.

Backups

kurz gesagt; Backups Ihrer verschlüsselten Postfächer werden täglich erstellt. Sie können jederzeit auch sofort ein neues Backup anfordern oder das neueste Backup herunterladen unter Mein Konto Domains Aliase.

Für Backups führen wir einfach jeden Tag während der IMAP-Befehlsverarbeitung den SQLite-Befehl VACUUM INTO aus, der Ihr verschlüsseltes Passwort aus einer IMAP-Verbindung im Arbeitsspeicher nutzt. Backups werden gespeichert, wenn kein vorhandenes Backup erkannt wird oder wenn sich der SHA-256 Hash der Datei im Vergleich zum letzten Backup geändert hat.

Beachten Sie, dass wir den Befehl VACUUM INTO anstelle des eingebauten backup Befehls verwenden, weil bei einer Änderung einer Seite während eines backup-Befehls der Vorgang neu gestartet werden muss. Der VACUUM INTO Befehl erstellt einen Schnappschuss. Siehe diese Kommentare auf GitHub und Hacker News für weitere Einblicke.

Außerdem verwenden wir VACUUM INTO anstelle von backup, weil der backup Befehl die Datenbank für eine kurze Zeit unverschlüsselt lassen würde, bis rekey aufgerufen wird (siehe diesen GitHub Kommentar für Einblicke).

Der Secondary weist den Primary über die WebSocket-Verbindung an, das Backup auszuführen – und der Primary erhält dann den Befehl und wird anschließend:

  1. Eine Verbindung zu Ihrem verschlüsselten Postfach herstellen.
  2. Ein Schreib-Lock erwerben.
  3. Einen WAL-Checkpoint via wal_checkpoint(PASSIVE) ausführen.
  4. Den SQLite-Befehl VACUUM INTO ausführen.
  5. Sicherstellen, dass die kopierte Datei mit dem verschlüsselten Passwort geöffnet werden kann (Absicherung/Fehlersicherheit).
  6. Die Datei zur Speicherung bei Cloudflare R2 hochladen (oder bei Ihrem eigenen Anbieter, falls angegeben).

Denke daran, dass deine Postfächer verschlüsselt sind – und obwohl wir IP-Beschränkungen und andere Authentifizierungsmaßnahmen für die WebSocket-Kommunikation implementiert haben – kannst du im Falle eines Angreifers sicher sein, dass die Datenbank nicht geöffnet werden kann, sofern die WebSocket-Nutzlast nicht dein IMAP-Passwort enthält.

Derzeit wird pro Postfach nur ein Backup gespeichert, aber in Zukunft könnten wir Point-in-Time-Recovery ("PITR") anbieten.

Unsere IMAP-Server unterstützen den SEARCH-Befehl mit komplexen Abfragen, regulären Ausdrücken und mehr.

Die schnelle Suchleistung verdanken wir FTS5 und sqlite-regex.

Wir speichern Date-Werte in den SQLite-Postfächern als ISO 8601-Strings über Date.prototype.toISOString (mit UTC-Zeitzone, damit Gleichheitsvergleiche korrekt funktionieren).

Indizes werden auch für alle Eigenschaften gespeichert, die in Suchanfragen verwendet werden.

Projekte

Hier ist eine Tabelle mit Projekten, die wir in unserem Quellcode und Entwicklungsprozess verwenden (alphabetisch sortiert):

Projekt Zweck
Ansible DevOps-Automatisierungsplattform zur einfachen Wartung, Skalierung und Verwaltung unserer gesamten Serverflotte.
Bree Job-Scheduler für Node.js und JavaScript mit Unterstützung für cron, Daten, ms, later und benutzerfreundliche Bedienung.
Cabin Entwicklerfreundliche JavaScript- und Node.js-Logging-Bibliothek mit Fokus auf Sicherheit und Datenschutz.
Lad Node.js-Framework, das unsere gesamte Architektur und das Engineering-Design mit MVC und mehr antreibt.
MongoDB NoSQL-Datenbanklösung, die wir zur Speicherung aller anderen Daten außerhalb der Postfächer verwenden (z. B. dein Konto, Einstellungen, Domains und Alias-Konfigurationen).
Mongoose MongoDB Object Document Modeling ("ODM"), das wir im gesamten Stack verwenden. Wir haben spezielle Helfer geschrieben, die es uns ermöglichen, Mongoose weiterhin mit SQLite zu verwenden 🎉
Node.js Node.js ist die Open-Source, plattformübergreifende JavaScript-Laufzeitumgebung, die alle unsere Serverprozesse ausführt.
Nodemailer Node.js-Paket zum Senden von E-Mails, Erstellen von Verbindungen und mehr. Wir sind offizieller Sponsor dieses Projekts.
Redis In-Memory-Datenbank für Caching, Publish/Subscribe-Kanäle und DNS-over-HTTPS-Anfragen.
SQLite3MultipleCiphers Verschlüsselungserweiterung für SQLite, die es erlaubt, komplette Datenbankdateien zu verschlüsseln (einschließlich Write-Ahead-Log ("WAL"), Journal, Rollback, …).
SQLiteStudio Visueller SQLite-Editor (den du auch verwenden könntest), um Entwicklungs-Postfächer zu testen, herunterzuladen und anzusehen.
SQLite Eingebettete Datenbankschicht für skalierbaren, eigenständigen, schnellen und robusten IMAP-Speicher.
Spam Scanner Node.js Anti-Spam-, E-Mail-Filter- und Phishing-Präventionstool (unsere Alternative zu Spam Assassin und rspamd).
Tangerine DNS-over-HTTPS-Anfragen mit Node.js und Caching mittels Redis – was globale Konsistenz und vieles mehr sicherstellt.
Thunderbird Unser Entwicklungsteam verwendet dies (und empfiehlt es auch) als bevorzugten E-Mail-Client für Forward Email.
UTM Unser Entwicklungsteam nutzt dies, um virtuelle Maschinen für iOS und macOS zu erstellen, um verschiedene E-Mail-Clients (parallel) mit unseren IMAP- und SMTP-Servern zu testen.
Ubuntu Modernes Open-Source-Linux-basiertes Server-Betriebssystem, das unsere gesamte Infrastruktur antreibt.
WildDuck IMAP-Server-Bibliothek – siehe die Hinweise zu Attachment-De-Duplizierung und IMAP-Protokollunterstützung.
better-sqlite3-multiple-ciphers Schnelle und einfache API-Bibliothek für Node.js zur programmgesteuerten Interaktion mit SQLite3.
email-templates Entwicklerfreundliches E-Mail-Framework zum Erstellen, Vorschauen und Versenden von benutzerdefinierten E-Mails (z. B. Konto-Benachrichtigungen und mehr).
json-sql-enhanced SQL-Abfrage-Builder mit Mongo-ähnlicher Syntax. Dies spart unserem Entwicklungsteam Zeit, da wir weiterhin im Mongo-Stil über den gesamten Stack mit einem datenbankagnostischen Ansatz schreiben können. Es hilft auch, SQL-Injection-Angriffe durch Verwendung von Abfrageparametern zu vermeiden.
knex-schema-inspector SQL-Utility zum Extrahieren von Informationen über bestehende Datenbankschemata. Dies ermöglicht es uns, einfach zu validieren, dass alle Indizes, Tabellen, Spalten, Einschränkungen und mehr gültig sind und 1:1 mit dem Soll-Zustand übereinstimmen. Wir haben sogar automatisierte Helfer geschrieben, um neue Spalten und Indizes hinzuzufügen, falls Änderungen an Datenbankschemata vorgenommen werden (mit sehr detaillierten Fehlermeldungen).
knex SQL-Abfrage-Builder, den wir nur für Datenbankmigrationen und Schema-Validierung über knex-schema-inspector verwenden.
mandarin Automatische i18n-Phrasenübersetzung mit Unterstützung für Markdown unter Verwendung der Google Cloud Translation API.
mx-connect Node.js-Paket zum Auflösen und Herstellen von Verbindungen mit MX-Servern und zur Fehlerbehandlung.
pm2 Node.js Produktionsprozessmanager mit eingebautem Load Balancer (feinabgestimmt für Performance).
smtp-server SMTP-Server-Bibliothek – wir verwenden diese für unsere Mail-Exchange-("MX")- und ausgehenden SMTP-Server.
ImapTest Nützliches Tool zum Testen von IMAP-Servern anhand von Benchmarks und RFC-Spezifikationen zur IMAP-Protokollkompatibilität. Dieses Projekt wurde vom Dovecot-Team erstellt (ein aktiver Open-Source-IMAP- und POP3-Server seit Juli 2002). Wir haben unseren IMAP-Server mit diesem Tool umfangreich getestet.

Sie können weitere Projekte, die wir verwenden, in unrem Quellcode auf GitHub finden.

Anbieter

Anbieter Zweck
Cloudflare DNS-Anbieter, Gesundheitschecks, Load Balancer und Backup-Speicher mit Cloudflare R2.
GitHub Hosting von Quellcode, CI/CD und Projektmanagement.
Digital Ocean Hosting von dedizierten Servern und verwalteten Datenbanken.
Vultr Hosting von dedizierten Servern.
DataPacket Hosting von dedizierten Servern.

Gedanken

Prinzipien

Forward Email ist nach folgenden Prinzipien gestaltet:

  1. Immer entwicklerfreundlich, sicherheits- und datenschutzorientiert sowie transparent sein.
  2. Einhaltung von MVC, Unix, KISS, DRY, YAGNI, Twelve Factor, Ockhams Rasiermesser und dogfooding
  3. Zielgruppe sind scrappy, bootstrapped und ramen-profitable Entwickler

Experimente

tldr; Letztendlich sind die Verwendung von S3-kompatiblem Objektspeicher und/oder virtuellen Tabellen aus Leistungsgründen technisch nicht machbar und aufgrund von Speicherbeschränkungen fehleranfällig.

Wir haben einige Experimente durchgeführt, die zu unserer finalen SQLite-Lösung geführt haben, wie oben beschrieben.

Eines davon war der Versuch, rclone und SQLite zusammen mit einer S3-kompatiblen Speicherschicht zu verwenden.

Dieses Experiment führte dazu, dass wir Randfälle im Zusammenhang mit rclone, SQLite und der Nutzung von VFS besser verstanden und entdeckten:

  • Wenn Sie mit rclone die Option --vfs-cache-mode writes aktivieren, sind Lesevorgänge in Ordnung, aber Schreibvorgänge werden zwischengespeichert.
    • Wenn Sie mehrere IMAP-Server global verteilt haben, ist der Cache zwischen ihnen nicht synchronisiert, es sei denn, Sie haben einen einzigen Schreiber und mehrere Zuhörer (z. B. einen Pub/Sub-Ansatz).
    • Das ist unglaublich komplex, und jede zusätzliche Komplexität führt zu mehr Single Points of Failure.
    • S3-kompatible Speicheranbieter unterstützen keine partiellen Dateiänderungen – das bedeutet, jede Änderung der .sqlite-Datei führt zu einer vollständigen Änderung und einem erneuten Hochladen der Datenbank.
    • Andere Lösungen wie rsync existieren, sind aber nicht auf Write-Ahead-Log ("WAL")-Unterstützung ausgelegt – daher haben wir Litestream überprüft. Glücklicherweise verschlüsselt unsere Verschlüsselung bereits die WAL-Dateien, sodass wir nicht auf Litestream angewiesen sind. Allerdings waren wir noch nicht sicher, ob Litestream für den Produktionseinsatz geeignet ist, und haben dazu einige Anmerkungen unten.
    • Die Verwendung der Option --vfs-cache-mode writes (die einzige Möglichkeit, SQLite über rclone für Schreibvorgänge zu verwenden) versucht, die gesamte Datenbank im Speicher von Grund auf zu kopieren – die Handhabung eines 10-GB-Postfachs ist in Ordnung, aber bei mehreren Postfächern mit sehr großem Speicherbedarf stoßen die IMAP-Server auf Speicherbeschränkungen, ENOMEM-Fehler, Segmentierungsfehler und Datenkorruption.
  • Wenn Sie versuchen, SQLite Virtuelle Tabellen (z. B. mit s3db) zu verwenden, um Daten auf einer S3-kompatiblen Speicherschicht zu halten, stoßen Sie auf mehrere weitere Probleme:
    • Lese- und Schreibvorgänge sind extrem langsam, da S3-API-Endpunkte mit HTTP-Methoden GET, PUT, HEAD und POST angesprochen werden müssen.
    • Entwicklungstests zeigten, dass bei mehr als 500K-1M+ Datensätzen bei Glasfaser-Internet die Durchsatzrate beim Schreiben und Lesen zu S3-kompatiblen Anbietern begrenzt ist. Unsere Entwickler führten z. B. for-Schleifen aus, um sowohl sequentielle SQL-INSERT-Anweisungen als auch solche mit Bulk-Schreibvorgängen großer Datenmengen durchzuführen. In beiden Fällen war die Leistung erschreckend langsam.
    • Virtuelle Tabellen können keine Indizes, ALTER TABLE-Anweisungen und andere Einschränkungen haben – was zu Verzögerungen von 1-2 Minuten oder mehr je nach Datenmenge führt.
    • Objekte wurden unverschlüsselt gespeichert, und eine native Verschlüsselungsunterstützung ist nicht verfügbar.
  • Wir haben auch sqlite-s3vfs untersucht, das konzeptionell und technisch ähnlich zum vorherigen Punkt ist (also die gleichen Probleme hat). Eine Möglichkeit wäre, eine benutzerdefinierte sqlite3-Version mit Verschlüsselung wie wxSQLite3 (die wir derzeit in unserer Lösung oben verwenden) zu verwenden, indem man die Setup-Datei bearbeitet.
  • Ein weiterer möglicher Ansatz war die Verwendung der multiplex-Erweiterung, die jedoch eine Begrenzung von 32 GB hat und komplexe Build- und Entwicklungsprobleme verursachen würde.
  • ALTER TABLE-Anweisungen sind erforderlich (was die Verwendung von virtuellen Tabellen komplett ausschließt). Wir benötigen ALTER TABLE-Anweisungen, damit unser Hook mit knex-schema-inspector korrekt funktioniert – das stellt sicher, dass Daten nicht beschädigt werden und abgerufene Zeilen in gültige Dokumente gemäß unseren mongoose-Schema-Definitionen umgewandelt werden können (einschließlich Einschränkungen, Variablentypen und beliebiger Datenvalidierung).
  • Fast alle S3-kompatiblen Projekte im Zusammenhang mit SQLite in der Open-Source-Community sind in Python (und nicht in JavaScript, das wir für 100 % unseres Stacks verwenden).
  • Kompressionsbibliotheken wie sqlite-zstd (siehe Kommentare) sehen vielversprechend aus, sind aber möglicherweise noch nicht für den Produktionseinsatz bereit. Stattdessen ist eine Kompression auf Anwendungsebene für Datentypen wie String, Object, Map, Array, Set und Buffer ein saubererer und einfacherer Ansatz (und leichter zu migrieren, da wir ein Boolean-Flag oder eine Spalte speichern könnten – oder sogar PRAGMA user_version=1 für Kompression oder user_version=0 für keine Kompression als Datenbank-Metadaten verwenden könnten).
    • Glücklicherweise haben wir bereits eine Anhangs-Deduplizierung in unserem IMAP-Server-Speicher implementiert – daher wird jeder Nachricht mit demselben Anhang nicht eine Kopie des Anhangs gespeichert, sondern ein einzelner Anhang für mehrere Nachrichten und Threads in einem Postfach gespeichert (und anschließend eine Fremdreferenz verwendet).
  • Das Projekt Litestream, eine SQLite-Replikations- und Backup-Lösung, ist sehr vielversprechend und wir werden es höchstwahrscheinlich in Zukunft verwenden.
  • Die Wiederherstellung von Backups muss reibungslos und trivial sein. Die Verwendung einer Lösung wie MongoDB mit mongodump und mongoexport ist nicht nur mühsam, sondern zeitaufwendig und komplex in der Konfiguration.
    • SQLite-Datenbanken machen es einfach (es ist eine einzelne Datei).
    • Wir wollten eine Lösung entwerfen, bei der Benutzer ihr Postfach jederzeit mitnehmen und verlassen können.
      • Einfache Node.js-Befehle wie fs.unlink('mailbox.sqlite') löschen es dauerhaft vom Festplattenspeicher.
      • Wir können ähnlich eine S3-kompatible API mit HTTP-DELETE verwenden, um Snapshots und Backups für Benutzer einfach zu entfernen.
    • SQLite war die einfachste, schnellste und kostengünstigste Lösung.

Mangel an Alternativen

Nach unserem Wissen sind keine anderen E-Mail-Dienste auf diese Weise konzipiert, noch sind sie Open-Source.

Wir denken, dass dies möglicherweise daran liegt, dass bestehende E-Mail-Dienste Legacy-Technologie mit Spaghetti-Code 🍝 in Produktion haben.

Die meisten, wenn nicht alle bestehenden E-Mail-Dienstanbieter sind entweder Closed-Source oder werben als Open-Source, aber in Wirklichkeit ist nur ihr Front-End Open-Source.

Der sensibelste Teil der E-Mail (die eigentliche Speicherung/IMAP/SMTP-Interaktion) findet vollständig im Back-End (Server) statt und nicht im Front-End (Client).

Probieren Sie Forward Email aus

Melden Sie sich noch heute an unter https://forwardemail.net! 🚀