Aprofundamento: como usamos caixas de correio SQLite criptografadas com segurança quântica para nosso serviço de e-mail seguro e focado na privacidade

Ao contrário de outros serviços de e-mail , garantimos que apenas você tenha acesso à sua caixa de correio em todos os momentos.

Prefácio

tldr; Nosso serviço de e-mail é 100% código aberto e com foco na privacidade por meio de caixas de correio SQLite seguras e criptografadas.

Até lançarmos Suporte IMAP, usamos o MongoDB para nossas necessidades persistentes de armazenamento de dados.

Essa tecnologia é incrível e ainda a usamos hoje – mas para ter criptografia em repouso com o MongoDB você precisa usar um provedor que ofereça MongoDB Enterprise, como Digital Ocean ou Mongo Atlas – ou pagar por uma licença corporativa (e posteriormente terá que trabalhar com a latência da equipe de vendas).

Nossa equipe em Encaminhar email precisava de uma solução de armazenamento criptografada, escalável, confiável e amigável ao desenvolvedor para caixas de correio IMAP. Como desenvolvedores de código aberto, usar uma tecnologia que você precisa pagar uma taxa de licença para obter o recurso de criptografia em repouso era contra nossos princípios – e assim experimentamos, pesquisamos e desenvolvemos uma nova solução do zero para resolver essas necessidades.

Em vez de usar um banco de dados compartilhado para armazenar suas caixas de correio, armazenamos e criptografamos individualmente suas caixas de correio com sua senha (que só você possui). Nosso serviço de e-mail é tão seguro que se você esquecer sua senha, perderá sua caixa de correio (e precisa recuperar com backups offline ou recomeçar).

Continue lendo enquanto nos aprofundamos abaixo com um comparação de provedores de serviços de e-mail, Como nosso serviço funciona, nossa pilha de tecnologia, e mais.

Comparação de provedores de serviços de e-mail

Somos o único provedor de serviços de e-mail 100% de código aberto e focado na privacidade que armazena caixas de correio SQLite criptografadas individualmente, oferece domínios, aliases e usuários ilimitados e tem suporte de saída para SMTP, IMAP e POP3:

Ao contrário de outros provedores de e-mail, você não precisa pagar pelo armazenamento por domínio ou alias com o Forward Email. O armazenamento é compartilhado por toda a sua conta – portanto, se você tiver vários nomes de domínio personalizados e vários aliases em cada um, nós somos a solução perfeita para você. Observe que você ainda pode impor limites de armazenamento, se desejar, por domínio ou alias.

Leia a comparação de serviços de e-mail

Como funciona

  1. Usando seu cliente de e-mail, como Apple Mail, Thunderbird, Gmail ou Outlook – você se conecta ao nosso seguro IMAP servidores usando seu nome de usuário e senha:

    • Seu nome de usuário é o alias completo do seu domínio, como hello@example.com.
    • Sua senha é gerada aleatoriamente e exibida apenas por 30 segundos quando você clica Gerar senha de Minha conta Domínios Apelido.
  2. Uma vez conectado, seu cliente de e-mail enviará Comandos do protocolo IMAP ao nosso servidor IMAP para manter sua caixa de correio sincronizada. Isso inclui escrever e armazenar rascunhos de e-mails e outras ações que você pode realizar (por exemplo, rotular um e-mail como Importante ou sinalizar um e-mail como Spam/Lixo Eletrônico).

  3. Os servidores de troca de correio (comumente conhecidos como servidores "MX") recebem novos e-mails de entrada e os armazenam em sua caixa de correio. Quando isso acontecer, seu cliente de e-mail será notificado e sincronizará sua caixa de correio. Nossos servidores de troca de e-mail podem encaminhar seu e-mail para um ou mais destinatários (incluindo webhooks), armazene seu e-mail em seu armazenamento IMAP criptografado conosco, ou ambos!

    Interessado em aprender mais? Ler como configurar o encaminhamento de e-mail, como funciona nosso serviço de troca de correspondênciaou visualizar nossos guias.

  4. Nos bastidores, nosso design seguro de armazenamento de e-mail funciona de duas maneiras para manter suas caixas de correio criptografadas e acessíveis apenas para você:

    • Quando novas mensagens são recebidas de um remetente, nossos servidores de troca de mensagens escrevem para você uma caixa de correio individual, temporária e criptografada.

      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!
      
    • Quando você se conecta ao nosso servidor IMAP com seu cliente de e-mail, sua senha é criptografada na memória e usada para ler e escrever em sua caixa de correio. Sua caixa de correio só pode ser lida e gravada com esta senha. Lembre-se de que, como você é o único com essa senha, só você pode ler e escrever em sua caixa de correio quando você a acessa. Na próxima vez que seu cliente de e-mail tentar pesquisar e-mails ou sincronizar, suas novas mensagens serão transferidas desta caixa de correio temporária e armazenadas em seu arquivo de caixa de correio real usando a senha fornecida. Observe que esta caixa de correio temporária é limpa e excluída posteriormente, para que apenas sua caixa de correio protegida por senha tenha as mensagens.

    • Se você estiver conectado ao IMAP (por exemplo, usando um cliente de e-mail como Apple Mail ou Thunderbird), não precisaremos gravar no armazenamento temporário em disco. Sua senha IMAP criptografada na memória é buscada e usada. Em tempo real, quando uma mensagem tenta ser entregue a você, enviamos uma solicitação WebSocket a todos os servidores IMAP perguntando se eles têm uma sessão ativa para você (esta é a parte de busca) e, posteriormente, repassaremos essa senha criptografada na memória – para que não precisemos escrever em uma caixa de correio temporária, podemos escrever em sua caixa de correio criptografada real usando sua senha criptografada.

      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. Backups de suas caixas de correio criptografadas são feitos diariamente. Você também pode solicitar um novo backup a qualquer momento ou baixar o backup mais recente em Minha conta Domínios Apelido. Se decidir mudar para outro serviço de e-mail, você poderá migrar, baixar, exportar e limpar facilmente suas caixas de correio e backups a qualquer momento.

Tecnologias

Bancos de dados

Exploramos outras possíveis camadas de armazenamento de banco de dados, porém nenhuma atendeu tanto aos nossos requisitos quanto o SQLite:

Base de dadosCriptografia em repousoEm área restrita Caixas de correioLicençaUsado em todos os lugares
SQLite✅ Sim com SQLite3MúltiplasCifras✅ Domínio Público
MongoDB"Disponível apenas no MongoDB Enterprise"❌ Banco de dados relacional❌ AGPL e SSPL-1.0
rqliteSomente rede❌ Banco de dados relacionalMIT
dqliteNão testado e ainda sem suporte?Não testado e ainda sem suporte?LGPL-3.0-only
PostgreSQLsim❌ Banco de dados relacionalPostgreSQL (igual a BSD ou MIT)
Maria DBApenas para InnoDB❌ Banco de dados relacionalGPLv2 e BUSL-1.1
BarataDBRecurso exclusivo para empresas❌ Banco de dados relacionalBUSL-1.1 e outros

Aqui está um postagem no blog que compara várias opções de armazenamento de banco de dados SQLite na tabela acima.

Segurança

Em todos os momentos usamos criptografia em repouso (AES-256), criptografia em trânsito (TLS), DNS sobre HTTPS ("DoH") usando 🍊 tangerina, e sqleet (ChaCha20-Poly1305) criptografia em caixas de correio. Além disso, usamos autenticação de dois fatores baseada em token (em oposição ao SMS, que é suspeito de ataques man-in-the-middle), chaves SSH rotacionadas com acesso root desabilitado, acesso exclusivo a servidores por meio de endereços IP restritos e muito mais.

No caso de um ataque de empregada malvada ou funcionário desonesto de um fornecedor terceirizado, sua caixa de correio ainda só pode ser aberta com sua senha gerada. Fique tranquilo, não contamos com nenhum fornecedor terceirizado além de nossos fornecedores de servidores de reclamação SOC Tipo 2 da Cloudflare, Digital Ocean e Vultr.

Nosso objetivo é ter o mínimo ponto único de falhas que possível.

Caixas de correio

tldr; Nossos servidores IMAP usam bancos de dados SQLite criptografados individualmente para cada uma de suas caixas de correio.

SQLite é extremamente popular banco de dados incorporado – atualmente em execução no seu telefone e computador – e usado por quase todas as principais tecnologias.

Por exemplo, em nossos servidores criptografados existe uma caixa de correio de banco de dados SQLite para linux@example.com, info@example.com, hello@example.com e assim por diante – um para cada como um .sqlite arquivo de banco de dados. Também não nomeamos os arquivos de banco de dados com o endereço de e-mail - em vez disso, usamos BSON ObjectID e UUIDs exclusivos gerados que não compartilham a quem a caixa de correio pertence ou em qual endereço de e-mail ela está (por exemplo, 353a03f21e534321f5d6e267.sqlite).

Cada um desses bancos de dados é criptografado usando sua senha (que só você tem) usando sqleet (ChaCha20-Poly1305). Isso significa que suas caixas de correio são criptografadas individualmente, independentes e em área restritae portátil.

Ajustamos o SQLite com o seguinte PRAGMA:

PRAGMAPropósito
cipher=chacha20Criptografia de banco de dados SQLite ChaCha20-Poly1305. Referência better-sqlite3-multiple-ciphers sob Projetos para mais insights.
key="****************"Esta é a sua senha descriptografada apenas na memória, que é transmitida através da conexão IMAP do seu cliente de e-mail para o nosso servidor. Novas instâncias de banco de dados são criadas e fechadas para cada sessão de leitura e gravação (para garantir sandbox e isolamento).
journal_model=WALRegistro de gravação antecipada ("WAL") que aumenta o desempenho e permite acesso de leitura simultâneo.
busy_timeout=5000Evita erros de bloqueio de gravação enquanto outras gravações estão ocorrendo.
synchronous=NORMALAumenta a durabilidade das transações sem risco de corrupção de dados.
foreign_keys=ONImpõe que as referências de chave estrangeira (por exemplo, uma relação de uma tabela para outra) sejam aplicadas. Por padrão, isso não está ativado no SQLite, mas para validação e integridade de dados ele deve estar habilitado.
encoding='UTF-8'Codificação padrão usar para garantir a sanidade do desenvolvedor.

Todos os outros padrões são do SQLite conforme especificado no documentação oficial PRAGMA.

Simultaneidade

tldr; Nós usamos rclone e WebSocket para leituras e gravações simultâneas em suas caixas de correio SQLite criptografadas.

Seu cliente de e-mail no seu telefone pode resolver imap.forwardemail.net para um de nossos endereços IP da Digital Ocean – e seu cliente de desktop pode resolver um IP separado de um diferente fornecedor completamente.

Independentemente do servidor IMAP ao qual seu cliente de e-mail se conecta, queremos que a conexão leia seu banco de dados em tempo real com 100% de precisão:

  • Isto é conseguido usando rclone com --vfs-cache-mode off (o padrão).

  • Em vez de usar o cache de disco local, o cache é lido diretamente da montagem remota (seu banco de dados) em tempo real.

  • Caso o arquivo local não possa ser encontrado, isso indica que rclone falhou ao montar ou tem um problema. Neste caso usamos um WebSocket fallback para leituras (que diminui ligeiramente o desempenho, mas ainda mantém a integridade do serviço).

  • Cada um de nossos servidores é configurado para ser montado com consistência e nos alerta em tempo real sobre quaisquer erros.

Escreve

Escrever em seu banco de dados é um pouco diferente – já que SQLite é um banco de dados incorporado e sua caixa de correio reside em um único arquivo por padrão.

Tínhamos explorado opções como litestream, rqlite, e dqlite abaixo – no entanto, nenhum deles satisfez nossos requisitos.

Para realizar gravações com registro write-ahead ("WAL") habilitado – precisamos garantir que apenas um servidor ("Primário") seja responsável por fazer isso. WAL acelera drasticamente a simultaneidade e permite um escritor e vários leitores.

O Primário está em execução nos servidores de dados com os volumes montados contendo as caixas de correio criptografadas. Do ponto de vista da distribuição, você poderia considerar todos os servidores IMAP individuais por trás imap.forwardemail.net ser servidores secundários (“Secundários”).

Realizamos comunicação bidirecional com WebSockets:

  • Os servidores primários usam uma instância de esde WebSocketServer servidor.
  • Servidores secundários usam uma instância de esde WebSocket cliente que está envolvido com websocket conforme prometido e reconectando-websocket. Esses dois invólucros garantem que o WebSocket reconecta e pode enviar e receber dados para gravações específicas do banco de dados.

Cópias de segurança

tldr; Os backups de suas caixas de correio criptografadas são feitos diariamente. Você também pode solicitar instantaneamente um novo backup ou baixar o backup mais recente a qualquer momento em Minha conta Domínios Apelido.

Para backups, simplesmente executamos o SQLite VACUUM INTO comando todos os dias durante o processamento do comando IMAP, que aproveita sua senha criptografada de uma conexão IMAP na memória. Os backups são armazenados se nenhum backup existente for detectado ou se o SHA-256 hash mudou no arquivo em comparação com o backup mais recente.

Observe que usamos o VACUUM INTO comando em oposição ao embutido backup comando porque se uma página for modificada durante um backup operação de comando, então ele tem que começar de novo. O VACUUM INTO O comando tirará um instantâneo. Veja esses comentários em GitHub e Notícias sobre hackers para mais insights.

Além disso usamos VACUUM INTO em oposição a backup, porque o backup comando deixaria o banco de dados sem criptografia por um breve período até rekey é invocado (veja este GitHub Comente para obter insights).

O Secundário instruirá o Primário sobre o WebSocket conexão para executar o backup – e o Primário receberá então o comando para fazê-lo e posteriormente:

  1. Conecte-se à sua caixa de correio criptografada.
  2. Adquira um bloqueio de gravação.
  3. Execute um ponto de verificação WAL via wal_checkpoint(PASSIVE).
  4. Execute o VACUUM INTO Comando SQLite.
  5. Certifique-se de que o arquivo copiado possa ser aberto com a senha criptografada (salvaguarda/dummyproofing).
  6. Faça upload para Cloudflare R2 para armazenamento (ou para seu próprio provedor, se especificado).
  7. Compacte o arquivo de backup resultante com gzip.
  8. Faça upload para Cloudflare R2 para armazenamento (ou para seu próprio provedor, se especificado).

Lembre-se de que suas caixas de correio são criptografadas – e embora tenhamos restrições de IP e outras medidas de autenticação em vigor para comunicação WebSocket – no caso de um malfeitor, você pode ter certeza de que, a menos que a carga útil do WebSocket tenha sua senha IMAP, ela não poderá abrir seu banco de dados .

No momento, apenas um backup é armazenado por caixa de correio, mas no futuro poderemos oferecer recuperação pontual ("PITR").

Nossos servidores IMAP suportam o SEARCH comando com consultas complexas, expressões regulares e muito mais.

O desempenho rápido da pesquisa se deve a FTS5 e sqlite-regex.

nós armazenamos Date valores nas caixas de correio SQLite como ISO 8601 cordas via Date.prototype.toISOString (com fuso horário UTC para que as comparações de igualdade funcionem corretamente).

Os índices também são armazenados para todas as propriedades que estão nas consultas de pesquisa.

Projetos

Aqui está uma tabela que descreve os projetos que usamos em nosso código-fonte e processo de desenvolvimento (classificados em ordem alfabética):

ProjetoPropósito
AnsiblePlataforma de automação DevOps para manter, dimensionar e gerenciar toda a nossa frota de servidores com facilidade.
BreeAgendador de tarefas para Node.js e JavaScript com cron, datas, ms, posterior e suporte amigável.
CabineBiblioteca de registro JavaScript e Node.js amigável ao desenvolvedor com segurança e privacidade em mente.
DeixeiEstrutura Node.js que potencializa toda a nossa arquitetura e design de engenharia com MVC e muito mais.
MongoDBSolução de banco de dados NoSQL que usamos para armazenar todos os outros dados fora das caixas de correio (por exemplo, sua conta, configurações, domínios e configurações de alias).
MangustoModelagem de documento de objeto MongoDB ("ODM") que usamos em toda a nossa pilha. Escrevemos ajudantes especiais que nos permitem simplesmente continuar usando Mangusto com SQLite 🎉
Node.jsNode.js é o ambiente de tempo de execução JavaScript de plataforma cruzada e código aberto que executa todos os nossos processos de servidor.
Envio de notasPacote Node.js para envio de e-mails, criação de conexões e muito mais. Somos patrocinadores oficiais deste projeto.
RedisBanco de dados na memória para armazenamento em cache, canais de publicação/assinatura e solicitações de DNS sobre HTTPS.
SQLite3MúltiplasCifrasExtensão de criptografia para SQLite para permitir que arquivos inteiros do banco de dados sejam criptografados (incluindo o log write-ahead ("WAL"), diário, reversão, …).
SQLiteStudioEditor Visual SQLite (que você também pode usar) para testar, baixar e visualizar caixas de correio de desenvolvimento.
SQLiteCamada de banco de dados incorporada para armazenamento IMAP escalonável, independente, rápido e resiliente.
Verificador de spamFerramenta Node.js anti-spam, filtragem de e-mail e prevenção de phishing (nossa alternativa para Assassino de Spam e rspamd).
tangerinaSolicitações de DNS sobre HTTPS com Node.js e cache usando Redis – o que garante consistência global e muito mais.
Pássaro TrovãoNossa equipe de desenvolvimento usa isso (e também recomenda) como o cliente de e-mail preferido para usar com Forward Email.
UTMNossa equipe de desenvolvimento utiliza isso para criar máquinas virtuais para iOS e macOS para testar diferentes clientes de e-mail (em paralelo) com nossos servidores IMAP e SMTP.
UbuntuSistema operacional de servidor moderno baseado em Linux de código aberto que alimenta toda a nossa infraestrutura.
Pato selvagemBiblioteca do servidor IMAP – veja suas notas em desduplicação de anexo e Suporte ao protocolo IMAP.
melhor-sqlite3-cifras múltiplasBiblioteca API rápida e simples para Node.js interagir com SQLite3 programaticamente.
modelos de e-mailEstrutura de e-mail amigável ao desenvolvedor para criar, visualizar e enviar e-mails personalizados (por exemplo, notificações de conta e muito mais).
json-sqlConstrutor de consultas SQL usando sintaxe estilo Mongo. Isso economiza tempo da nossa equipe de desenvolvimento, pois podemos continuar escrevendo no estilo Mongo em toda a pilha com uma abordagem independente de banco de dados. Também ajuda a evitar ataques de injeção de SQL usando parâmetros de consulta.
inspetor de esquema knexUtilitário SQL para extrair informações sobre o esquema de banco de dados existente. Isso nos permite validar facilmente se todos os índices, tabelas, colunas, restrições e muito mais são válidos e estão 1:1 com como deveriam ser. Nós até escrevemos auxiliares automatizados para adicionar novas colunas e índices se forem feitas alterações nos esquemas do banco de dados (com alertas de erros extremamente detalhados também).
knexConstrutor de consultas SQL que usamos apenas para migrações de banco de dados e validação de esquema por meio de knex-schema-inspector.
mandarimAutomático i18n tradução de frases com suporte para Markdown usando API de tradução do Google Cloud.
mx-conectarPacote Node.js para resolver e estabelecer conexões com servidores MX e lidar com erros.
pm2Gerenciador de processo de produção Node.js com balanceador de carga integrado (ajustado para desempenho).
servidor smtpBiblioteca de servidores SMTP – usamos isso para nossos servidores de troca de correio ("MX") e servidores SMTP de saída.
ImapTestFerramenta útil para testar servidores IMAP em relação a benchmarks e compatibilidade de protocolo IMAP com especificação RFC. Este projeto foi criado pela Pombal team (um servidor IMAP e POP3 de código aberto ativo desde julho de 2002). Testamos extensivamente nosso servidor IMAP com esta ferramenta.

Você pode encontrar outros projetos que usamos em nosso código fonte no GitHub.

Provedores

FornecedorPropósito
nuvemflareProvedor de DNS, verificações de integridade, balanceadores de carga e armazenamento de backup usando Cloudflare R2.
Oceano DigitalHospedagem de servidor dedicado, armazenamento em bloco SSD e bancos de dados gerenciados.
VultrHospedagem de servidor dedicado e armazenamento em bloco SSD.

Pensamentos

Princípios

O encaminhamento de e-mail é projetado de acordo com estes princípios:

  1. Seja sempre amigável ao desenvolvedor, focado na segurança e na privacidade e transparente.
  2. Aderir a MVC, Unix, KISS, DRY, YAGNI, Doze Fatores, Navalha de Occam, e alimentação para cães
  3. Direcione o fragmentado, inicializado e ramen lucrativo desenvolvedor

Experimentos

tldr; Em última análise, o uso de armazenamento de objetos compatível com S3 e/ou tabelas virtuais não é tecnicamente viável por motivos de desempenho e está sujeito a erros devido a limitações de memória.

Fizemos alguns experimentos que levaram à nossa solução SQLite final, conforme discutido acima.

Uma delas foi tentar usar clone e SQLite junto com uma camada de armazenamento compatível com S3.

Esse experimento nos levou a entender melhor e descobrir casos extremos em torno de rclone, SQLite e VFS uso:

  • Se você ativar --vfs-cache-mode writes sinalizar com rclone, então as leituras serão OK, porém as gravações serão armazenadas em cache.
    • Se você tiver vários servidores IMAP distribuídos globalmente, o cache estará desativado entre eles, a menos que você tenha um único gravador e vários ouvintes (por exemplo, uma abordagem pub/sub).
    • Isso é incrivelmente complexo e adicionar qualquer complexidade adicional como essa resultará em mais pontos únicos de falha.
    • Os provedores de armazenamento compatíveis com S3 não suportam alterações parciais de arquivos – o que significa qualquer alteração do .sqlite arquivo resultará em uma alteração completa e reenvio do banco de dados.
    • Outras soluções como rsync existem, mas eles não estão focados em write-ahead-log ("WAL") suporte – então acabamos analisando o Litestream. Felizmente, nosso uso de criptografia já criptografa o WAL arquivos para nós, então não precisamos depender do Litestream para isso. No entanto, ainda não estávamos confiantes no Litestream para uso em produção e temos algumas notas abaixo sobre isso.
    • Usando esta opção de --vfs-cache-mode writes (o apenas maneira de usar o SQLite rclone para gravações) tentará copiar todo o banco de dados do zero na memória – lidar com uma caixa de correio de 10 GB é aceitável, no entanto, lidar com várias caixas de correio com armazenamento excessivamente alto fará com que os servidores IMAP tenham limitações de memória e ENOMEM erros, falhas de segmentação e corrupção de dados.
  • Se você tentar usar SQLite Mesas Virtuais (por exemplo, usando s3db) para ter os dados ativos em uma camada de armazenamento compatível com S3, você enfrentará vários outros problemas:
    • A leitura e a gravação serão extremamente lentas, pois os endpoints da API S3 precisarão ser atingidos com HTTP GET, PUT, HEAD, e POST métodos.
    • Os testes de desenvolvimento mostraram que exceder 500 mil a mais de 1 milhão de registros na Internet de fibra ainda é limitado pela taxa de transferência de gravação e leitura para provedores compatíveis com S3. Por exemplo, nossos desenvolvedores executaram for loops para fazer ambos SQL sequencial INSERT declarações e aquelas que gravaram grandes quantidades de dados em massa. Em ambos os casos, o desempenho foi surpreendentemente lento.
    • Mesas virtuais não pode ter índices, ALTER TABLE declarações, e outro limitações – o que leva a atrasos de mais de 1-2 minutos ou mais, dependendo da quantidade de dados.
    • Os objetos foram armazenados sem criptografia e nenhum suporte de criptografia nativa está prontamente disponível.
  • Também exploramos usando sqlite-s3vfs que é conceitual e tecnicamente semelhante ao ponto anterior (portanto, tem os mesmos problemas). Uma possibilidade seria usar um costume sqlite3 compilação envolvida com criptografia, como wxSQLite3 (que usamos atualmente em nossa solução acima) por meio editando o arquivo de configuração.
  • Outra abordagem potencial seria usar o extensão multiplexada, no entanto, isso tem uma limitação de 32 GB e exigiria dores de cabeça complexas de construção e desenvolvimento.
  • ALTER TABLE são necessárias (portanto, isso exclui completamente o uso de tabelas virtuais). Nós precisamos ALTER TABLE declarações para que nosso gancho com knex-schema-inspector funcione corretamente – o que garante que os dados não sejam corrompidos e que as linhas recuperadas possam ser convertidas em documentos válidos de acordo com nossos mongoose definições de esquema (que incluem restrição, tipo de variável e validação de dados arbitrária).
  • Quase todos os projetos compatíveis com S3 relacionados ao SQLite na comunidade de código aberto estão em Python (e não em JavaScript que usamos em 100% de nossa pilha).
  • Bibliotecas de compactação como sqlite-zstd (ver comentários) parecem promissores, mas pode ainda não estar pronto para uso em produção. Em vez disso, compactação do lado do aplicativo em tipos de dados como String, Object, Map, Array, Set, e Buffer será uma abordagem mais limpa e fácil (e também é mais fácil de migrar, já que poderíamos armazenar um Boolean sinalizador ou coluna – ou até mesmo usar PRAGMA user_version=1 para compressão ou user_version=0 para nenhuma compactação como metadados do banco de dados).
    • Felizmente já temos a desduplicação de anexos implementada no armazenamento do nosso servidor IMAP – portanto, cada mensagem com o mesmo anexo não manterá uma cópia do anexo – em vez disso, um único anexo é armazenado para múltiplas mensagens e threads em uma caixa de correio (e um estrangeiro). referência é usada posteriormente).
  • O projeto Litestream, que é uma solução de replicação e backup SQLite, é muito promissor e provavelmente o utilizaremos no futuro.
  • A restauração de backup precisa ser simples e trivial. Usando uma solução como MongoDB com mongodump e mongoexport não é apenas tedioso, mas também demorado e tem complexidade de configuração.
    • Os bancos de dados SQLite simplificam (é um único arquivo).
    • Queríamos projetar uma solução onde os usuários pudessem pegar sua caixa de correio e sair a qualquer momento.
      • Comandos simples do Node.js para fs.unlink('mailbox.sqlite')) e é permanentemente apagado do armazenamento em disco.
      • Da mesma forma, podemos usar uma API compatível com S3 com HTTP DELETE para remover facilmente instantâneos e backups dos usuários.
    • SQLite foi a solução mais simples, rápida e econômica.

Falta de alternativas

Até onde sabemos, nenhum outro serviço de e-mail foi projetado dessa forma nem é de código aberto.

Nós acho que isso pode ser devido aos serviços de e-mail existentes com tecnologia legada em produção com código espaguete 🍝.

A maioria, senão todos, dos provedores de serviços de e-mail existentes são de código fechado ou anunciam como código aberto, mas na realidade apenas o seu front-end é de código aberto.

A parte mais sensível do e-mail (a interação real de armazenamento/IMAP/SMTP) tudo é feito no back-end (servidor) e não no front-end (cliente).

Experimente encaminhar e-mail

Inscreva-se hoje em https://forwardemail.net! 🚀