Análisis profundo: cómo utilizamos buzones de correo SQLite cifrados con seguridad cuántica para nuestro servicio de correo electrónico seguro y centrado en la privacidad

A diferencia de otros servicios de correo electrónico , nos aseguramos de que solo usted tenga acceso a su buzón en todo momento.

Prefacio

tldr; Nuestro servicio de correo electrónico es 100% de código abierto y centrado en la privacidad a través de buzones de correo SQLite seguros y cifrados.

Hasta que lanzamos Soporte IMAP, utilizamos MongoDB para nuestras necesidades de almacenamiento de datos persistentes.

Esta tecnología es asombrosa y todavía la usamos hoy en día, pero para tener cifrado en reposo con MongoDB es necesario utilizar un proveedor que ofrezca MongoDB Enterprise, como Digital Ocean o Mongo Atlas, o pagar por una licencia empresarial (y posteriormente tendrá que trabajar con el equipo de ventas (latencia).

Nuestro equipo en Redirigir correo Necesitaba una solución de almacenamiento cifrada, confiable, escalable y fácil de usar para desarrolladores para buzones de correo IMAP. Como desarrolladores de código abierto, usar una tecnología que requiere pagar una tarifa de licencia para obtener la función de cifrado en reposo estaba en contra. nuestros principios – y entonces experimentamos, investigamos y desarrollamos una nueva solución desde cero para resolver estas necesidades.

En lugar de utilizar una base de datos compartida para almacenar sus buzones de correo, los almacenamos y encriptamos individualmente con su contraseña (que solo usted tiene). Nuestro servicio de correo electrónico es tan seguro que si olvida su contraseña, perderá su buzón (y necesita recuperarse con copias de seguridad fuera de línea o comenzar de nuevo).

Continúe leyendo mientras profundizamos a continuación con un comparación de proveedores de servicios de correo electrónico, Cómo funciona nuestro servicio, nuestra pila de tecnología, y más.

Comparación de proveedores de servicios de correo electrónico

Somos el único proveedor de servicios de correo electrónico 100% de código abierto y centrado en la privacidad que almacena buzones de correo SQLite cifrados individualmente, ofrece dominios, alias y usuarios ilimitados, y admite SMTP, IMAP y POP3 salientes:

A diferencia de otros proveedores de correo electrónico, no necesita pagar por el almacenamiento por dominio o alias con Forward Email. El almacenamiento se comparte en toda su cuenta, por lo que si tiene varios nombres de dominio personalizados y varios alias en cada uno, entonces somos la solución perfecta para usted. Tenga en cuenta que aún puede aplicar límites de almacenamiento si lo desea por dominio o alias.

Leer comparación de servicios de correo electrónico

Como funciona

  1. Usando su cliente de correo electrónico como Apple Mail, Thunderbird, Gmail o Outlook, se conecta a nuestro sitio seguro IMAP servidores usando su nombre de usuario y contraseña:

    • Su nombre de usuario es su alias completo con su dominio, como hello@example.com.
    • Su contraseña se genera aleatoriamente y solo se le muestra durante 30 segundos cuando hace clic Generar contraseña de Mi cuenta Dominios Alias.
  2. Una vez conectado, su cliente de correo electrónico le enviará Comandos del protocolo IMAP a nuestro servidor IMAP para mantener su buzón sincronizado. Esto incluye escribir y almacenar borradores de correos electrónicos y otras acciones que pueda realizar (por ejemplo, etiquetar un correo electrónico como Importante o marcar un correo electrónico como Spam/Correo no deseado).

  3. Los servidores de intercambio de correo (comúnmente conocidos como servidores "MX") reciben nuevos correos electrónicos entrantes y los almacenan en su buzón. Cuando esto suceda, su cliente de correo electrónico recibirá una notificación y sincronizará su buzón. Nuestros servidores de intercambio de correo pueden reenviar su correo electrónico a uno o más destinatarios (incluido ganchos web), almacenar su correo electrónico en su almacenamiento IMAP cifrado con nosotros, o ambos!

    ¿Interesado en aprender más? Leer cómo configurar el reenvío de correo electrónico, cómo funciona nuestro servicio de intercambio de correo, o ver nuestros guías.

  4. Detrás de escena, nuestro diseño de almacenamiento seguro de correo electrónico funciona de dos maneras para mantener sus buzones de correo encriptados y solo usted pueda acceder a ellos:

    • Cuando se recibe correo nuevo de un remitente, nuestros servidores de intercambio de correo escriben en un buzón individual, temporal y cifrado para usted.

      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!
      
    • Cuando se conecta a nuestro servidor IMAP con su cliente de correo electrónico, su contraseña se cifra en la memoria y se utiliza para leer y escribir en su buzón. Sólo se puede leer y escribir en su buzón con esta contraseña. Ten en cuenta que como eres el único que tiene esta contraseña, sólo tu Puede leer y escribir en su buzón cuando accede a él. La próxima vez que su cliente de correo electrónico intente buscar correo o sincronizaciones, sus nuevos mensajes se transferirán desde este buzón temporal y se almacenarán en el archivo de su buzón real utilizando la contraseña proporcionada. Tenga en cuenta que este buzón temporal se purga y elimina posteriormente para que solo su buzón protegido con contraseña tenga los mensajes.

    • Si está conectado a IMAP (por ejemplo, utilizando un cliente de correo electrónico como Apple Mail o Thunderbird), no necesitamos escribir en el almacenamiento temporal del disco. En su lugar, se recupera y utiliza su contraseña IMAP cifrada en la memoria. En tiempo real, cuando se intenta entregarle un mensaje, enviamos una solicitud WebSocket a todos los servidores IMAP preguntándoles si tienen una sesión activa para usted (esta es la parte de recuperación) y luego la transmitimos. Contraseña cifrada en memoria: por lo que no necesitamos escribir en un buzón temporal, podemos escribir en su buzón cifrado real utilizando su contraseña cifrada.

      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. Copias de seguridad de sus buzones de correo cifrados se hacen diariamente. También puede solicitar una nueva copia de seguridad en cualquier momento o descargar la última copia de seguridad desde Mi cuenta Dominios Alias. Si decide cambiar a otro servicio de correo electrónico, podrá migrar, descargar, exportar y eliminar fácilmente sus buzones de correo y copias de seguridad en cualquier momento.

Tecnologías

Bases de datos

Exploramos otras posibles capas de almacenamiento de bases de datos, sin embargo, ninguna satisfizo nuestros requisitos tanto como SQLite:

Base de datosCifrado en reposoEn zona protegida BuzonesLicenciaUsado en todas partes
SQLite✅ Sí con SQLite3Múltiples cifrados✅ Dominio Público
MongoDB"Disponible sólo en MongoDB Enterprise"❌ Base de datos relacional❌AGPL y SSPL-1.0
rqlitaSólo red❌ Base de datos relacionalMIT
dqlite¿No ha sido probado y aún no es compatible?¿No ha sido probado y aún no es compatible?LGPL-3.0-only
PostgreSQLsi❌ Base de datos relacionalPostgreSQL (Similar a BSD o MIT)
mariadbSólo para InnoDB❌ Base de datos relacionalGPLv2 y BUSL-1.1
CucarachaDBFunción exclusiva para empresas❌ Base de datos relacionalBUSL-1.1 y otros

Aquí hay un publicación de blog que compara varias opciones de almacenamiento de bases de datos SQLite en la tabla de arriba.

Seguridad

En todo momento utilizamos cifrado en reposo (AES-256), cifrado en tránsito (TLS), DNS sobre HTTPS ("DoH") usando 🍊 Mandarina, y cuadrilátero (ChaCha20-Poly1305) cifrado en buzones de correo. Además, utilizamos autenticación de dos factores basada en tokens (a diferencia de SMS, que se sospecha que ataques de hombre en el medio), claves SSH rotadas con acceso raíz deshabilitado, acceso exclusivo a servidores a través de direcciones IP restringidas y más.

En caso de un ataque de sirvienta malvada o empleado deshonesto de un proveedor externo, su buzón de correo solo se puede abrir con su contraseña generada. Tenga la seguridad de que no dependemos de ningún proveedor externo que no sea nuestro proveedor de servidores de quejas SOC Tipo 2 de Cloudflare, Digital Ocean y Vultr.

Nuestro objetivo es tener el menor número punto único de fallas como sea posible.

Buzones

tldr; Nuestros servidores IMAP utilizan bases de datos SQLite cifradas individualmente para cada uno de sus buzones de correo.

SQLite es un extremadamente popular base de datos integrada (actualmente se está ejecutando en su teléfono y computadora) y utilizado por casi todas las tecnologías principales.

Por ejemplo, en nuestros servidores cifrados hay un buzón de base de datos SQLite para linux@example.com, info@example.com, hello@example.com y así sucesivamente, uno para cada uno como .sqlite archivo de base de datos. Tampoco nombramos los archivos de la base de datos con la dirección de correo electrónico; en su lugar, utilizamos BSON ObjectID y UUID únicos generados que no comparten a quién pertenece el buzón ni en qué dirección de correo electrónico se encuentra (p. ej. 353a03f21e534321f5d6e267.sqlite).

Cada una de estas bases de datos está encriptada usando su contraseña (que solo usted tiene) usando cuadrilátero (ChaCha20-Poly1305). Esto significa que sus buzones de correo están cifrados individualmente, son autónomos, en la zona de arenay portátil.

Hemos ajustado SQLite con lo siguiente PRAGMA:

PRAGMAObjetivo
cipher=chacha20Cifrado de base de datos SQLite ChaCha20-Poly1305. Referencia better-sqlite3-multiple-ciphers bajo Proyectos para obtener más información.
key="****************"Esta es su contraseña descifrada únicamente en memoria que se transmite a través de la conexión IMAP de su cliente de correo electrónico a nuestro servidor. Se crean y cierran nuevas instancias de bases de datos para cada sesión de lectura y escritura (para garantizar el aislamiento y la zona de pruebas).
journal_model=WALRegistro de escritura anticipada ("WAL") lo que aumenta el rendimiento y permite el acceso de lectura concurrente.
busy_timeout=5000Previene errores de bloqueo de escritura mientras se realizan otras escrituras.
synchronous=NORMALAumenta la durabilidad de las transacciones. sin riesgo de corrupción de datos.
foreign_keys=ONHace cumplir que se apliquen las referencias de clave externa (por ejemplo, una relación de una tabla a otra). Por defecto esto no está activado en SQLite, pero para la validación y la integridad de los datos debe estar habilitado.
encoding='UTF-8'Codificación predeterminada utilizar para garantizar la cordura del desarrollador.

Todos los demás valores predeterminados son de SQLite como se especifica en el documentación oficial de PRAGMA.

concurrencia

tldr; Usamos rclone y WebSocket para lecturas y escrituras simultáneas en sus buzones de correo SQLite cifrados.

Lee

El cliente de correo electrónico de tu teléfono puede resolver imap.forwardemail.net a una de nuestras direcciones IP de Digital Ocean, y su cliente de escritorio puede resolver una IP separada desde una diferente proveedor en total.

Independientemente del servidor IMAP al que se conecte su cliente de correo electrónico, queremos que la conexión lea desde su base de datos en tiempo real con 100% de precisión:

  • Esto se logra utilizando rclone con --vfs-cache-mode off (el valor por defecto).

  • En lugar de utilizar la memoria caché del disco local, la memoria caché se lee directamente desde el montaje remoto (su base de datos) en tiempo real.

  • En el caso de que no se pueda encontrar el archivo local, esto indica que rclone No se pudo montar o tiene un problema. En este caso utilizamos un WebSocket respaldo para lecturas (que disminuye ligeramente el rendimiento, pero aún mantiene la integridad del servicio).

  • Cada uno de nuestros servidores está configurado para montarse con coherencia y nos alerta en tiempo real sobre cualquier error.

escribe

Escribir en su base de datos es un poco diferente, ya que SQLite es una base de datos integrada y su buzón de correo se encuentra en un solo archivo de forma predeterminada.

Habíamos explorado opciones como litestream, rqlite, y dqlite a continuación; sin embargo, ninguno de estos satisfizo nuestros requisitos.

Para realizar escrituras con registro de escritura anticipada ("WAL") habilitado: debemos asegurarnos de que solo un servidor ("Primario") sea responsable de hacerlo. WAL acelera drásticamente la concurrencia y permite un escritor y varios lectores.

El primario se ejecuta en los servidores de datos con los volúmenes montados que contienen los buzones de correo cifrados. Desde el punto de vista de la distribución, podría considerar todos los servidores IMAP individuales detrás imap.forwardemail.net ser servidores secundarios ("Secundarios").

Logramos comunicación bidireccional con WebSockets:

  • Los servidores primarios utilizan una instancia de ws's WebSocketServer servidor.
  • Los servidores secundarios utilizan una instancia de ws's WebSocket cliente que está envuelto con websocket-según-lo-prometido y reconexión-websocket. Estos dos envoltorios aseguran que el WebSocket se vuelve a conectar y puede enviar y recibir datos para escrituras de bases de datos específicas.

Copias de seguridad

tldr; Diariamente se realizan copias de seguridad de sus buzones de correo cifrados. También puede solicitar instantáneamente una nueva copia de seguridad o descargar la última copia de seguridad en cualquier momento desde Mi cuenta Dominios Alias.

Para copias de seguridad, simplemente ejecutamos SQLite VACUUM INTO comando todos los días durante el procesamiento del comando IMAP, que aprovecha su contraseña cifrada desde una conexión IMAP en memoria. Las copias de seguridad se almacenan si no se detecta ninguna copia de seguridad existente o si el SHA-256 El hash ha cambiado en el archivo en comparación con la copia de seguridad más reciente.

Tenga en cuenta que usamos el VACUUM INTO comando en lugar del incorporado backup comando porque si una página se modifica durante un backup operación de comando, entonces tiene que empezar de nuevo. El VACUUM INTO El comando tomará una instantánea. Vea estos comentarios en GitHub y Noticias de piratas informáticos para obtener más información.

Además utilizamos VACUUM INTO Opuesto a backup, porque el backup El comando dejaría la base de datos sin cifrar durante un breve período hasta que rekey se invoca (ver este GitHub comentario para obtener información).

La Secundaria instruirá a la Primaria sobre el WebSocket conexión para ejecutar la copia de seguridad, y el Primario recibirá el comando para hacerlo y posteriormente:

  1. Conéctese a su buzón de correo cifrado.
  2. Adquirir un bloqueo de escritura.
  3. Ejecute un punto de control WAL a través de wal_checkpoint(PASSIVE).
  4. Ejecute el VACUUM INTO Comando SQLite.
  5. Asegúrese de que el archivo copiado se pueda abrir con la contraseña cifrada (protección/protección falsa).
  6. Cárguelo en Cloudflare R2 para almacenamiento (o en su propio proveedor, si se especifica).
  7. Comprima el archivo de copia de seguridad resultante con gzip.
  8. Cárguelo en Cloudflare R2 para almacenamiento (o en su propio proveedor, si se especifica).

Recuerde que sus buzones de correo están encriptados (y si bien contamos con restricciones de IP y otras medidas de autenticación para la comunicación WebSocket), en caso de un mal actor, puede estar seguro de que, a menos que la carga útil de WebSocket tenga su contraseña IMAP, no podrá abrir su base de datos. .

En este momento, solo se almacena una copia de seguridad por buzón, pero en el futuro podremos ofrecer recuperación en un momento determinado ("PITR").

Nuestros servidores IMAP soportan la SEARCH comando con consultas complejas, expresiones regulares y más.

El rápido rendimiento de búsqueda se debe a FTS5 y expresiones regulares sqlite.

nosotros almacenamos Date valores en los buzones de correo de SQLite como ISO 8601 cuerdas a través de Date.prototype.toISOString (con zona horaria UTC para que las comparaciones de igualdad funcionen correctamente).

Los índices también se almacenan para todas las propiedades que se encuentran en las consultas de búsqueda.

Proyectos

Aquí hay una tabla que describe los proyectos que utilizamos en nuestro código fuente y proceso de desarrollo (ordenados alfabéticamente):

ProyectoObjetivo
ansiblePlataforma de automatización DevOps para mantener, escalar y administrar toda nuestra flota de servidores con facilidad.
breeProgramador de trabajos para Node.js y JavaScript con cron, fechas, ms, más tarde y soporte amigable para los humanos.
CabinaBiblioteca de registro de JavaScript y Node.js fácil de usar para desarrolladores que tiene en cuenta la seguridad y la privacidad.
DejarMarco Node.js que impulsa toda nuestra arquitectura y diseño de ingeniería con MVC y más.
MongoDBSolución de base de datos NoSQL que utilizamos para almacenar todos los demás datos fuera de los buzones de correo (por ejemplo, su cuenta, configuración, dominios y configuraciones de alias).
MangostaModelado de documentos de objetos de MongoDB ("ODM") que utilizamos en toda nuestra pila. Escribimos ayudantes especiales que nos permiten simplemente continuar usando Mangosta con SQLite 🎉
Nodo.jsNode.js es el entorno de ejecución de JavaScript multiplataforma y de código abierto que ejecuta todos los procesos de nuestro servidor.
Nota de correoPaquete Node.js para enviar correos electrónicos, crear conexiones y más. Somos patrocinador oficial de este proyecto.
RedisBase de datos en memoria para almacenamiento en caché, canales de publicación/suscripción y solicitudes DNS sobre HTTPS.
SQLite3Múltiples cifradosExtensión de cifrado para SQLite que permite cifrar archivos completos de bases de datos (incluido el registro de escritura anticipada ("WAL"), diario, reversión, …).
SQLiteStudioEditor visual SQLite (que también puede utilizar) para probar, descargar y ver buzones de correo de desarrollo.
SQLiteCapa de base de datos integrada para almacenamiento IMAP escalable, autónomo, rápido y resistente.
Escáner de spamLa herramienta antispam, filtrado de correo electrónico y prevención de phishing de Node.js (nuestra alternativa a Asesino de spam y rspamd).
MandarinaSolicitudes DNS sobre HTTPS con Node.js y almacenamiento en caché con Redis, lo que garantiza coherencia global y mucho más.
pájaro truenoNuestro equipo de desarrollo utiliza esto (y también lo recomienda) como el cliente de correo electrónico preferido para usar con Reenviar correo electrónico.
UTMNuestro equipo de desarrollo utiliza esta creación de máquinas virtuales para iOS y macOS para probar diferentes clientes de correo electrónico (en paralelo) con nuestros servidores IMAP y SMTP.
ubuntuModerno sistema operativo de servidor de código abierto basado en Linux que impulsa toda nuestra infraestructura.
Pato salvajeBiblioteca del servidor IMAP: consulte sus notas en deduplicación de archivos adjuntos y Soporte de protocolo IMAP.
mejor-sqlite3-múltiples-cifradosBiblioteca API rápida y sencilla para que Node.js interactúe con SQLite3 mediante programación.
Plantillas de correo electrónicoMarco de correo electrónico fácil de desarrollar para crear, obtener una vista previa y enviar correos electrónicos personalizados (por ejemplo, notificaciones de cuentas y más).
json-sqlGenerador de consultas SQL que utiliza sintaxis estilo Mongo. Esto le ahorra tiempo a nuestro equipo de desarrollo, ya que podemos continuar escribiendo en estilo Mongo en toda la pila con un enfoque independiente de la base de datos. También ayuda a evitar ataques de inyección SQL mediante el uso de parámetros de consulta.
inspector-de-esquemas-knexUtilidad SQL para extraer información sobre el esquema de base de datos existente. Esto nos permite validar fácilmente que todos los índices, tablas, columnas, restricciones y más son válidos y están 1:1 con cómo deberían ser. Incluso escribimos ayudantes automatizados para agregar nuevas columnas e índices si se realizan cambios en los esquemas de la base de datos (también con alertas de errores extremadamente detalladas).
knexGenerador de consultas SQL que utilizamos solo para migraciones de bases de datos y validación de esquemas a través de knex-schema-inspector.
mandarínAutomático i18n traducción de frases con soporte para Markdown usando API de traducción de Google Cloud.
conexión mxPaquete Node.js para resolver y establecer conexiones con servidores MX y manejar errores.
pm2Administrador de procesos de producción de Node.js con balanceador de carga incorporado (afinado para el rendimiento).
servidor SMTPBiblioteca de servidor SMTP: la utilizamos para nuestro intercambio de correo ("MX") y servidores SMTP salientes.
Prueba ImapHerramienta útil para probar servidores IMAP comparándolos con puntos de referencia y la compatibilidad del protocolo IMAP con la especificación RFC. Este proyecto fue creado por el Palomar equipo (un servidor IMAP y POP3 activo de código abierto desde julio de 2002). Probamos exhaustivamente nuestro servidor IMAP con esta herramienta.

Puedes encontrar otros proyectos en los que utilizamos nuestro código fuente en GitHub.

Proveedores

ProveedorObjetivo
Flama de nubeProveedor de DNS, controles de estado, balanceadores de carga y almacenamiento de respaldo usando nubeflare r2.
océano digitalAlojamiento de servidor dedicado, almacenamiento en bloque SSD y bases de datos administradas.
vultrAlojamiento de servidor dedicado y almacenamiento en bloque SSD.

Pensamientos

Principios

Forward Email está diseñado de acuerdo con estos principios:

  1. Sea siempre transparente y amigable para los desarrolladores, centrado en la seguridad y la privacidad.
  2. Adherirse a MVC, Unix, KISS, DRY, YAGNI, Doce factores, La navaja de Occam, y comida para perros
  3. Apunte a los luchadores, a los que arrancan y ramen-rentable desarrollador

experimentos

tldr; En última instancia, el uso de almacenamiento de objetos compatible con S3 y/o tablas virtuales no es técnicamente factible por razones de rendimiento y es propenso a errores debido a limitaciones de memoria.

Hemos realizado algunos experimentos previos a nuestra solución SQLite final como se mencionó anteriormente.

Una de ellas fue intentar usar clonar y SQLite junto con una capa de almacenamiento compatible con S3.

Ese experimento nos llevó a comprender y descubrir más casos extremos relacionados con rclone, SQLite y VFS uso:

  • Si habilitas --vfs-cache-mode writes marque con rclone, entonces las lecturas estarán bien, sin embargo, las escrituras se almacenarán en caché.
    • Si tiene varios servidores IMAP distribuidos globalmente, el caché estará desactivado en todos ellos a menos que tenga un único escritor y varios oyentes (por ejemplo, un enfoque pub/sub).
    • Esto es increíblemente complejo y agregar cualquier complejidad adicional como esta dará como resultado más puntos únicos de falla.
    • Los proveedores de almacenamiento compatibles con S3 no admiten cambios parciales de archivos, lo que significa que cualquier cambio del .sqlite El archivo resultará en un cambio completo y una nueva carga de la base de datos.
    • Otras soluciones como rsync existen, pero no se centran en el registro de escritura anticipada ("WAL") soporte, así que terminamos revisando Litestream. Afortunadamente, nuestro uso de cifrado ya cifra el WAL archivos por nosotros, por lo que no necesitamos depender de Litestream para eso. Sin embargo, todavía no confiábamos en Litestream para uso en producción y tenemos algunas notas a continuación al respecto.
    • Usando esta opción de --vfs-cache-mode writes (el solo forma de utilizar SQLite sobre rclone para escrituras) intentará copiar toda la base de datos desde cero en la memoria; manejar un buzón de 10 GB está bien; sin embargo, manejar múltiples buzones con un almacenamiento excesivamente alto hará que los servidores IMAP se ejecuten con limitaciones de memoria y ENOMEM errores, fallas de segmentación y corrupción de datos.
  • Si intenta utilizar SQLite Mesas Virtuales (por ejemplo, usando s3db) para tener datos activos en una capa de almacenamiento compatible con S3, se encontrará con varios problemas más:
    • Las lecturas y escrituras serán extremadamente lentas ya que los puntos finales de la API de S3 deberán funcionar con HTTP GET, PUT, HEAD, y POST métodos.
    • Las pruebas de desarrollo demostraron que superar los 500.000-1 millón de registros en Internet de fibra todavía está limitado por el rendimiento de escritura y lectura en proveedores compatibles con S3. Por ejemplo, nuestros desarrolladores ejecutaron for bucles para hacer SQL secuencial INSERT declaraciones y aquellas que escribieron en masa grandes cantidades de datos. En ambos casos, el desempeño fue asombrosamente lento.
    • Mesas virtuales no puede tener índices, ALTER TABLE declaraciones, y otro limitaciones – lo que provoca retrasos de más de 1 a 2 minutos o más, dependiendo de la cantidad de datos.
    • Los objetos se almacenaron sin cifrar y no hay soporte de cifrado nativo disponible.
  • También exploramos usando sqlite-s3vfs que es similar conceptual y técnicamente al punto anterior (por lo que tiene los mismos problemas). Una posibilidad sería utilizar un personalizado sqlite3 construir envuelto con cifrado como wxSQLite3 (que utilizamos actualmente en nuestra solución anterior) a través de editando el archivo de instalación.
  • Otro posible enfoque era utilizar el extensión multiplex, sin embargo, esto tiene una limitación de 32 GB y requeriría complejos dolores de cabeza de construcción y desarrollo.
  • ALTER TABLE Se requieren declaraciones (por lo que esto descarta completamente el uso de tablas virtuales). Nosotros necesitamos ALTER TABLE declaraciones para que nuestro gancho con knex-schema-inspector para funcionar correctamente, lo que garantiza que los datos no se corrompan y que las filas recuperadas se puedan convertir en documentos válidos de acuerdo con nuestra mongoose definiciones de esquema (que incluyen restricciones, tipos de variables y validación de datos arbitrarios).
  • Casi todos los proyectos compatibles con S3 relacionados con SQLite en la comunidad de código abierto están en Python (y no en JavaScript, que utilizamos para el 100% de nuestra pila).
  • Bibliotecas de compresión como sqlite-zstd (ver comentarios) parecen prometedores, pero Es posible que aún no esté listo para su uso en producción.. En lugar de la compresión del lado de la aplicación en tipos de datos como String, Object, Map, Array, Set, y Buffer será un enfoque más limpio y sencillo (y también es más fácil de migrar, ya que podríamos almacenar un Boolean bandera o columna, o incluso usar PRAGMA user_version=1 para compresión o user_version=0 sin compresión como metadatos de la base de datos).
    • Afortunadamente, ya tenemos implementada la deduplicación de archivos adjuntos en el almacenamiento de nuestro servidor IMAP; por lo tanto, cada mensaje con el mismo archivo adjunto no conservará una copia del archivo adjunto; en su lugar, se almacena un solo archivo adjunto para múltiples mensajes e hilos en un buzón (y un archivo externo). posteriormente se utiliza la referencia).
  • El proyecto Litestream, que es una solución de copia de seguridad y replicación de SQLite, es muy prometedor y lo más probable es que lo utilicemos en el futuro.
  • La restauración de la copia de seguridad debe ser sencilla y trivial. Usando una solución como MongoDB con mongodump y mongoexport No sólo es tedioso, sino que requiere mucho tiempo y tiene una configuración compleja.
    • Las bases de datos SQLite lo hacen simple (es un solo archivo).
    • Queríamos diseñar una solución donde los usuarios pudieran tomar su buzón y salir en cualquier momento.
      • Comandos simples de Node.js para fs.unlink('mailbox.sqlite')) y se borra permanentemente del almacenamiento en disco.
      • De manera similar, podemos usar una API compatible con S3 con HTTP. DELETE para eliminar fácilmente instantáneas y copias de seguridad para los usuarios.
    • SQLite era la solución más sencilla, rápida y rentable.

Falta de alternativas

Hasta donde sabemos, ningún otro servicio de correo electrónico está diseñado de esta manera ni es de código abierto.

Nosotros Creo que esto podría deberse a los servicios de correo electrónico existentes que tienen tecnología heredada en producción con código de espagueti 🍝.

La mayoría, si no todos, los proveedores de servicios de correo electrónico existentes son de código cerrado o se anuncian como de código abierto. pero en realidad sólo su interfaz es de código abierto.

La parte más sensible del correo electrónico (la interacción real de almacenamiento/IMAP/SMTP) todo se hace en el back-end (servidor), y no en el front-end (cliente).

Pruebe Reenviar correo electrónico

Regístrese hoy en https://forwardemail.net! 🚀