Email Resistente al Quantum: Come utilizziamo cassette postali SQLite criptate per mantenere la tua email sicura

Illustrazione del servizio email criptato sicuro contro il quantum

Prefazione

Important

Il nostro servizio email è 100% open-source e focalizzato sulla privacy tramite cassette postali SQLite sicure e criptate.

Fino al lancio del supporto IMAP, utilizzavamo MongoDB per le nostre esigenze di archiviazione dati persistente.

Questa tecnologia è straordinaria e la usiamo ancora oggi – ma per avere la crittografia a riposo con MongoDB è necessario utilizzare un provider che offra MongoDB Enterprise, come Digital Ocean o Mongo Atlas – oppure pagare una licenza enterprise (e di conseguenza dover gestire i tempi di risposta del team commerciale).

Il nostro team di Forward Email aveva bisogno di una soluzione di archiviazione crittografata, scalabile, affidabile e amichevole per gli sviluppatori per le cassette postali IMAP. Come sviluppatori open-source, usare una tecnologia per cui è necessario pagare una licenza per ottenere la crittografia a riposo andava contro i nostri principi – così abbiamo sperimentato, ricercato e sviluppato una nuova soluzione da zero per soddisfare queste esigenze.

Invece di usare un database condiviso per memorizzare le tue cassette postali, le memorizziamo e crittografiamo individualmente con la tua password (che solo tu possiedi). Il nostro servizio email è così sicuro che se dimentichi la tua password, perdi la tua casella (e devi recuperare con backup offline o ricominciare da capo).

Continua a leggere mentre approfondiamo con un confronto tra provider di servizi email, come funziona il nostro servizio, la nostra tecnologia e altro.

Confronto tra provider di servizi email

Siamo l’unico provider di servizi email 100% open-source e focalizzato sulla privacy che memorizza cassette postali SQLite criptate individualmente, offre domini, alias e utenti illimitati, e supporta SMTP in uscita, IMAP e POP3:

A differenza di altri provider email, con Forward Email non devi pagare per lo spazio di archiviazione su base per dominio o alias. Lo spazio è condiviso su tutto il tuo account – quindi se hai più nomi di dominio personalizzati e più alias per ciascuno, siamo la soluzione perfetta per te. Nota che puoi comunque imporre limiti di archiviazione se desideri su base per dominio o alias.

Leggi il Confronto tra Servizi Email

Come funziona

  1. Usando il tuo client email come Apple Mail, Thunderbird, Gmail o Outlook – ti connetti ai nostri server IMAP sicuri usando il tuo nome utente e password:

    • Il tuo nome utente è il tuo alias completo con il dominio, ad esempio hello@example.com.
    • La tua password è generata casualmente e mostrata solo a te per 30 secondi quando clicchi su Genera Password da Il Mio Account Domini Alias.
  2. Una volta connesso, il tuo client di posta invierà comandi del protocollo IMAP al nostro server IMAP per mantenere la tua casella di posta sincronizzata. Questo include la scrittura e la memorizzazione di bozze di email e altre azioni che potresti fare (ad esempio, etichettare un'email come Importante o contrassegnare un'email come Spam/Posta Indesiderata).

  3. I server di scambio mail (comunemente noti come server "MX") ricevono nuove email in arrivo e le memorizzano nella tua casella di posta. Quando ciò accade, il tuo client di posta viene notificato e sincronizza la tua casella. I nostri server di scambio mail possono inoltrare la tua email a uno o più destinatari (inclusi i webhook), memorizzare la tua email per te nel tuo spazio IMAP crittografato con noi, o entrambi!

  4. Dietro le quinte, il nostro design di archiviazione email sicura funziona in due modi per mantenere le tue caselle di posta crittografate e accessibili solo da te:

    • Quando arriva una nuova mail per te da un mittente, i nostri server di scambio mail scrivono in una casella di posta individuale, temporanea e crittografata per te.

    • Quando ti connetti al nostro server IMAP con il tuo client di posta, la tua password viene crittografata in memoria e usata per leggere e scrivere nella tua casella di posta. La tua casella può essere letta e scritta solo con questa password. Tieni presente che, poiché sei l'unico a possedere questa password, solo tu puoi leggere e scrivere nella tua casella quando la stai utilizzando. La prossima volta che il tuo client di posta tenterà di controllare la posta o sincronizzarsi, i nuovi messaggi verranno trasferiti da questa casella temporanea e memorizzati nel file della tua casella reale usando la password fornita. Nota che questa casella temporanea viene poi svuotata e cancellata in modo che solo la tua casella protetta da password contenga i messaggi.

    • Se sei connesso a IMAP (ad esempio usando un client di posta come Apple Mail o Thunderbird), allora non è necessario scrivere su uno storage temporaneo su disco. La tua password IMAP crittografata in memoria viene invece recuperata e usata. In tempo reale, quando un messaggio sta per essere consegnato a te, inviamo una richiesta WebSocket a tutti i server IMAP chiedendo se hanno una sessione attiva per te (questa è la parte di fetch), e successivamente passeremo quella password crittografata in memoria – così non dobbiamo scrivere in una casella temporanea, possiamo scrivere direttamente nella tua casella crittografata usando la tua password crittografata.

  5. I backup delle tue caselle di posta crittografate vengono effettuati quotidianamente. Puoi anche richiedere un nuovo backup in qualsiasi momento o scaricare l'ultimo backup da Il Mio Account Domini Alias. Se decidi di passare a un altro servizio email, puoi facilmente migrare, scaricare, esportare e cancellare le tue caselle e i backup in qualsiasi momento.

Tecnologie

Database

Abbiamo esplorato altri possibili livelli di archiviazione database, tuttavia nessuno ha soddisfatto le nostre esigenze quanto SQLite:

Database Crittografia a riposo Caselle di posta Sandboxed Licenza Usato Ovunque
SQLite ✅ Sì con SQLite3MultipleCiphers ✅ Pubblico Dominio
MongoDB "Disponibile solo in MongoDB Enterprise" ❌ Database relazionale ❌ AGPL e SSPL-1.0
rqlite Solo rete ❌ Database relazionale MIT
dqlite Non testato e non ancora supportato? Non testato e non ancora supportato? LGPL-3.0-only
PostgreSQL ❌ Database relazionale PostgreSQL (simile a BSD o MIT)
MariaDB Solo per InnoDB ❌ Database relazionale GPLv2 e BUSL-1.1
CockroachDB Funzionalità solo Enterprise ❌ Database relazionale BUSL-1.1 e altri

Ecco un post sul blog che confronta diverse opzioni di archiviazione del database SQLite nella tabella sopra.

Sicurezza

In ogni momento utilizziamo crittografia a riposo (AES-256), crittografia in transito (TLS), DNS over HTTPS ("DoH") usando 🍊 Tangerine, e la crittografia sqleet (ChaCha20-Poly1305) sulle caselle di posta. Inoltre utilizziamo l'autenticazione a due fattori basata su token (invece di SMS che è suscettibile a attacchi man-in-the-middle), chiavi SSH ruotate con accesso root disabilitato, accesso esclusivo ai server tramite indirizzi IP limitati e altro ancora. In caso di un attacco evil maid o di un dipendente infedele di un fornitore terzo, la tua casella di posta può comunque essere aperta solo con la password che hai generato tu. Stai tranquillo, non ci affidiamo a nessun fornitore terzo oltre ai nostri provider di server conformi SOC Type 2 come Cloudflare, DataPacket, Digital Ocean, GitHub e Vultr.

Il nostro obiettivo è avere il minor numero possibile di punti singoli di guasto.

Caselle di posta

tldr; I nostri server IMAP utilizzano database SQLite crittografati individualmente per ciascuna delle tue caselle di posta.

SQLite è un database embedded estremamente popolare – attualmente è in esecuzione sul tuo telefono e computer – e utilizzato da quasi tutte le principali tecnologie.

Ad esempio, sui nostri server crittografati c’è un database SQLite per la casella linux@example.com, info@example.com, hello@example.com e così via – uno per ciascuna come file database .sqlite. Non nominiamo i file database con l’indirizzo email – invece usiamo BSON ObjectID e UUID unici generati che non rivelano a chi appartiene la casella o quale indirizzo email rappresentano (es. 353a03f21e534321f5d6e267.sqlite).

Ognuno di questi database è crittografato usando la tua password (che solo tu possiedi) tramite sqleet (ChaCha20-Poly1305). Questo significa che le tue caselle sono crittografate individualmente, autonome, sandboxed e portatili.

Abbiamo ottimizzato SQLite con i seguenti PRAGMA:

PRAGMA Scopo
cipher=chacha20 Crittografia del database SQLite ChaCha20-Poly1305. Consulta better-sqlite3-multiple-ciphers sotto Projects per maggiori dettagli.
key="****************" Questa è la tua password decrittata solo in memoria che viene passata tramite la connessione IMAP del tuo client email al nostro server. Nuove istanze di database vengono create e chiuse per ogni sessione di lettura e scrittura (per garantire sandboxing e isolamento).
journal_mode=WAL Write-ahead-log ("WAL") che migliora le prestazioni e permette accessi di lettura concorrenti.
busy_timeout=5000 Previene errori di blocco in scrittura mentre altre scritture sono in corso.
synchronous=NORMAL Aumenta la durabilità delle transazioni senza rischio di corruzione dati.
foreign_keys=ON Impone che i riferimenti alle chiavi esterne (es. una relazione da una tabella a un’altra) siano rispettati. Di default non è attivato in SQLite, ma per la validazione e integrità dei dati dovrebbe essere abilitato.
encoding='UTF-8' Codifica predefinita da usare per garantire coerenza agli sviluppatori.

Tutti gli altri valori predefiniti provengono da SQLite come specificato nella documentazione ufficiale PRAGMA.

Concorrenza

tldr; Usiamo WebSocket per letture e scritture concorrenti nelle tue cassette postali SQLite criptate.

Letture

Il tuo client email sul telefono potrebbe risolvere imap.forwardemail.net in uno dei nostri indirizzi IP Digital Ocean – e il tuo client desktop potrebbe risolvere un IP separato da un diverso provider.

Indipendentemente da quale server IMAP il tuo client email si connetta, vogliamo che la connessione legga dal tuo database in tempo reale con il 100% di accuratezza. Questo viene fatto tramite WebSockets.

Scritture

Scrivere nel tuo database è un po' diverso – dato che SQLite è un database embedded e la tua cassetta postale risiede in un singolo file di default.

Abbiamo esplorato opzioni come litestream, rqlite e dqlite di seguito – tuttavia nessuna di queste ha soddisfatto i nostri requisiti.

Per eseguire scritture con il write-ahead-logging ("WAL") abilitato – dobbiamo assicurarci che solo un server ("Primario") sia responsabile di farlo. WAL accelera drasticamente la concorrenza e permette un solo scrittore e più lettori.

Il Primario è in esecuzione sui server dati con i volumi montati contenenti le cassette postali criptate. Dal punto di vista della distribuzione, potresti considerare tutti i singoli server IMAP dietro imap.forwardemail.net come server secondari ("Secondari").

Realizziamo una comunicazione bidirezionale con WebSockets:

  • I server Primari usano un'istanza del server WebSocketServer di ws.
  • I server Secondari usano un'istanza client WebSocket di ws avvolta con websocket-as-promised e reconnecting-websocket. Questi due wrapper assicurano che il WebSocket si ricolleghi e possa inviare e ricevere dati per scritture specifiche nel database.

Backup

tldr; I backup delle tue cassette postali criptate vengono effettuati quotidianamente. Puoi anche richiedere istantaneamente un nuovo backup o scaricare l'ultimo backup in qualsiasi momento da Il Mio Account Domini Alias.

Per i backup, eseguiamo semplicemente il comando SQLite VACUUM INTO ogni giorno durante l'elaborazione dei comandi IMAP, che sfrutta la tua password criptata da una connessione IMAP in memoria. I backup vengono salvati se non viene rilevato un backup esistente o se l'hash SHA-256 è cambiato sul file rispetto all'ultimo backup più recente.

Nota che usiamo il comando VACUUM INTO invece del comando backup integrato perché se una pagina viene modificata durante un'operazione di comando backup, allora deve ricominciare da capo. Il comando VACUUM INTO scatta un'istantanea. Vedi questi commenti su GitHub e Hacker News per maggiori dettagli.

Inoltre usiamo VACUUM INTO invece di backup, perché il comando backup lascerebbe il database non criptato per un breve periodo fino a quando non viene invocato rekey (vedi questo commento GitHub commento per approfondimenti).

Il Secondario istruirà il Primario tramite la connessione WebSocket per eseguire il backup – e il Primario riceverà il comando per farlo e successivamente:

  1. Si connetterà alla tua cassetta postale criptata.
  2. Acquisirà un lock di scrittura.
  3. Eseguirà un checkpoint WAL tramite wal_checkpoint(PASSIVE).
  4. Eseguirà il comando SQLite VACUUM INTO.
  5. Verificherà che il file copiato possa essere aperto con la password criptata (protezione/garanzia).
  6. Lo caricherà su Cloudflare R2 per l'archiviazione (o sul tuo provider se specificato).

Ricorda che le tue caselle di posta sono criptate – e mentre abbiamo restrizioni IP e altre misure di autenticazione in atto per la comunicazione WebSocket – in caso di un attore malevolo, puoi stare tranquillo che a meno che il payload WebSocket non contenga la tua password IMAP, non può aprire il tuo database.

Al momento viene memorizzato un solo backup per casella di posta, ma in futuro potremmo offrire il recupero puntuale ("PITR").

I nostri server IMAP supportano il comando SEARCH con query complesse, espressioni regolari e altro.

Le prestazioni di ricerca rapide sono grazie a FTS5 e sqlite-regex.

Memorizziamo i valori Date nelle caselle SQLite come stringhe ISO 8601 tramite Date.prototype.toISOString (con fuso orario UTC affinché le comparazioni di uguaglianza funzionino correttamente).

Sono inoltre memorizzati indici per tutte le proprietà presenti nelle query di ricerca.

Progetti

Ecco una tabella che illustra i progetti che utilizziamo nel nostro codice sorgente e nel processo di sviluppo (ordinati alfabeticamente):

Progetto Scopo
Ansible Piattaforma di automazione DevOps per mantenere, scalare e gestire con facilità l'intera flotta di server.
Bree Scheduler di job per Node.js e JavaScript con supporto per cron, date, ms, later e formati umani.
Cabin Libreria di logging JavaScript e Node.js amichevole per sviluppatori, con attenzione a sicurezza e privacy.
Lad Framework Node.js che alimenta tutta la nostra architettura e design ingegneristico con MVC e altro.
MongoDB Soluzione database NoSQL che usiamo per memorizzare tutti gli altri dati al di fuori delle caselle di posta (es. il tuo account, impostazioni, domini e configurazioni alias).
Mongoose Object document modeling ("ODM") per MongoDB che usiamo in tutto il nostro stack. Abbiamo scritto helper speciali che ci permettono di continuare a usare Mongoose con SQLite 🎉
Node.js Node.js è l'ambiente di runtime JavaScript open-source e multipiattaforma che esegue tutti i nostri processi server.
Nodemailer Pacchetto Node.js per inviare email, creare connessioni e altro. Siamo sponsor ufficiali di questo progetto.
Redis Database in-memory per caching, canali publish/subscribe e richieste DNS over HTTPS.
SQLite3MultipleCiphers Estensione di crittografia per SQLite che permette di criptare interi file di database (inclusi write-ahead-log ("WAL"), journal, rollback, …).
SQLiteStudio Editor visuale SQLite (che potresti anche usare) per testare, scaricare e visualizzare caselle di posta di sviluppo.
SQLite Livello di database embedded per uno storage IMAP scalabile, autonomo, veloce e resiliente.
Spam Scanner Strumento Node.js anti-spam, filtro email e prevenzione phishing (nostra alternativa a Spam Assassin e rspamd).
Tangerine Richieste DNS over HTTPS con Node.js e caching usando Redis – che garantisce coerenza globale e molto altro.
Thunderbird Il nostro team di sviluppo usa questo (e lo raccomanda) come client email preferito da usare con Forward Email.
UTM Il nostro team di sviluppo usa questo per creare macchine virtuali per iOS e macOS al fine di testare diversi client email (in parallelo) con i nostri server IMAP e SMTP.
Ubuntu Sistema operativo server moderno open-source basato su Linux che alimenta tutta la nostra infrastruttura.
WildDuck Libreria server IMAP – vedi le sue note su de-duplicazione allegati e supporto protocollo IMAP.
better-sqlite3-multiple-ciphers Libreria API veloce e semplice per Node.js per interagire programmaticamente con SQLite3.
email-templates Framework email amichevole per sviluppatori per creare, visualizzare in anteprima e inviare email personalizzate (es. notifiche account e altro).
json-sql-enhanced Costruttore di query SQL usando sintassi in stile Mongo. Questo fa risparmiare tempo al nostro team di sviluppo poiché possiamo continuare a scrivere in stile Mongo in tutto lo stack con un approccio agnostico al database. Aiuta anche a evitare attacchi di SQL injection usando parametri di query.
knex-schema-inspector Utility SQL per estrarre informazioni sullo schema di database esistente. Questo ci permette di validare facilmente che tutti gli indici, tabelle, colonne, vincoli e altro siano validi e corrispondano 1:1 a come dovrebbero essere. Abbiamo anche scritto helper automatici per aggiungere nuove colonne e indici se vengono fatte modifiche agli schemi di database (con avvisi di errore estremamente dettagliati).
knex Costruttore di query SQL che usiamo solo per migrazioni di database e validazione schema tramite knex-schema-inspector.
mandarin Traduzione automatica di frasi i18n con supporto per Markdown usando Google Cloud Translation API.
mx-connect Pacchetto Node.js per risolvere e stabilire connessioni con server MX e gestire errori.
pm2 Gestore di processi di produzione Node.js con bilanciatore di carico integrato (ottimizzato per le prestazioni).
smtp-server Libreria server SMTP – la usiamo per i nostri server di scambio mail ("MX") e SMTP in uscita.
ImapTest Strumento utile per testare server IMAP rispetto a benchmark e compatibilità con la specifica RFC del protocollo IMAP. Questo progetto è stato creato dal team di Dovecot (un server IMAP e POP3 open-source attivo da luglio 2002). Abbiamo testato ampiamente il nostro server IMAP con questo strumento.

Puoi trovare altri progetti che utilizziamo in il nostro codice sorgente su GitHub.

Provider

Provider Scopo
Cloudflare Provider DNS, controlli di integrità, bilanciatori di carico e storage di backup usando Cloudflare R2.
GitHub Hosting del codice sorgente, CI/CD e gestione del progetto.
Digital Ocean Hosting di server dedicati e database gestiti.
Vultr Hosting di server dedicati.
DataPacket Hosting di server dedicati.

Considerazioni

Principi

Forward Email è progettato secondo questi principi:

  1. Essere sempre orientato agli sviluppatori, con attenzione alla sicurezza, alla privacy e alla trasparenza.
  2. Attenersi a MVC, Unix, KISS, DRY, YAGNI, Twelve Factor, Rasoio di Occam e dogfooding
  3. Rivolgersi agli sviluppatori intraprendenti, autofinanziati e ramen-profitable

Esperimenti

tldr; In definitiva, l’uso di storage oggetti compatibile con S3 e/o Tabelle Virtuali non è tecnicamente fattibile per motivi di prestazioni ed è soggetto a errori a causa di limitazioni di memoria.

Abbiamo condotto alcuni esperimenti che ci hanno portato alla nostra soluzione finale con SQLite come discusso sopra.

Uno di questi è stato provare a usare rclone e SQLite insieme a un livello di storage compatibile con S3.

Questo esperimento ci ha portato a comprendere meglio e scoprire casi limite riguardanti l’uso di rclone, SQLite e VFS:

  • Se abiliti il flag --vfs-cache-mode writes con rclone, allora le letture andranno bene, tuttavia le scritture verranno memorizzate nella cache.
    • Se hai più server IMAP distribuiti globalmente, allora la cache sarà disallineata tra loro a meno che tu non abbia un singolo scrittore e più ascoltatori (ad esempio un approccio pub/sub).
    • Questo è incredibilmente complesso e aggiungere qualsiasi complessità ulteriore come questa comporterà più punti singoli di guasto.
    • I provider di storage compatibili con S3 non supportano modifiche parziali ai file – il che significa che ogni modifica al file .sqlite comporterà una modifica completa e un nuovo caricamento del database.
    • Esistono altre soluzioni come rsync, ma non sono focalizzate sul supporto del write-ahead-log ("WAL") – quindi abbiamo finito per esaminare Litestream. Fortunatamente il nostro uso della crittografia già cifra i file WAL per noi, quindi non dobbiamo fare affidamento su Litestream per questo. Tuttavia non eravamo ancora sicuri di Litestream per l’uso in produzione e abbiamo alcune note a riguardo più avanti.
    • Usare questa opzione --vfs-cache-mode writes (l’unico modo per usare SQLite su rclone per scritture) tenterà di copiare l’intero database da zero in memoria – gestire una casella da 10 GB va bene, ma gestire più caselle con uno storage estremamente elevato farà sì che i server IMAP incontrino limitazioni di memoria e errori ENOMEM, fault di segmentazione e corruzione dei dati.
  • Se provi a usare le Tabelle Virtuali di SQLite (ad esempio usando s3db) per avere dati direttamente su uno storage compatibile con S3, incontrerai diversi altri problemi:
    • Le letture e scritture saranno estremamente lente poiché gli endpoint API S3 dovranno essere colpiti con metodi HTTP GET, PUT, HEAD e POST.
    • I test di sviluppo hanno mostrato che superare 500K-1M+ record su internet in fibra è ancora limitato dalla velocità di scrittura e lettura verso provider compatibili con S3. Ad esempio, i nostri sviluppatori hanno eseguito cicli for per fare sia istruzioni SQL INSERT sequenziali sia scritture massive di grandi quantità di dati. In entrambi i casi le prestazioni erano incredibilmente lente.
    • Le tabelle virtuali non possono avere indici, istruzioni ALTER TABLE e altre limitazioni – il che porta a ritardi di 1-2 minuti o più a seconda della quantità di dati.
    • Gli oggetti venivano memorizzati non criptati e non è disponibile un supporto nativo per la crittografia.
  • Abbiamo anche esplorato l’uso di sqlite-s3vfs che è simile concettualmente e tecnicamente al punto precedente (quindi ha gli stessi problemi). Una possibilità sarebbe usare una build personalizzata di sqlite3 avvolta con crittografia come wxSQLite3 (che usiamo attualmente nella nostra soluzione sopra) tramite modifica del file di setup.
  • Un altro approccio potenziale era usare l’estensione multiplex, tuttavia questa ha una limitazione di 32 GB e richiederebbe costruzioni complesse e problemi di sviluppo.
  • Le istruzioni ALTER TABLE sono necessarie (quindi questo esclude completamente l’uso delle Tabelle Virtuali). Abbiamo bisogno delle istruzioni ALTER TABLE affinché il nostro hook con knex-schema-inspector funzioni correttamente – il che garantisce che i dati non vengano corrotti e che le righe recuperate possano essere convertite in documenti validi secondo le nostre definizioni di schema mongoose (che includono vincoli, tipi di variabili e validazione arbitraria dei dati).
  • Quasi tutti i progetti open-source relativi a SQLite compatibili con S3 sono in Python (e non in JavaScript che usiamo per il 100% del nostro stack).
  • Le librerie di compressione come sqlite-zstd (vedi commenti) sembrano promettenti, ma potrebbero non essere ancora pronte per l’uso in produzione. Invece la compressione lato applicazione su tipi di dati come String, Object, Map, Array, Set e Buffer sarà un approccio più pulito e semplice (e più facile da migrare, dato che potremmo memorizzare un flag o colonna Boolean – o anche usare PRAGMA user_version=1 per la compressione o user_version=0 per nessuna compressione come metadati del database).
    • Fortunatamente abbiamo già implementato la de-duplicazione degli allegati nel nostro storage del server IMAP – quindi ogni messaggio con lo stesso allegato non mantiene una copia dell’allegato – invece un singolo allegato è memorizzato per più messaggi e thread in una casella (e viene successivamente usato un riferimento esterno).
  • Il progetto Litestream, che è una soluzione di replica e backup per SQLite, è molto promettente e probabilmente lo useremo in futuro.
  • Il ripristino del backup deve essere senza attriti e banale. Usare una soluzione come MongoDB con mongodump e mongoexport non è solo tedioso, ma richiede molto tempo e ha complessità di configurazione.
    • I database SQLite lo rendono semplice (è un singolo file).
    • Volevamo progettare una soluzione in cui gli utenti potessero prendere la loro casella e andarsene in qualsiasi momento.
      • Comandi Node.js semplici come fs.unlink('mailbox.sqlite') e viene cancellato definitivamente dallo storage su disco.
      • Possiamo similmente usare un’API compatibile con S3 con HTTP DELETE per rimuovere facilmente snapshot e backup per gli utenti.
    • SQLite è stata la soluzione più semplice, veloce e conveniente.

Mancanza di alternative

A nostra conoscenza, nessun altro servizio email è progettato in questo modo né è open-source.

Pensiamo che ciò possa essere dovuto al fatto che i servizi email esistenti utilizzano tecnologie legacy in produzione con spaghetti code 🍝.

La maggior parte, se non tutti, i fornitori di servizi email esistenti sono o closed-source o si pubblicizzano come open-source, ma in realtà solo il loro front-end è open-source.

La parte più sensibile dell'email (la vera e propria memorizzazione/interazione IMAP/SMTP) avviene tutta sul back-end (server), e non sul front-end (client).

Prova Forward Email

Iscriviti oggi su https://forwardemail.net! 🚀