Głębokie informacje: Jak używamy szyfrowanych skrzynek pocztowych SQLite z zabezpieczeniem kwantowym w naszej bezpiecznej usłudze e-mail zorientowanej na prywatność

W przeciwieństwie do innych usług e-mailowych zapewniamy, że tylko Ty masz stały dostęp do swojej skrzynki pocztowej .

Przedmowa

tldr; Nasza usługa e-mail jest W 100% otwarte i zorientowane na prywatność dzięki bezpiecznym i szyfrowanym skrzynce pocztowej SQLite.

Dopóki nie wystartowaliśmy Obsługa protokołu IMAP, użyliśmy MongoDB do naszych stałych potrzeb w zakresie przechowywania danych.

Ta technologia jest niesamowita i nadal jej używamy – ale aby mieć szyfrowanie w MongoDB, musisz skorzystać z dostawcy oferującego MongoDB Enterprise, takiego jak Digital Ocean lub Mongo Atlas – lub zapłacić za licencję dla przedsiębiorstw (i później muszą pracować nad opóźnieniami zespołu sprzedaży).

Nasz zespół o godz Prześlij dalej e-mail potrzebował przyjaznego dla programistów, skalowalnego, niezawodnego i szyfrowanego rozwiązania do przechowywania skrzynek pocztowych IMAP. Jako twórcy oprogramowania open source korzystanie z technologii wymagającej uiszczenia opłaty licencyjnej, aby móc korzystać z funkcji szyfrowania w stanie spoczynku, było sprzeczne z nasze zasady – dlatego eksperymentowaliśmy, badaliśmy i opracowaliśmy od podstaw nowe rozwiązanie, aby sprostać tym potrzebom.

Zamiast korzystać ze wspólnej bazy danych do przechowywania Twoich skrzynek pocztowych, przechowujemy je indywidualnie i szyfrujemy Twoim hasłem (które masz tylko Ty). Nasza usługa e-mail jest tak bezpieczna, że jeśli zapomnisz hasła, utracisz skrzynkę pocztową (i musisz odzyskać dane za pomocą kopii zapasowych offline lub zacząć od nowa).

Czytaj dalej, gdy zagłębimy się poniżej w porównanie dostawców usług e-mail, jak działa nasz serwis, nasz stos technologii, i więcej.

Porównanie dostawców usług e-mail

Jesteśmy jedynym dostawcą usług e-mail w pełni open source i zorientowanym na prywatność, który przechowuje indywidualnie zaszyfrowane skrzynki pocztowe SQLite, oferuje nieograniczoną liczbę domen, aliasów i użytkowników oraz obsługuje wychodzące SMTP, IMAP i POP3:

W przeciwieństwie do innych dostawców poczty e-mail, w przypadku usługi Forward Email nie musisz płacić za przechowywanie w oparciu o domenę lub alias. Miejsce na dane jest współdzielone na całym koncie – więc jeśli masz wiele niestandardowych nazw domen i wiele aliasów na każdej z nich, jesteśmy dla Ciebie idealnym rozwiązaniem. Pamiętaj, że w razie potrzeby możesz nadal egzekwować limity miejsca na domenę lub alias.

Przeczytaj Porównanie usług e-mail

Jak to działa

  1. Korzystając z klienta poczty e-mail, takiego jak Apple Mail, Thunderbird, Gmail lub Outlook – łączysz się z naszym bezpiecznym IMAP serwery korzystające z Twojej nazwy użytkownika i hasła:

    • Twoja nazwa użytkownika to pełny alias z Twoją domeną, np hello@example.com.
    • Twoje hasło jest generowane losowo i wyświetlane tylko przez 30 sekund po kliknięciu Wygeneruj hasło z Moje konto Domeny Skróty.
  2. Po nawiązaniu połączenia Twój klient poczty e-mail wyśle wiadomość Polecenia protokołu IMAP do naszego serwera IMAP, aby synchronizować skrzynkę pocztową. Obejmuje to pisanie i przechowywanie wersji roboczych wiadomości e-mail oraz inne czynności, które możesz wykonać (np. oznaczenie wiadomości e-mail jako ważnej lub oznaczenie wiadomości e-mail jako spam/śmieci).

  3. Serwery wymiany poczty (powszechnie zwane serwerami „MX”) odbierają nowe przychodzące wiadomości e-mail i przechowują je w Twojej skrzynce pocztowej. Gdy tak się stanie, Twój klient poczty e-mail otrzyma powiadomienie i zsynchronizuje Twoją skrzynkę pocztową. Nasze serwery wymiany poczty mogą przekazywać Twoją pocztę e-mail do jednego lub większej liczby odbiorców (w tym webhooki), przechowuj u nas swoje wiadomości e-mail w zaszyfrowanym magazynie IMAP, lub oba!

    Chcesz dowiedzieć się więcej? Czytać jak skonfigurować przekazywanie wiadomości e-mail, jak działa nasza usługa wymiany pocztylub obejrzyj nasi przewodnicy.

  4. Za kulisami nasz projekt bezpiecznego przechowywania wiadomości e-mail działa na dwa sposoby, aby Twoje skrzynki pocztowe były szyfrowane i dostępne tylko dla Ciebie:

    • Po otrzymaniu nowej poczty od nadawcy nasze serwery wymiany poczty zapisują ją w indywidualnej, tymczasowej i zaszyfrowanej skrzynce pocztowej.

      sequenceDiagram
          autonumber
          actor Sender
          Sender->>MX: Inbound message received for your alias (e.g. you@yourdomain.com).
          MX->>SQLite: Message is stored in a temporary mailbox.
          Note over MX,SQLite: Forwards to other recipients and webhooks configured.
          MX->>Sender: Success!
      
    • Kiedy łączysz się z naszym serwerem IMAP za pomocą swojego klienta poczty e-mail, Twoje hasło jest następnie szyfrowane w pamięci i używane do odczytu i zapisu w Twojej skrzynce pocztowej. Z Twojej skrzynki pocztowej można czytać i zapisywać tylko przy użyciu tego hasła. Pamiętaj, że ponieważ jesteś jedyną osobą znającą to hasło, tylko ty może czytać i pisać w Twojej skrzynce pocztowej, gdy uzyskujesz do niej dostęp. Następnym razem, gdy Twój klient poczty e-mail będzie próbował odpytać pocztę lub przeprowadzić synchronizację, nowe wiadomości zostaną przeniesione z tymczasowej skrzynki pocztowej i zapisane w rzeczywistym pliku skrzynki pocztowej przy użyciu podanego hasła. Pamiętaj, że ta tymczasowa skrzynka pocztowa jest później czyszczona i usuwana, dzięki czemu wiadomości znajdują się tylko w Twojej skrzynce pocztowej chronionej hasłem.

    • Jeśli jesteś podłączony do protokołu IMAP (np. korzystasz z klienta poczty e-mail, takiego jak Apple Mail lub Thunderbird), nie musimy zapisywać danych na dysku tymczasowym. Zamiast tego zostanie pobrane i użyte Twoje hasło IMAP zaszyfrowane w pamięci. W czasie rzeczywistym, gdy próbujemy dostarczyć Ci wiadomość, wysyłamy żądanie WebSocket do wszystkich serwerów IMAP z pytaniem, czy mają dla Ciebie aktywną sesję (jest to część pobierania), a następnie przekazujemy to dalej zaszyfrowane hasło w pamięci – dzięki temu nie musimy pisać do tymczasowej skrzynki pocztowej, możemy pisać do Twojej rzeczywistej zaszyfrowanej skrzynki pocztowej, używając zaszyfrowanego hasła.

      sequenceDiagram
          autonumber
          actor You
          You->>IMAP: You connect to IMAP server using an email client.
          IMAP->>SQLite: Transfer message from temporary mailbox to your alias' mailbox.
          Note over IMAP,SQLite: Your alias' mailbox is only available in-memory using IMAP password.
          SQLite->>IMAP: Retrieves messages as requested by email client.
          IMAP->>You: Success!
      
  5. Kopie zapasowe zaszyfrowanych skrzynek pocztowych są robione codziennie. Możesz także w dowolnym momencie poprosić o utworzenie nowej kopii zapasowej lub pobrać najnowszą kopię zapasową z witryny Moje konto Domeny Skróty. Jeśli zdecydujesz się przejść na inną usługę e-mail, możesz w dowolnym momencie łatwo migrować, pobierać, eksportować i czyścić swoje skrzynki pocztowe i kopie zapasowe.

Technologie

Bazy danych

Zbadaliśmy inne możliwe warstwy przechowywania baz danych, jednak żadna nie spełniła naszych wymagań w takim stopniu jak SQLite:

Baza danychSzyfrowanie w stanie spoczynkuW piaskownicy Skrzynki pocztoweLicencjaUżywany wszędzie
SQLite✅Tak z SQLite3MultipleCiphers✅ Domena publiczna
MongoDB„Dostępne tylko w MongoDB Enterprise”❌ Relacyjna baza danych❌ AGPL i SSPL-1.0
rqliteTylko sieć❌ Relacyjna baza danychMIT
dqliteNieprzetestowany i jeszcze nieobsługiwany?Nieprzetestowany i jeszcze nieobsługiwany?LGPL-3.0-only
PostgreSQLtak❌ Relacyjna baza danychPostgreSQL (podobny do BSD lub MIT)
MariaDBTylko dla InnoDB❌ Relacyjna baza danychGPLv2 oraz BUSL-1.1
KaraluchDBFunkcja dostępna tylko dla przedsiębiorstw❌ Relacyjna baza danychBUSL-1.1 i inni

Tutaj jest wpis na blogu porównujący kilka opcji przechowywania baz danych SQLite w tabeli powyżej.

Bezpieczeństwo

Cały czas używamy szyfrowanie w stanie spoczynku (AES-256), szyfrowanie w transporcie (TLS), DNS przez HTTPS („DoH”) za pomocą 🍊 Mandarynka, oraz kwadrat (ChaCha20-Poly1305) szyfrowanie skrzynek pocztowych. Dodatkowo stosujemy uwierzytelnianie dwuskładnikowe oparte na tokenach (w przeciwieństwie do SMS-ów, które mogą być podejrzane). ataki typu man-in-the-middle), obrócone klucze SSH z wyłączonym dostępem roota, wyłącznym dostępem do serwerów poprzez zastrzeżone adresy IP i nie tylko.

W przypadku atak złej pokojówki lub nieuczciwego pracownika od zewnętrznego dostawcy, nadal możesz otworzyć swoją skrzynkę pocztową tylko za pomocą wygenerowanego hasła. Możesz mieć pewność, że nie polegamy na żadnych zewnętrznych dostawcach innych niż nasi dostawcy serwerów skarg SOC typu 2, takich jak Cloudflare, Digital Ocean i Vultr.

Naszym celem jest mieć ich jak najmniej pojedynczy punkt awarii jak to możliwe.

Skrzynki pocztowe

tldr; Nasze serwery IMAP korzystają z indywidualnie zaszyfrowanych baz danych SQLite dla każdej Twojej skrzynki pocztowej.

SQLite jest niezwykle popularny wbudowana baza danych – aktualnie działa na Twoim telefonie i komputerze – i wykorzystywane przez prawie wszystkie główne technologie.

Na przykład na naszych zaszyfrowanych serwerach znajduje się skrzynka pocztowa bazy danych SQLite linux@example.com, info@example.com, hello@example.com i tak dalej – po jednym dla każdego jako a .sqlite plik bazy danych. Nie nazywamy również plików bazy danych adresem e-mail – zamiast tego używamy BSON ObjectID i wygenerowanych unikalnych identyfikatorów UUID, które nie informują, do kogo należy skrzynka pocztowa ani pod jakim adresem e-mail się znajduje (np. 353a03f21e534321f5d6e267.sqlite).

Każda z tych baz danych jest szyfrowana przy użyciu Twojego hasła (które tylko Ty posiadasz). kwadrat (ChaCha20-Poly1305). Oznacza to, że Twoje skrzynki pocztowe są indywidualnie szyfrowane, samodzielne, piaskownicai przenośny.

Dopracowaliśmy SQLite w następujący sposób PRAGMA:

PRAGMAZamiar
cipher=chacha20Szyfrowanie bazy danych SQLite ChaCha20-Poly1305. Odniesienie better-sqlite3-multiple-ciphers pod Projektowanie aby uzyskać więcej informacji.
key="****************"To jest Twoje odszyfrowane hasło przechowywane wyłącznie w pamięci, które jest przesyłane przez połączenie IMAP Twojego klienta poczty e-mail z naszym serwerem. Dla każdej sesji odczytu i zapisu tworzone są i zamykane nowe instancje bazy danych (w celu zapewnienia piaskownicy i izolacji).
journal_model=WALDziennik zapisu z wyprzedzeniem („WAL") co zwiększa wydajność i umożliwia równoczesny dostęp do odczytu.
busy_timeout=5000Zapobiega błędom blokady zapisu podczas gdy inne zapisy mają miejsce.
synchronous=NORMALZwiększa trwałość transakcji bez ryzyka uszkodzenia danych.
foreign_keys=ONWymusza wymuszanie odwołań do klucza obcego (np. relacji z jednej tabeli do drugiej). Domyślnie nie jest to włączone w SQLite, ale w celu sprawdzenia poprawności i integralności danych należy ją włączyć.
encoding='UTF-8'Domyślne kodowanie używać, aby zapewnić programistom zdrowy rozsądek.

Wszystkie pozostałe wartości domyślne pochodzą z SQLite, jak określono w pliku oficjalna dokumentacja PRAGMY.

Konkurencja

tldr; Używamy rclone oraz WebSocket do równoczesnych odczytów i zapisów w zaszyfrowanych skrzynkach pocztowych SQLite.

Czyta

Klient poczty e-mail w telefonie może zostać rozwiązany imap.forwardemail.net na jeden z naszych adresów IP Digital Ocean – a Twój klient stacjonarny może rozpoznać oddzielny adres IP od innego dostawca całkowicie.

Niezależnie od tego, z jakim serwerem IMAP łączy się Twój klient poczty e-mail, chcemy, aby połączenie odczytywało Twoją bazę danych w czasie rzeczywistym ze 100% dokładnością:

  • Osiąga się to za pomocą rclone z --vfs-cache-mode off (domyślny).

  • Zamiast korzystać z lokalnej pamięci podręcznej dysku, pamięć podręczna jest odczytywana bezpośrednio ze zdalnego podłączenia (twoja baza danych) w czasie rzeczywistym.

  • W przypadku, gdy nie można znaleźć pliku lokalnego, oznacza to, że rclone nie udało się zamontować lub wystąpił problem. W tym przypadku używamy a WebSocket rezerwa dla odczytów (co nieznacznie zmniejsza wydajność, ale nadal utrzymuje integralność usługi).

  • Każdy z naszych serwerów jest skonfigurowany tak, aby montował się spójnie i powiadamia nas w czasie rzeczywistym o wszelkich błędach.

Pisze

Zapisywanie w bazie danych przebiega nieco inaczej – ponieważ SQLite jest wbudowaną bazą danych, a Twoja skrzynka pocztowa domyślnie znajduje się w jednym pliku.

Rozważaliśmy opcje takie jak litestream, rqlite, oraz dqlite poniżej – jednak żaden z nich nie spełniał naszych wymagań.

Aby wykonać zapisy z rejestrowaniem zapisu z wyprzedzeniem ("WAL„) włączone – musimy upewnić się, że tylko jeden serwer („Podstawowy”) jest za to odpowiedzialny. WAL drastycznie przyspiesza współbieżność i umożliwia jednemu pisarzowi i wielu czytelnikom.

Jednostka podstawowa działa na serwerach danych z zamontowanymi woluminami zawierającymi zaszyfrowane skrzynki pocztowe. Z punktu widzenia dystrybucji można wziąć pod uwagę wszystkie pojedyncze serwery IMAP imap.forwardemail.net być serwerami dodatkowymi („Dodatkowe”).

Realizujemy dwustronną komunikację z WebSockety:

  • Serwery główne korzystają z instancji ws'S WebSocketServer serwer.
  • Serwery dodatkowe korzystają z instancji ws'S WebSocket klient, który jest opakowany websocket-zgodnie z obietnicą oraz ponowne łączenie-websocket. Te dwie owijki zapewniają, że WebSocket ponownie łączy się i może wysyłać i odbierać dane w ramach określonych zapisów w bazie danych.

Kopie zapasowe

tldr; Kopie zapasowe zaszyfrowanych skrzynek pocztowych są tworzone codziennie. Możesz także natychmiast poprosić o nową kopię zapasową lub pobrać najnowszą kopię zapasową w dowolnym momencie ze strony Moje konto Domeny Skróty.

W przypadku kopii zapasowych po prostu uruchamiamy SQLite VACUUM INTO polecenie codziennie podczas przetwarzania poleceń IMAP, które wykorzystuje zaszyfrowane hasło z połączenia IMAP w pamięci. Kopie zapasowe są przechowywane, jeśli nie zostanie wykryta żadna istniejąca kopia zapasowa lub jeśli SHA-256 hash w pliku uległ zmianie w porównaniu z najnowszą kopią zapasową.

Zauważ, że używamy VACUUM INTO polecenie w przeciwieństwie do wbudowanego backup polecenie, ponieważ jeśli strona zostanie zmodyfikowana podczas a backup polecenia, to trzeba zacząć od nowa. The VACUUM INTO polecenie wykona migawkę. Zobacz te komentarze dot GitHub oraz Wiadomości hakerskie aby uzyskać więcej informacji.

Dodatkowo używamy VACUUM INTO w przeciwieństwie do backup, ponieważ backup polecenie pozostawi bazę danych niezaszyfrowaną na krótki okres do rekey jest wywoływany (zobacz ten GitHub komentarz dla wglądu).

Szkoła Podstawowa będzie instruować Organizację Podstawową w zakresie WebSocket połączenie w celu wykonania kopii zapasowej – a Podstawowy otrzyma wówczas polecenie, aby to zrobić, a następnie:

  1. Połącz się ze swoją zaszyfrowaną skrzynką pocztową.
  2. Zdobądź blokadę zapisu.
  3. Uruchom punkt kontrolny WAL poprzez wal_checkpoint(PASSIVE).
  4. Uruchom VACUUM INTO Polecenie SQLite.
  5. Upewnij się, że skopiowany plik można otworzyć za pomocą zaszyfrowanego hasła (zabezpieczenie/zabezpieczenie fikcyjne).
  6. Prześlij go do Cloudflare R2 w celu przechowywania (lub u własnego dostawcy, jeśli określono).

Pamiętaj, że Twoje skrzynki pocztowe są szyfrowane — i chociaż mamy ograniczenia IP i inne środki uwierzytelniania dla komunikacji WebSocket — w przypadku złego aktora możesz mieć pewność, że jeśli ładunek WebSocket nie będzie zawierał Twojego hasła IMAP, nie będzie mógł otworzyć Twojej bazy danych .

Obecnie na każdą skrzynkę pocztową przechowywana jest tylko jedna kopia zapasowa, ale w przyszłości możemy zaoferować odzyskiwanie do określonego momentu („PITR").

Nasze serwery IMAP obsługują SEARCH polecenia ze złożonymi zapytaniami, wyrażeniami regularnymi i nie tylko.

Szybka wydajność wyszukiwania jest dzięki FTS5 oraz sqlite-regex.

przechowujemy Date wartości w skrzynkach pocztowych SQLite jako ISO 8601 ciągi przez Date.prototype.toISOString (ze strefą czasową UTC, aby porównania równości działały prawidłowo).

Indeksy są również przechowywane dla wszystkich właściwości występujących w zapytaniach wyszukiwania.

Projektowanie

Oto tabela przedstawiająca projekty, których używamy w naszym kodzie źródłowym i procesie programowania (posortowane alfabetycznie):

ProjektZamiar
AnsiblePlatforma automatyzacji DevOps do łatwego utrzymywania, skalowania i zarządzania całą naszą flotą serwerów.
BreeHarmonogram zadań dla Node.js i JavaScript z cron, date, ms, later i przyjazną dla człowieka obsługą.
KabinaPrzyjazna dla programistów biblioteka rejestrowania JavaScript i Node.js z myślą o bezpieczeństwie i prywatności.
PozwolićFramework Node.js, który wspiera całą naszą architekturę i projekty inżynieryjne za pomocą MVC i nie tylko.
MongoDBRozwiązanie bazodanowe NoSQL, którego używamy do przechowywania wszystkich innych danych poza skrzynkami pocztowymi (np. Twoje konto, ustawienia, domeny i konfiguracje aliasów).
MangustaModelowanie dokumentów obiektowych MongoDB („ODM”), którego używamy w całym naszym stosie. Napisaliśmy specjalne pomocniki, które pozwalają nam po prostu kontynuować korzystanie Mangusta z SQLite 🎉
Node.jsNode.js to wieloplatformowe środowisko uruchomieniowe JavaScript o otwartym kodzie źródłowym, w którym uruchamiane są wszystkie nasze procesy serwerowe.
Uwaga na pocztęPakiet Node.js do wysyłania e-maili, tworzenia połączeń i nie tylko. Jesteśmy oficjalnym sponsorem tego projektu.
RedisaBaza danych w pamięci do buforowania, kanałów publikowania/subskrypcji i DNS przez żądania HTTPS.
SQLite3MultipleCiphersRozszerzenie szyfrowania dla SQLite umożliwiające szyfrowanie całych plików bazy danych (w tym dziennika zapisu z wyprzedzeniem („WAL"), dziennik, wycofanie, ...).
SQLiteStudioWizualny edytor SQLite (którego możesz również użyć) do testowania, pobierania i przeglądania skrzynek pocztowych programistów.
SQLiteWbudowana warstwa bazy danych zapewniająca skalowalne, samodzielne, szybkie i odporne przechowywanie IMAP.
Skaner spamuNarzędzie antyspamowe, filtrujące pocztę e-mail i zapobiegające phishingowi Node.js (nasza alternatywa dla Zabójca spamu oraz rspamd).
MandarynkaDNS przez żądania HTTPS z Node.js i buforowanie przy użyciu Redis – co zapewnia globalną spójność i wiele więcej.
ThunderbirdNasz zespół programistów używa tego (i również to zaleca) jako preferowany klient poczty e-mail używany z funkcją przesyłania dalej.
UTMNasz zespół programistów używa tej maszyny wirtualnej do tworzenia maszyn wirtualnych dla iOS i macOS w celu testowania różnych klientów poczty e-mail (równolegle) z naszymi serwerami IMAP i SMTP.
UbuntuNowoczesny serwerowy system operacyjny typu open source oparty na systemie Linux, który napędza całą naszą infrastrukturę.
Dzika kaczkaBiblioteka serwerów IMAP – zobacz jej uwagi na deduplikacja załączników oraz Obsługa protokołu IMAP.
lepsze-sqlite3-wiele-szyfrówSzybka i prosta biblioteka API dla Node.js do programowej interakcji z SQLite3.
Szablony wiadomościPrzyjazna dla programistów platforma e-mail do tworzenia, podglądu i wysyłania niestandardowych wiadomości e-mail (np. powiadomień o koncie i nie tylko).
json-sqlKreator zapytań SQL wykorzystujący składnię w stylu Mongo. Oszczędza to czas naszego zespołu programistów, ponieważ możemy kontynuować pisanie w stylu Mongo na całym stosie, stosując podejście niezależne od bazy danych. Pomaga także uniknąć ataków polegających na wstrzykiwaniu SQL poprzez użycie parametrów zapytania.
Inspektor schematu knexNarzędzie SQL do wyodrębniania informacji o istniejącym schemacie bazy danych. Pozwala nam to łatwo sprawdzić, czy wszystkie indeksy, tabele, kolumny, ograniczenia i inne są prawidłowe i są 1:1 z tym, jak powinny wyglądać. Napisaliśmy nawet automatyczne pomocniki, które dodadzą nowe kolumny i indeksy w przypadku wprowadzenia zmian w schematach baz danych (z niezwykle szczegółowym powiadamianiem o błędach).
knexKreator zapytań SQL, którego używamy tylko do migracji baz danych i sprawdzania poprawności schematu knex-schema-inspector.
mandarynkaAutomatyczny 18n tłumaczenie fraz z obsługą Markdown przy użyciu API tłumaczenia w chmurze Google.
mx-connectPakiet Node.js do rozwiązywania i nawiązywania połączeń z serwerami MX oraz obsługi błędów.
2:00Menedżer procesów produkcyjnych Node.js z wbudowanym modułem równoważenia obciążenia (dostrojony za wydajność).
serwer smtpBiblioteka serwerów SMTP – używamy jej do naszych serwerów wymiany poczty („MX”) i serwerów wychodzących SMTP.
Test ImapPrzydatne narzędzie do testowania serwerów IMAP pod kątem testów porównawczych i zgodności protokołu IMAP ze specyfikacją RFC. Projekt ten został stworzony przez firmę Gołębnik zespół (aktywny serwer IMAP i POP3 o otwartym kodzie źródłowym od lipca 2002 r.). Za pomocą tego narzędzia dokładnie przetestowaliśmy nasz serwer IMAP.

Możesz znaleźć inne projekty, w których używamy nasz kod źródłowy na GitHubie.

Dostawcy

DostawcaZamiar
Rozbłysk chmurDostawca DNS, kontrole stanu, moduły równoważenia obciążenia i miejsce na kopie zapasowe Cloudflare R2.
Cyfrowy oceanHosting serwerów dedykowanych, pamięć blokowa SSD i zarządzane bazy danych.
VultrHosting serwerów dedykowanych i pamięć blokowa SSD.

Myśli

Zasady

Przesyłanie wiadomości e-mail zostało zaprojektowane zgodnie z następującymi zasadami:

  1. Zawsze bądź przyjazny dla programistów, skupiający się na bezpieczeństwie i prywatności oraz przejrzysty.
  2. Przestrzegaj MVC, Uniksa, KISS, DRY, YAGNI, Dwanaście czynników, Brzytwa Ockhama, oraz karmienie psów
  3. Celuj w scrappy, bootstrap i ramen-dochodowy deweloper

Eksperymenty

tldr; Ostatecznie korzystanie z pamięci obiektowej i/lub tabel wirtualnych zgodnych z S3 nie jest technicznie wykonalne ze względu na wydajność i jest podatne na błędy z powodu ograniczeń pamięci.

Przeprowadziliśmy kilka eksperymentów prowadzących do ostatecznego rozwiązania SQLite, jak omówiono powyżej.

Jednym z nich była próba użycia rclone i SQLite wraz z warstwą pamięci kompatybilną z S3.

Ten eksperyment doprowadził nas do lepszego zrozumienia i odkrycia przypadków brzegowych związanych z rclone, SQLite i VFS stosowanie:

  • Jeśli włączysz --vfs-cache-mode writes flag za pomocą rclone, wtedy odczyty będą OK, jednak zapisy będą buforowane.
    • Jeśli masz wiele serwerów IMAP rozproszonych na całym świecie, pamięć podręczna będzie na nich wyłączona, chyba że masz jednego autora i wielu słuchaczy (np. podejście pub/sub).
    • Jest to niezwykle złożone i dodanie dodatkowej złożoności tego typu spowoduje więcej pojedynczych punktów awarii.
    • Dostawcy pamięci masowej kompatybilni z S3 nie obsługują częściowych zmian plików – co oznacza jakąkolwiek zmianę pliku .sqlite plik spowoduje całkowitą zmianę i ponowne przesłanie bazy danych.
    • Inne rozwiązania, np rsync istnieją, ale nie skupiają się na dzienniku zapisu z wyprzedzeniem („WAL") - więc ostatecznie sprawdziliśmy Litestream. Na szczęście nasze użycie szyfrowania już szyfruje WAL plików za nas, więc nie musimy w tym celu polegać na Litestream. Jednak nie byliśmy jeszcze pewni Litestream do użytku produkcyjnego i poniżej zamieszczamy kilka uwag na ten temat.
    • Korzystając z tej opcji --vfs-cache-mode writes (t tylko sposób na użycie SQLite rclone do zapisu) podejmie próbę skopiowania całej bazy danych od zera do pamięci – obsługa jednej skrzynki pocztowej o pojemności 10 GB jest OK, jednak obsługa wielu skrzynek pocztowych o wyjątkowo dużej pojemności spowoduje, że serwery IMAP będą miały ograniczenia pamięci i ENOMEM błędy, błędy segmentacji i uszkodzenia danych.
  • Jeśli spróbujesz użyć SQLite Wirtualne stoły (np. za pomocą s3db), aby dane znajdowały się w warstwie pamięci kompatybilnej z S3, napotkasz kilka dodatkowych problemów:
    • Odczyt i zapis będą bardzo powolne, ponieważ punkty końcowe interfejsu API S3 będą musiały zostać trafione za pomocą protokołu HTTP GET, PUT, HEAD, oraz POST metody.
    • Testy rozwojowe wykazały, że przekraczanie 500K-1M+ rekordów w Internecie światłowodowym jest w dalszym ciągu ograniczone przepustowością zapisu i odczytu dla dostawców kompatybilnych z S3. Na przykład nasi programiści pobiegli for pętle do wykonywania obu sekwencyjnych operacji SQL INSERT instrukcje i te, które masowo zapisywały duże ilości danych. W obu przypadkach występ był zdumiewająco powolny.
    • Wirtualne stoły nie może mieć indeksów, ALTER TABLE wypowiedzi i Inny ograniczenia – co prowadzi do opóźnień sięgających 1-2 minut lub więcej, w zależności od ilości danych.
    • Obiekty były przechowywane w postaci niezaszyfrowanej i nie jest łatwo dostępna natywna obsługa szyfrowania.
  • Zbadaliśmy także użycie sqlite-s3vfs który jest podobny koncepcyjnie i technicznie do poprzedniego punktu (więc ma te same problemy). Jedną z możliwości byłoby użycie zwyczaju sqlite3 kompilacja owinięta szyfrowaniem, takim jak wxSQLite3 (którego obecnie używamy w naszym rozwiązaniu powyżej) poprzez edycja pliku instalacyjnego.
  • Innym potencjalnym podejściem było użycie metody przedłużenie multipleksu, jednakże ma to ograniczenie do 32 GB i wymagałoby skomplikowanych problemów związanych z budowaniem i programowaniem.
  • ALTER TABLE wymagane są instrukcje (więc całkowicie wyklucza to użycie wirtualnych tabel). Potrzebujemy ALTER TABLE instrukcje, aby nasz hak z knex-schema-inspector działać poprawnie – co gwarantuje, że dane nie zostaną uszkodzone, a odzyskane wiersze będą mogły zostać przekonwertowane na prawidłowe dokumenty zgodnie z naszymi mongoose definicje schematów (które obejmują ograniczenia, typ zmiennej i dowolną walidację danych).
  • Prawie wszystkie projekty kompatybilne z S3, związane z SQLite w społeczności open source, są w Pythonie (a nie w JavaScript, którego używamy w 100% naszego stosu).
  • Biblioteki kompresji, takie jak sqlite-zstd (Widzieć uwagi) wyglądają obiecująco, ale mogą nie być jeszcze gotowe do użytku produkcyjnego. Zamiast tego kompresja po stronie aplikacji dla typów danych, takich jak String, Object, Map, Array, Set, oraz Buffer będzie czystszym i łatwiejszym podejściem (a także łatwiej jest migrować, ponieważ moglibyśmy przechowywać plik Boolean flaga lub kolumna – lub nawet użyć PRAGMA user_version=1 do kompresji lub user_version=0 bez kompresji jako metadane bazy danych).
    • Na szczęście w pamięci naszego serwera IMAP wdrożono już funkcję usuwania duplikatów załączników — dlatego w każdej wiadomości z tym samym załącznikiem nie zostanie zachowana kopia załącznika — zamiast tego pojedynczy załącznik jest przechowywany dla wielu wiadomości i wątków w skrzynce pocztowej (a obcy później stosuje się odniesienie).
  • Projekt Litestream, będący rozwiązaniem do replikacji i tworzenia kopii zapasowych SQLite, jest bardzo obiecujący i najprawdopodobniej będziemy z niego korzystać w przyszłości.
  • Przywracanie kopii zapasowych musi być bezproblemowe i proste. Korzystanie z rozwiązania takiego jak MongoDB z mongodump oraz mongoexport jest nie tylko żmudne, ale także czasochłonne i wymaga złożoności konfiguracji.
    • Bazy danych SQLite sprawiają, że jest to proste (jest to pojedynczy plik).
    • Chcieliśmy zaprojektować rozwiązanie, w którym użytkownicy będą mogli w każdej chwili zabrać swoją skrzynkę pocztową i wyjść.
      • Proste polecenia Node.js do fs.unlink('mailbox.sqlite')) i jest trwale usuwany z pamięci dyskowej.
      • W podobny sposób możemy używać interfejsu API zgodnego z S3 z protokołem HTTP DELETE aby łatwo usuwać migawki i kopie zapasowe dla użytkowników.
    • SQLite był najprostszym, najszybszym i najbardziej opłacalnym rozwiązaniem.

Brak alternatyw

Według naszej wiedzy żadne inne usługi e-mail nie są zaprojektowane w ten sposób ani nie są typu open source.

My myślę, że to może być spowodowane do istniejących usług e-mail, w których wykorzystywana jest starsza technologia kod spaghetti 🍝.

Większość, jeśli nie wszyscy, istniejących dostawców usług e-mail to dostawcy usług o zamkniętym kodzie źródłowym lub reklamujący się jako dostawcy o otwartym kodzie źródłowym, ale w rzeczywistości tylko ich front-end jest open-source.

Najbardziej wrażliwa część wiadomości e-mail (rzeczywista interakcja przechowywania/IMAP/SMTP) wszystko odbywa się na zapleczu (serwerze) i nie na froncie (klient).

Wypróbuj funkcję przesyłania dalej e-mailem

Zapisz się już dziś o godz https://forwardemail.net! 🚀