Квантово-устойчивая электронная почта: как мы используем зашифрованные почтовые ящики SQLite для защиты вашей почты

Иллюстрация квантово-безопасного зашифрованного почтового сервиса

Предисловие

Important

Наш почтовый сервис является 100% открытым исходным кодом и ориентирован на конфиденциальность благодаря безопасным и зашифрованным почтовым ящикам SQLite.

До запуска поддержки IMAP мы использовали MongoDB для хранения постоянных данных.

Эта технология потрясающая, и мы до сих пор её используем – но чтобы иметь шифрование данных в состоянии покоя (encryption-at-rest) с MongoDB, нужно использовать провайдера, который предлагает MongoDB Enterprise, например Digital Ocean или Mongo Atlas – либо платить за корпоративную лицензию (а затем сталкиваться с задержками работы с отделом продаж).

Наша команда в Forward Email нуждалась в удобном для разработчиков, масштабируемом, надежном и зашифрованном решении для хранения IMAP-почтовых ящиков. Как разработчики с открытым исходным кодом, использовать технологию, за которую нужно платить лицензию ради функции шифрования данных в состоянии покоя, противоречило нашим принципам – поэтому мы экспериментировали, исследовали и разработали новое решение с нуля для удовлетворения этих потребностей.

Вместо использования общей базы данных для хранения ваших почтовых ящиков, мы храним и шифруем каждый почтовый ящик индивидуально с вашим паролем (который есть только у вас). Наш почтовый сервис настолько безопасен, что если вы забудете пароль, то потеряете доступ к своему почтовому ящику (и вам придется восстанавливаться из офлайн-резервных копий или начинать заново).

Читайте дальше, чтобы подробно ознакомиться с сравнением провайдеров почтовых услуг, как работает наш сервис, нашим технологическим стеком и многим другим.

Сравнение провайдеров почтовых услуг

Мы единственный 100% открытый и ориентированный на конфиденциальность провайдер электронной почты, который хранит индивидуально зашифрованные почтовые ящики SQLite, предлагает неограниченное количество доменов, алиасов и пользователей, а также поддерживает исходящую SMTP, IMAP и POP3:

В отличие от других почтовых провайдеров, с Forward Email вам не нужно платить за хранение на основе каждого домена или алиаса. Хранение разделяется по всей вашей учетной записи – так что если у вас несколько пользовательских доменов и множество алиасов на каждом, мы — идеальное решение для вас. Обратите внимание, что при желании вы всё равно можете установить лимиты хранения для каждого домена или алиаса.

Читать сравнение почтовых сервисов

Как это работает

  1. Используя ваш почтовый клиент, такой как Apple Mail, Thunderbird, Gmail или Outlook, вы подключаетесь к нашим защищённым IMAP серверам, используя ваше имя пользователя и пароль:

    • Ваше имя пользователя — это полный алиас с вашим доменом, например hello@example.com.
    • Ваш пароль генерируется случайным образом и отображается вам только в течение 30 секунд при нажатии Сгенерировать пароль в разделе Мой аккаунт Домены Алиасы.
  2. После подключения ваш почтовый клиент будет отправлять команды протокола IMAP на наш IMAP-сервер для синхронизации вашего почтового ящика. Это включает создание и сохранение черновиков писем и другие действия, которые вы можете выполнять (например, пометить письмо как Важное или отметить письмо как Спам/Нежелательная почта).

  3. Серверы обмена почтой (обычно называемые "MX" серверами) принимают новые входящие письма и сохраняют их в вашем почтовом ящике. Когда это происходит, ваш почтовый клиент получает уведомление и синхронизирует ваш почтовый ящик. Наши серверы обмена почтой могут пересылать вашу почту одному или нескольким получателям (включая вебхуки), хранить вашу почту для вас в нашем зашифрованном IMAP-хранилище, или и то, и другое!

  4. За кулисами наш дизайн безопасного хранения почты работает двумя способами, чтобы ваши почтовые ящики оставались зашифрованными и доступными только вам:

    • Когда для вас приходит новое письмо от отправителя, наши серверы обмена почтой записывают его в отдельный, временный и зашифрованный почтовый ящик.

    • Когда вы подключаетесь к нашему IMAP-серверу с помощью почтового клиента, ваш пароль затем шифруется в памяти и используется для чтения и записи в ваш почтовый ящик. Ваш почтовый ящик можно читать и записывать только с этим паролем. Имейте в виду, что поскольку пароль есть только у вас, только вы можете читать и записывать в ваш почтовый ящик при его использовании. В следующий раз, когда ваш почтовый клиент попытается проверить почту или синхронизироваться, ваши новые сообщения будут перенесены из этого временного почтового ящика и сохранены в вашем фактическом почтовом ящике с использованием предоставленного вами пароля. Обратите внимание, что этот временный почтовый ящик затем очищается и удаляется, чтобы сообщения хранились только в вашем защищённом паролем почтовом ящике.

    • Если вы подключены к IMAP (например, используя почтовый клиент, такой как Apple Mail или Thunderbird), тогда нам не нужно записывать данные во временное дисковое хранилище. Ваш зашифрованный в памяти IMAP-пароль вместо этого извлекается и используется. В реальном времени, когда сообщение пытается быть доставлено вам, мы отправляем WebSocket-запрос всем IMAP-серверам с вопросом, есть ли у них активная сессия для вас (это часть извлечения), а затем передаем этот зашифрованный пароль в памяти – таким образом нам не нужно записывать во временный почтовый ящик, мы можем записывать в ваш фактический зашифрованный почтовый ящик, используя ваш зашифрованный пароль.

  5. Резервные копии ваших зашифрованных почтовых ящиков создаются ежедневно. Вы также можете запросить новую резервную копию в любое время или скачать последнюю резервную копию на странице Мой аккаунт Домены Псевдонимы. Если вы решите перейти на другой почтовый сервис, вы сможете легко мигрировать, скачать, экспортировать и удалить ваши почтовые ящики и резервные копии в любое время.

Технологии

Базы данных

Мы рассматривали другие возможные уровни хранения данных, однако ни один не удовлетворял наши требования так, как 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 в таблице выше.

Security

Мы всегда используем шифрование данных в покое (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_mode=WAL Журнал предварительной записи ("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 и возможность отправлять и получать данные для конкретных операций записи в базу данных.

Резервные копии

коротко: Резервные копии ваших зашифрованных почтовых ящиков создаются ежедневно. Вы также можете мгновенно запросить новую копию или скачать последнюю резервную копию в любое время на странице Мой аккаунт Домены Псевдонимы.

Для резервного копирования мы просто выполняем команду SQLite VACUUM INTO каждый день во время обработки команд IMAP, используя ваш зашифрованный пароль из IMAP-соединения в памяти. Резервные копии сохраняются, если не обнаружена существующая копия или если SHA-256 хэш файла изменился по сравнению с самой последней копией.

Обратите внимание, что мы используем команду VACUUM INTO, а не встроенную команду backup, потому что если страница изменяется во время операции backup, то процесс приходится начинать заново. Команда VACUUM INTO создаёт снимок. Подробнее см. комментарии на GitHub и Hacker News.

Кроме того, мы используем VACUUM INTO вместо backup, потому что команда backup оставляет базу данных незашифрованной на короткое время до вызова rekey (см. этот комментарий на GitHub comment для подробностей).

Secondary через соединение WebSocket даёт команду Primary выполнить резервное копирование – и Primary затем получает эту команду и последовательно:

  1. Подключается к вашему зашифрованному почтовому ящику.
  2. Получает блокировку на запись.
  3. Выполняет контрольную точку WAL через wal_checkpoint(PASSIVE).
  4. Выполняет команду SQLite VACUUM INTO.
  5. Проверяет, что скопированный файл можно открыть с зашифрованным паролем (защита/проверка).
  6. Загружает его в 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 (активный open-source IMAP и POP3 сервер с июля 2002 года). Мы широко тестировали наш IMAP-сервер с помощью этого инструмента.

Вы можете найти другие проекты, которые мы используем, в нашем исходном коде на GitHub.

Провайдеры

Провайдер Назначение
Cloudflare Провайдер DNS, проверки состояния, балансировщики нагрузки и резервное хранилище с использованием Cloudflare R2.
GitHub Хостинг исходного кода, CI/CD и управление проектами.
Digital Ocean Хостинг выделенных серверов и управляемые базы данных.
Vultr Хостинг выделенных серверов.
DataPacket Хостинг выделенных серверов.

Мысли

Принципы

Forward Email разработан согласно следующим принципам:

  1. Всегда быть удобным для разработчиков, ориентированным на безопасность и конфиденциальность, а также прозрачным.
  2. Следовать MVC, Unix, KISS, DRY, YAGNI, Twelve Factor, Бритве Оккама и dogfooding
  3. Ориентироваться на предприимчивого, самостоятельно финансируемого и приносящего доход на уровне рамена разработчика

Эксперименты

кратко; В конечном итоге использование совместимого с 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.
    • Тесты разработки показали, что при превышении 500K-1M+ записей на оптоволоконном интернете производительность всё равно ограничена пропускной способностью записи и чтения у провайдеров совместимого с S3 хранилища. Например, наши разработчики запускали циклы for для последовательных SQL INSERT запросов и для массовой записи больших объёмов данных. В обоих случаях производительность была крайне низкой.
    • Виртуальные таблицы не могут иметь индексы, операторы ALTER TABLE и другие ограничения – что приводит к задержкам до 1-2 минут и более в зависимости от объёма данных.
    • Объекты хранились без шифрования, и нативная поддержка шифрования отсутствует.
  • Мы также исследовали использование sqlite-s3vfs, который концептуально и технически похож на предыдущий пункт (поэтому имеет те же проблемы). Возможным решением было бы использовать кастомную сборку sqlite3 с обёрткой шифрования, такую как wxSQLite3 (которую мы используем в нашем решении выше) через редактирование файла настройки.
  • Другой потенциальный подход – использовать расширение multiplex, однако оно ограничено 32 ГБ и требует сложной сборки и разработки.
  • Операторы ALTER TABLE необходимы (что полностью исключает использование Виртуальных Таблиц). Нам нужны операторы ALTER TABLE для корректной работы нашего хука с knex-schema-inspector – это гарантирует, что данные не будут повреждены, а извлечённые строки могут быть преобразованы в валидные документы согласно нашим определениям схемы mongoose (включая ограничения, типы переменных и произвольную валидацию данных).
  • Почти все проекты с поддержкой совместимости S3 и SQLite в сообществе с открытым исходным кодом написаны на Python (а не на JavaScript, который мы используем для 100% нашего стека).
  • Библиотеки сжатия, такие как sqlite-zstd (см. комментарии) выглядят многообещающе, но возможно, ещё не готовы к использованию в продакшене. Вместо этого сжатие на стороне приложения для типов данных, таких как String, Object, Map, Array, Set и Buffer будет более чистым и простым подходом (и проще для миграции, так как мы можем хранить булев флаг или колонку – или даже использовать PRAGMA user_version=1 для сжатия или user_version=0 для отсутствия сжатия как метаданные базы данных).
    • К счастью, у нас уже реализована дедупликация вложений в хранилище IMAP сервера – поэтому каждое сообщение с одинаковым вложением не хранит копию вложения – вместо этого одно вложение хранится для нескольких сообщений и потоков в почтовом ящике (и используется внешняя ссылка).
  • Проект Litestream, который является решением для репликации и резервного копирования SQLite, очень перспективен, и мы, скорее всего, будем использовать его в будущем.
  • Восстановление из резервной копии должно быть простым и беспрепятственным. Использование решений, таких как MongoDB с mongodump и mongoexport, не только утомительно, но и требует много времени и сложной настройки.
    • Базы данных SQLite упрощают это (это один файл).
    • Мы хотели разработать решение, при котором пользователи могли бы в любой момент забрать свой почтовый ящик и уйти.
      • Простые команды Node.js, такие как fs.unlink('mailbox.sqlite')), и файл навсегда удалён с диска.
      • Аналогично мы можем использовать API совместимый с S3 с HTTP DELETE для лёгкого удаления снимков и резервных копий пользователей.
    • SQLite было самым простым, быстрым и экономичным решением.

Отсутствие альтернатив

Насколько нам известно, ни один другой почтовый сервис не построен таким образом и не является открытым исходным кодом.

Мы думаем, что это может быть связано с тем, что существующие почтовые сервисы используют устаревшие технологии в продакшене с спагетти-кодом 🍝.

Большинство, если не все, существующих провайдеров почтовых услуг либо закрыты, либо позиционируются как открытые, но на самом деле только их фронтенд является открытым исходным кодом.

Самая чувствительная часть электронной почты (фактическое хранение/взаимодействие с IMAP/SMTP) выполняется на бэкенде (сервере), а не на фронтенде (клиенте).

Попробуйте Forward Email

Зарегистрируйтесь сегодня на https://forwardemail.net! 🚀