Квантово-стійка електронна пошта: як ми використовуємо зашифровані поштові скриньки SQLite для захисту вашої пошти
Передмова
Important
Наш поштовий сервіс є 100% відкритим кодом та орієнтований на конфіденційність через безпечні та зашифровані поштові скриньки SQLite.
Поки ми не запустили підтримку IMAP, ми використовували MongoDB для зберігання постійних даних.
Ця технологія чудова, і ми досі її використовуємо – але щоб мати шифрування даних у стані спокою (encryption-at-rest) з MongoDB, потрібно користуватися провайдером, який пропонує MongoDB Enterprise, наприклад Digital Ocean або Mongo Atlas – або купувати ліцензію Enterprise (і відповідно стикатися з затримками відділу продажів).
Наша команда в Forward Email потребувала зручне для розробників, масштабоване, надійне та зашифроване сховище для IMAP-поштових скриньок. Як розробники відкритого коду, використовувати технологію, за яку потрібно платити ліцензію, щоб отримати функцію шифрування даних у стані спокою, було проти наших принципів – тому ми експериментували, досліджували і розробили нове рішення з нуля, щоб задовольнити ці потреби.
Замість використання спільної бази даних для зберігання ваших поштових скриньок, ми індивідуально зберігаємо та шифруємо ваші поштові скриньки вашим паролем (який є тільки у вас). Наш поштовий сервіс настільки безпечний, що якщо ви забудете свій пароль, то втратите поштову скриньку (і доведеться відновлювати її з офлайн резервних копій або починати заново).
Продовжуйте читати, адже ми детально розглянемо нижче порівняння провайдерів поштових сервісів, як працює наш сервіс, наш технологічний стек та інше.
Порівняння провайдерів поштових сервісів
Ми є єдиним 100% відкритим та орієнтованим на конфіденційність провайдером поштових сервісів, який зберігає індивідуально зашифровані поштові скриньки SQLite, пропонує необмежену кількість доменів, псевдонімів та користувачів, а також підтримує вихідний SMTP, IMAP та POP3:
На відміну від інших поштових провайдерів, вам не потрібно платити за зберігання на основі домену чи псевдоніму з Forward Email. Зберігання спільне для всього вашого акаунту – тож якщо у вас кілька власних доменів і кілька псевдонімів на кожному, ми ідеальне рішення для вас. Зверніть увагу, що ви все одно можете встановлювати обмеження на зберігання за доменом або псевдонімом, якщо бажаєте.
Прочитати порівняння поштових сервісів
Як це працює
-
Використовуючи ваш поштовий клієнт, наприклад Apple Mail, Thunderbird, Gmail або Outlook – ви підключаєтесь до наших безпечних IMAP серверів, використовуючи ваше ім’я користувача та пароль:
- Ваше ім’я користувача – це повний псевдонім з вашим доменом, наприклад
hello@example.com. - Ваш пароль генерується випадково і відображається вам лише 30 секунд, коли ви натискаєте Згенерувати пароль у Мій акаунт Домени Псевдоніми.
- Ваше ім’я користувача – це повний псевдонім з вашим доменом, наприклад
-
Після підключення ваш поштовий клієнт надсилатиме команди протоколу IMAP на наш IMAP сервер для синхронізації вашої поштової скриньки. Це включає написання та збереження чернеток листів та інші дії, які ви можете виконувати (наприклад, позначити лист як Важливий або позначити лист як Спам/Небажана пошта).
-
Сервери обміну поштою (зазвичай відомі як "MX" сервери) отримують нові вхідні листи та зберігають їх у вашій поштовій скриньці. Коли це відбувається, ваш поштовий клієнт отримує сповіщення та синхронізує вашу поштову скриньку. Наші сервери обміну поштою можуть пересилати вашу пошту одному або кільком отримувачам (включно з вебхуками), зберігати вашу пошту у вашому зашифрованому IMAP сховищі у нас, або і те, і інше!
Tip
Зацікавлені дізнатися більше? Прочитайте як налаштувати пересилання пошти, як працює наша служба обміну поштою, або перегляньте наші посібники.
-
За лаштунками наш дизайн безпечного зберігання пошти працює двома способами, щоб зберігати ваші поштові скриньки зашифрованими та доступними лише для вас:
-
Коли для вас надходить нова пошта від відправника, наші сервери обміну поштою записують її у індивідуальну, тимчасову та зашифровану поштову скриньку для вас.
-
Коли ви підключаєтеся до нашого IMAP сервера за допомогою поштового клієнта, ваш пароль шифрується в пам’яті і використовується для читання та запису у вашу поштову скриньку. Вашу поштову скриньку можна читати та записувати лише з цим паролем. Пам’ятайте, що оскільки ви є єдиним, хто має цей пароль, тільки ви можете читати та записувати у вашу поштову скриньку під час доступу до неї. Наступного разу, коли ваш поштовий клієнт спробує перевірити пошту або синхронізуватися, ваші нові повідомлення будуть перенесені з цієї тимчасової поштової скриньки і збережені у вашому фактичному файлі поштової скриньки з використанням наданого вами пароля. Зверніть увагу, що ця тимчасова пошта очищується та видаляється після цього, щоб лише ваша захищена паролем пошта містила повідомлення.
-
Якщо ви підключені через IMAP (наприклад, використовуючи поштовий клієнт, такий як Apple Mail або Thunderbird), тоді нам не потрібно записувати у тимчасове дискове сховище. Ваш зашифрований в пам’яті IMAP пароль натомість отримується і використовується. У реальному часі, коли повідомлення намагається бути доставленим вам, ми надсилаємо WebSocket-запит усім IMAP серверам, запитуючи, чи є у них активна сесія для вас (це частина отримання), а потім передаємо цей зашифрований пароль у пам’яті – таким чином нам не потрібно записувати у тимчасову поштову скриньку, ми можемо записувати у вашу фактичну зашифровану поштову скриньку, використовуючи ваш зашифрований пароль.
-
-
Резервні копії ваших зашифрованих поштових скриньок створюються щодня. Ви також можете будь-коли запросити нову резервну копію або завантажити останню резервну копію з Мій акаунт Домени Псевдоніми. Якщо ви вирішите перейти на інший поштовий сервіс, ви можете легко мігрувати, завантажувати, експортувати та очищати ваші поштові скриньки та резервні копії у будь-який час.
Технології
Бази даних
Ми досліджували інші можливі шари зберігання баз даних, проте жоден не задовольнив наші вимоги так, як SQLite:
| Database | Encryption-at-rest | Sandboxed Mailboxes | License | Used Everywhere |
|---|---|---|---|---|
| SQLite ⭐ | ✅ Так з SQLite3MultipleCiphers | ✅ | ✅ Публічний домен | ✅ |
| MongoDB | ❌ "Доступно лише в MongoDB Enterprise" | ❌ Реляційна база даних | ❌ AGPL та SSPL-1.0 |
❌ |
| rqlite | ❌ Тільки мережеве | ❌ Реляційна база даних | ✅ MIT |
❌ |
| dqlite | ❌ Не протестовано і поки не підтримується? | ❌ Не протестовано і поки не підтримується? | ✅ LGPL-3.0-only |
❌ |
| PostgreSQL | ✅ Так | ❌ Реляційна база даних | ✅ PostgreSQL (схоже на BSD або MIT) |
❌ |
| MariaDB | ✅ Лише для InnoDB | ❌ Реляційна база даних | ✅ GPLv2 та BUSL-1.1 |
❌ |
| CockroachDB | ❌ Функція лише для Enterprise | ❌ Реляційна база даних | ❌ BUSL-1.1 та інші |
❌ |
Ось публікація в блозі, що порівнює кілька варіантів зберігання бази даних SQLite у таблиці вище.
Безпека
Завжди ми використовуємо шифрування даних у стані спокою (AES-256), шифрування даних під час передачі (TLS), DNS через HTTPS ("DoH") за допомогою 🍊 Tangerine, та sqleet (ChaCha20-Poly1305) шифрування на поштових скриньках. Додатково ми використовуємо двофакторну автентифікацію на основі токенів (на відміну від SMS, які вразливі до атак посередника), ротацію SSH-ключів з відключеним доступом root, ексклюзивний доступ до серверів через обмежені IP-адреси та інше. У разі атаки зловмисної покоївки або недобросовісного працівника стороннього постачальника, ваша поштова скринька все одно може бути відкрита лише за допомогою вашого згенерованого пароля. Будьте впевнені, ми не покладаємося на жодних сторонніх постачальників, окрім наших серверів із сертифікатом SOC Type 2 від Cloudflare, DataPacket, Digital Ocean, GitHub та Vultr.
Наша мета — мати якомога менше одиночних точок відмови.
Поштові скриньки
коротко; Наші IMAP-сервери використовують індивідуально зашифровані бази даних SQLite для кожної вашої поштової скриньки.
SQLite — надзвичайно популярна вбудована база даних – вона наразі працює на вашому телефоні та комп’ютері – і використовується майже всіма основними технологіями.
Наприклад, на наших зашифрованих серверах є база даних SQLite для поштової скриньки linux@example.com, info@example.com, hello@example.com і так далі – по одній для кожної у вигляді файлу бази даних .sqlite. Ми також не називаємо файли бази даних за адресою електронної пошти – натомість використовуємо BSON ObjectID та унікальні UUID, які не розкривають, кому належить поштова скринька або під якою адресою вона знаходиться (наприклад, 353a03f21e534321f5d6e267.sqlite).
Кожна з цих баз даних сама зашифрована за допомогою вашого пароля (який є лише у вас) із використанням sqleet (ChaCha20-Poly1305). Це означає, що ваші поштові скриньки індивідуально зашифровані, автономні, ізольовані та портативні.
Ми тонко налаштували SQLite за допомогою наступних PRAGMA:
PRAGMA |
Призначення |
|---|---|
cipher=chacha20 |
Шифрування бази даних SQLite ChaCha20-Poly1305. Для детальнішої інформації див. better-sqlite3-multiple-ciphers у розділі Projects. |
key="****************" |
Це ваш розшифрований пароль, який зберігається лише в пам’яті і передається через IMAP-з’єднання вашого поштового клієнта на наш сервер. Нові екземпляри бази даних створюються та закриваються для кожної сесії читання та запису (щоб забезпечити ізоляцію). |
journal_model=WAL |
Write-ahead-log ("WAL") який підвищує продуктивність і дозволяє одночасний доступ на читання. |
busy_timeout=5000 |
Запобігає помилкам блокування запису під час інших операцій запису. |
synchronous=NORMAL |
Підвищує надійність транзакцій без ризику пошкодження даних. |
foreign_keys=ON |
Забезпечує дотримання зовнішніх ключів (наприклад, зв’язок між таблицями). За замовчуванням ця опція вимкнена в SQLite, але для валідації та цілісності даних її слід увімкнути. |
encoding='UTF-8' |
Кодування за замовчуванням для забезпечення зручності розробника. |
Всі інші значення за замовчуванням походять із SQLite, як зазначено в офіційній документації PRAGMA.
Конкурентність
коротко; Ми використовуємо
WebSocketдля одночасного читання та запису у ваші зашифровані поштові скриньки SQLite.
Читання
Ваш поштовий клієнт на телефоні може розпізнавати imap.forwardemail.net як одну з наших IP-адрес Digital Ocean – а ваш десктопний клієнт може розпізнавати окрему IP-адресу від іншого провайдера.
Незалежно від того, до якого IMAP-сервера підключається ваш поштовий клієнт, ми хочемо, щоб з’єднання читало з вашої бази даних у реальному часі з 100% точністю. Це реалізовано через WebSockets.
Записи
Запис у вашу базу даних трохи відрізняється – оскільки SQLite є вбудованою базою даних, і ваша поштові скринька за замовчуванням зберігається в одному файлі.
Ми розглядали варіанти, такі як litestream, rqlite та dqlite нижче – проте жоден із них не задовольнив наші вимоги.
Щоб виконувати записи з увімкненим журналом попереднього запису ("WAL"), потрібно гарантувати, що лише один сервер ("Primary") відповідає за це. WAL значно прискорює конкурентність і дозволяє одному писачу та кільком читачам працювати одночасно.
Primary працює на серверах даних із змонтованими томами, що містять зашифровані поштові скриньки. З точки зору розподілу, можна вважати всі окремі IMAP-сервери за imap.forwardemail.net вторинними серверами ("Secondary").
Ми реалізуємо двонаправлену комунікацію за допомогою WebSockets:
- Primary-сервери використовують екземпляр сервера
WebSocketServerз ws. - Secondary-сервери використовують екземпляр клієнта
WebSocketз ws, обгорнутий у websocket-as-promised та reconnecting-websocket. Ці два обгортки забезпечують повторне підключенняWebSocketта можливість надсилати й отримувати дані для конкретних записів у базу даних.
Резервні копії
коротко; Резервні копії ваших зашифрованих поштових скриньок створюються щодня. Ви також можете миттєво запросити нову копію або завантажити останню резервну копію в будь-який час із Мій акаунт Домени Псевдоніми.
Для резервного копіювання ми просто щодня під час обробки команд IMAP виконуємо команду SQLite VACUUM INTO, яка використовує ваш зашифрований пароль із підключення IMAP у пам’яті. Резервні копії зберігаються, якщо не виявлено існуючу копію або якщо хеш SHA-256 файлу змінився порівняно з останньою резервною копією.
Зверніть увагу, що ми використовуємо команду VACUUM INTO замість вбудованої команди backup, тому що якщо сторінка змінюється під час операції backup, то процес потрібно починати спочатку. Команда VACUUM INTO робить знімок. Детальніше дивіться в цих коментарях на GitHub та Hacker News.
Крім того, ми використовуємо VACUUM INTO замість backup, тому що команда backup залишає базу даних незашифрованою на короткий час, доки не виконається rekey (див. цей коментар на GitHub comment для роз’яснень).
Secondary через з’єднання WebSocket дає команду Primary виконати резервне копіювання – і Primary отримує цю команду та послідовно виконує:
- Підключається до вашої зашифрованої поштової скриньки.
- Отримує блокування на запис.
- Виконує контрольну точку WAL через
wal_checkpoint(PASSIVE). - Виконує команду SQLite
VACUUM INTO. - Переконується, що скопійований файл можна відкрити за допомогою зашифрованого пароля (запобігання помилкам).
- Завантажує його до Cloudflare R2 для зберігання (або до вашого власного провайдера, якщо вказано).
Пам’ятайте, що ваші поштові скриньки зашифровані – і хоча ми маємо обмеження за IP та інші заходи автентифікації для WebSocket-з’єднань – у випадку зловмисника ви можете бути впевнені, що якщо WebSocket-пакет не містить вашого IMAP-пароля, він не зможе відкрити вашу базу даних.
На даний момент зберігається лише одна резервна копія на поштову скриньку, але в майбутньому ми можемо запропонувати відновлення на певний момент часу ("PITR").
Пошук
Наші IMAP-сервери підтримують команду SEARCH з комплексними запитами, регулярними виразами та іншим.
Швидкість пошуку забезпечується завдяки FTS5 та sqlite-regex.
Ми зберігаємо значення Date у SQLite-поштових скриньках у вигляді рядків за стандартом ISO 8601 через Date.prototype.toISOString (з часовою зоною UTC для коректного порівняння).
Індекси також зберігаються для всіх властивостей, які використовуються у пошукових запитах.
Проєкти
Ось таблиця з переліком проєктів, які ми використовуємо у нашому вихідному коді та процесі розробки (відсортовано за алфавітом):
| Проєкт | Призначення |
|---|---|
| Ansible | Платформа автоматизації DevOps для підтримки, масштабування та керування всіма нашими серверами з легкістю. |
| Bree | Планувальник завдань для Node.js та JavaScript з підтримкою cron, дат, ms, later та зручним для людини інтерфейсом. |
| Cabin | Зручна для розробників бібліотека логування для JavaScript та Node.js з урахуванням безпеки та конфіденційності. |
| Lad | Фреймворк Node.js, який забезпечує всю нашу архітектуру та інженерний дизайн з MVC та іншим. |
| MongoDB | NoSQL база даних, яку ми використовуємо для зберігання всіх інших даних поза поштовими скриньками (наприклад, вашого акаунта, налаштувань, доменів та конфігурацій псевдонімів). |
| Mongoose | Об’єктно-документна модель MongoDB ("ODM"), яку ми використовуємо у всьому стеку. Ми написали спеціальні допоміжні засоби, що дозволяють нам просто продовжувати використовувати Mongoose з SQLite 🎉 |
| Node.js | Node.js — це відкрите, кросплатформне середовище виконання JavaScript, яке запускає всі наші серверні процеси. |
| Nodemailer | Пакет Node.js для відправки електронних листів, створення з’єднань та іншого. Ми є офіційним спонсором цього проєкту. |
| Redis | База даних у пам’яті для кешування, каналів публікації/підписки та запитів DNS через HTTPS. |
| SQLite3MultipleCiphers | Розширення шифрування для SQLite, що дозволяє шифрувати цілі файли бази даних (включно з журналом попереднього запису ("WAL"), журналом, відкатом тощо). |
| SQLiteStudio | Візуальний редактор SQLite (яким ви також можете користуватися) для тестування, завантаження та перегляду поштових скриньок під час розробки. |
| SQLite | Вбудований рівень бази даних для масштабованого, автономного, швидкого та надійного зберігання IMAP. |
| Spam Scanner | Інструмент Node.js для антиспаму, фільтрації електронної пошти та запобігання фішингу (наша альтернатива Spam Assassin та rspamd). |
| Tangerine | Запити DNS через HTTPS з Node.js та кешування за допомогою Redis – що забезпечує глобальну узгодженість та багато іншого. |
| Thunderbird | Наша команда розробників використовує цей клієнт (і також рекомендує його) як переважний поштовий клієнт для роботи з Forward Email. |
| UTM | Наша команда розробників використовує цей інструмент для створення віртуальних машин для iOS та macOS, щоб тестувати різні поштові клієнти (паралельно) з нашими IMAP та SMTP серверами. |
| Ubuntu | Сучасна відкрита операційна система на базі Linux, яка забезпечує роботу всієї нашої інфраструктури. |
| WildDuck | Бібліотека IMAP-сервера – дивіться її нотатки про де-дуплікацію вкладень та підтримку протоколу IMAP. |
| better-sqlite3-multiple-ciphers | Швидка та проста API-бібліотека для Node.js для програмної взаємодії з SQLite3. |
| email-templates | Зручний для розробників фреймворк для створення, попереднього перегляду та відправки кастомних листів (наприклад, повідомлень акаунта та іншого). |
| json-sql-enhanced | Конструктор SQL-запитів із синтаксисом у стилі Mongo. Це економить час нашій команді розробників, оскільки ми можемо продовжувати писати у стилі Mongo по всьому стеку з підходом, що не залежить від бази даних. Також це допомагає уникнути SQL-ін’єкцій, використовуючи параметри запитів. |
| knex-schema-inspector | SQL-утиліта для отримання інформації про існуючу схему бази даних. Це дозволяє нам легко перевіряти, що всі індекси, таблиці, колонки, обмеження тощо є дійсними і відповідають 1:1 тому, як вони мають бути. Ми навіть написали автоматизовані помічники для додавання нових колонок та індексів, якщо вносяться зміни до схем баз даних (з дуже детальним оповіщенням про помилки). |
| knex | Конструктор SQL-запитів, який ми використовуємо лише для міграцій бази даних та перевірки схем через knex-schema-inspector. |
| mandarin | Автоматичний переклад фраз i18n з підтримкою Markdown за допомогою Google Cloud Translation API. |
| mx-connect | Пакет Node.js для визначення та встановлення з’єднань з MX-серверами та обробки помилок. |
| pm2 | Менеджер процесів Node.js для продакшн з вбудованим балансувальником навантаження (тонко налаштований для продуктивності). |
| smtp-server | Бібліотека SMTP-сервера – ми використовуємо її для наших серверів обміну поштою ("MX") та вихідних SMTP-серверів. |
| ImapTest | Корисний інструмент для тестування IMAP-серверів за стандартами та сумісності з протоколом IMAP згідно з RFC. Цей проєкт створено командою Dovecot (активний відкритий IMAP та POP3 сервер з липня 2002 року). Ми широко тестували наш IMAP-сервер за допомогою цього інструменту. |
Ви можете знайти інші проєкти, які ми використовуємо, у нашому вихідному коді на GitHub.
Провайдери
| Провайдер | Призначення |
|---|---|
| Cloudflare | Провайдер DNS, перевірки стану, балансувальники навантаження та резервне зберігання за допомогою Cloudflare R2. |
| GitHub | Хостинг вихідного коду, CI/CD та управління проєктами. |
| Digital Ocean | Хостинг виділених серверів та керовані бази даних. |
| Vultr | Хостинг виділених серверів. |
| DataPacket | Хостинг виділених серверів. |
Думки
Принципи
Forward Email розроблено відповідно до цих принципів:
- Завжди бути дружнім до розробників, орієнтованим на безпеку та конфіденційність, а також прозорим.
- Дотримуватися MVC, Unix, KISS, DRY, YAGNI, Twelve Factor, бритви Оккама та dogfooding
- Орієнтуватися на наполегливого, самофінансованого та ramen-прибуткового розробника
Експерименти
коротко; Врешті-решт використання об’єктного сховища, сумісного з S3, та/або Віртуальних Таблиць технічно неможливе з причин продуктивності та схильне до помилок через обмеження пам’яті.
Ми провели кілька експериментів, що призвели до нашого остаточного рішення на основі SQLite, як описано вище.
Один із них полягав у спробі використання rclone та SQLite разом із шаром сховища, сумісним із S3.
Цей експеримент допоміг нам краще зрозуміти та виявити крайні випадки, пов’язані з rclone, SQLite та використанням VFS:
- Якщо увімкнути прапорець
--vfs-cache-mode writesу rclone, тоді читання буде нормальним, але записи кешуватимуться.- Якщо у вас є кілька IMAP-серверів, розподілених глобально, кеш буде розрізненим між ними, якщо у вас немає одного записувача та кількох слухачів (наприклад, підхід pub/sub).
- Це надзвичайно складно, і додавання будь-якої додаткової складності призведе до більшої кількості єдиних точок відмови.
- Провайдери сховищ, сумісних із S3, не підтримують часткові зміни файлів – це означає, що будь-яка зміна файлу
.sqliteпризведе до повної зміни та повторного завантаження бази даних. - Існують інші рішення, такі як
rsync, але вони не орієнтовані на підтримку журналу попереднього запису ("WAL") – тому ми розглянули Litestream. На щастя, наше шифрування вже шифрує файли WAL, тому нам не потрібно покладатися на Litestream для цього. Однак ми ще не були впевнені в Litestream для використання у виробництві і маємо кілька зауважень нижче. - Використання опції
--vfs-cache-mode writes(єдиний спосіб використовувати SQLite черезrcloneдля записів) спробує скопіювати всю базу даних з нуля в пам’яті – обробка однієї поштової скриньки розміром 10 ГБ є прийнятною, але обробка кількох скриньок із надзвичайно великим обсягом призведе до обмежень пам’яті на IMAP-серверах, помилокENOMEM, збоїв сегментації та пошкодження даних.
- Якщо спробувати використовувати SQLite Віртуальні Таблиці (наприклад, за допомогою s3db) для зберігання даних безпосередньо на шарі сховища, сумісного з S3, виникне кілька додаткових проблем:
- Читання та записи будуть надзвичайно повільними, оскільки до API S3 доведеться звертатися через HTTP методи
GET,PUT,HEADтаPOST. - Тести розробки показали, що при перевищенні 500 тис. – 1 млн+ записів через оптоволоконний інтернет швидкість все одно обмежена пропускною здатністю запису та читання до провайдерів, сумісних із S3. Наприклад, наші розробники запускали цикли
forдля послідовних SQLINSERTта для масового запису великих обсягів даних. В обох випадках продуктивність була надзвичайно повільною. - Віртуальні таблиці не можуть мати індекси, оператори
ALTER TABLEта інші обмеження – що призводить до затримок понад 1-2 хвилини або більше залежно від обсягу даних. - Об’єкти зберігалися без шифрування, і нативна підтримка шифрування відсутня.
- Читання та записи будуть надзвичайно повільними, оскільки до API S3 доведеться звертатися через HTTP методи
- Ми також досліджували використання sqlite-s3vfs, що концептуально та технічно схоже на попередній пункт (тому має ті ж проблеми). Можливо, можна використати кастомну збірку
sqlite3з шифруванням, наприклад wxSQLite3 (яку ми наразі використовуємо у нашому рішенні вище) через редагування setup-файлу. - Іншим потенційним підходом було використання розширення multiplex, але воно має обмеження у 32 ГБ і потребує складної збірки та розробницьких труднощів.
- Оператори
ALTER TABLEнеобхідні (тому використання Віртуальних Таблиць повністю виключено). Нам потрібні операториALTER TABLE, щоб наш хук зknex-schema-inspectorпрацював коректно – це гарантує, що дані не пошкоджені, а отримані рядки можна конвертувати у валідні документи згідно з нашими визначеннями схемmongoose(включно з обмеженнями, типами змінних та довільною валідацією даних). - Майже всі проєкти, сумісні з S3 і пов’язані з SQLite в open-source спільноті, написані на Python (а не на JavaScript, який ми використовуємо для 100% нашого стеку).
- Бібліотеки стиснення, такі як sqlite-zstd (див. коментарі), виглядають перспективно, але можуть ще не бути готовими для виробничого використання. Натомість стиснення на стороні застосунку для типів даних, таких як
String,Object,Map,Array,SetтаBuffer, буде чистішим і простішим підходом (і легшим для міграції, оскільки ми могли б зберігати булевий прапорець або колонку – або навіть використовуватиPRAGMAuser_version=1для стиснення абоuser_version=0для відсутності стиснення як метадані бази даних).- На щастя, у нашому сховищі IMAP-сервера вже реалізовано дедуплікацію вкладень – тому кожне повідомлення з однаковим вкладенням не зберігає копію вкладення, а зберігається одне вкладення для кількох повідомлень і ниток у скриньці (з подальшим використанням зовнішнього посилання).
- Проєкт Litestream, який є рішенням для реплікації та резервного копіювання SQLite, дуже перспективний, і ми, ймовірно, будемо його використовувати в майбутньому.
- Не хочу применшувати заслуги автора(ів) – ми любимо їхню роботу та внесок у open-source вже понад десятиліття – але з реального досвіду здається, що там може бути багато проблем і потенційна втрата даних при використанні.
- Відновлення резервних копій має бути безперешкодним і тривіальним. Використання рішень на кшталт MongoDB з
mongodumpтаmongoexportне лише трудомістке, але й часозатратне та складне в налаштуванні.- Бази даних SQLite роблять це просто (це один файл).
- Ми хотіли розробити рішення, де користувачі можуть забрати свою поштову скриньку і піти в будь-який момент.
- Простими командами Node.js
fs.unlink('mailbox.sqlite'))вона назавжди видаляється з дискового сховища. - Аналогічно можна використовувати API, сумісний із S3, з HTTP
DELETEдля легкого видалення знімків і резервних копій користувачів.
- Простими командами Node.js
- SQLite було найпростішим, найшвидшим і найекономічнішим рішенням.
Відсутність альтернатив
Нам відомо, що жоден інший сервіс електронної пошти не спроєктований таким чином і не є відкритим програмним забезпеченням.
Ми вважаємо, що це може бути пов’язано з тим, що існуючі сервіси електронної пошти використовують застарілі технології в продуктиві з спагеті-кодом 🍝.
Більшість, якщо не всі, існуючих провайдерів електронної пошти є або закритим програмним забезпеченням, або рекламують себе як відкриті, але насправді лише їхній фронтенд є відкритим кодом.
Найчутливіша частина електронної пошти (фактичне зберігання/взаємодія IMAP/SMTP) виконується на бекенді (сервері), а не на фронтенді (клієнті).
Спробуйте Forward Email
Зареєструйтесь сьогодні на https://forwardemail.net! 🚀