Tìm hiểu sâu: Cách chúng tôi sử dụng hộp thư SQLite được mã hóa an toàn lượng tử cho dịch vụ email bảo mật và tập trung vào quyền riêng tư của chúng tôi

Không giống như các dịch vụ email khác , chúng tôi đảm bảo rằng chỉ bạn mới có quyền truy cập vào hộp thư của mình mọi lúc.

Lời tựa

tldr; Dịch vụ email của chúng tôi là 100% nguồn mở và tập trung vào quyền riêng tư thông qua các hộp thư SQLite an toàn và được mã hóa.

Cho đến khi chúng tôi ra mắt Hỗ trợ IMAP, chúng tôi đã sử dụng MongoDB cho nhu cầu lưu trữ dữ liệu liên tục của mình.

Công nghệ này thật tuyệt vời và chúng tôi vẫn sử dụng nó cho đến ngày nay – nhưng để mã hóa ổn định với MongoDB, bạn cần sử dụng nhà cung cấp cung cấp MongoDB Enterprise, chẳng hạn như Digital Ocean hoặc Mongo Atlas – hoặc trả tiền cho giấy phép doanh nghiệp (và sau đó phải làm việc với độ trễ của đội ngũ bán hàng).

Đội ngũ của chúng tôi tại Chuyển tiếp email cần một giải pháp lưu trữ được mã hóa, có thể mở rộng, đáng tin cậy và thân thiện với nhà phát triển cho hộp thư IMAP. Với tư cách là nhà phát triển nguồn mở, việc sử dụng công nghệ mà bạn cần phải trả phí cấp phép để có được tính năng mã hóa ở trạng thái lưu trữ là điều trái ngược. nguyên tắc của chúng tôi – và vì vậy chúng tôi đã thử nghiệm, nghiên cứu và phát triển một giải pháp mới từ đầu để giải quyết những nhu cầu này.

Thay vì sử dụng cơ sở dữ liệu dùng chung để lưu trữ hộp thư của bạn, chúng tôi lưu trữ và mã hóa riêng hộp thư của bạn bằng mật khẩu (chỉ bạn mới có). Dịch vụ email của chúng tôi an toàn đến mức nếu bạn quên mật khẩu, bạn sẽ mất hộp thư (và cần khôi phục bằng bản sao lưu ngoại tuyến hoặc bắt đầu lại).

Hãy tiếp tục đọc khi chúng tôi đi sâu vào bên dưới với so sánh các nhà cung cấp dịch vụ email, dịch vụ của chúng tôi hoạt động như thế nào, kho công nghệ của chúng tôi, và hơn thế nữa.

So sánh nhà cung cấp dịch vụ email

Chúng tôi là nhà cung cấp dịch vụ email tập trung vào quyền riêng tư và mã nguồn mở 100% duy nhất lưu trữ các hộp thư SQLite được mã hóa riêng lẻ, cung cấp miền, bí danh và người dùng không giới hạn, đồng thời có hỗ trợ SMTP, IMAP và POP3 gửi đi:

Không giống như các nhà cung cấp email khác, bạn không cần phải trả tiền cho dung lượng lưu trữ trên cơ sở từng tên miền hoặc bí danh bằng Email chuyển tiếp. Dung lượng được chia sẻ trên toàn bộ tài khoản của bạn – vì vậy nếu bạn có nhiều tên miền tùy chỉnh và nhiều bí danh trên mỗi tên miền thì chúng tôi là giải pháp hoàn hảo dành cho bạn. Lưu ý rằng bạn vẫn có thể thực thi giới hạn bộ nhớ nếu muốn trên cơ sở từng miền hoặc bí danh.

Đọc So sánh Dịch vụ Email

Làm thế nào nó hoạt động

  1. Sử dụng ứng dụng email khách của bạn như Apple Mail, Thunderbird, Gmail hoặc Outlook – bạn kết nối với hệ thống bảo mật của chúng tôi IMAP máy chủ sử dụng tên người dùng và mật khẩu của bạn:

    • Tên người dùng của bạn là bí danh đầy đủ của bạn với tên miền của bạn, chẳng hạn như hello@example.com.
    • Mật khẩu của bạn được tạo ngẫu nhiên và chỉ hiển thị cho bạn trong 30 giây khi bạn nhấp vào Tạo mật khẩu từ Tài khoản của tôi Tên miền Bí danh.
  2. Sau khi kết nối, ứng dụng email của bạn sẽ gửi Các lệnh giao thức IMAP tới máy chủ IMAP của chúng tôi để giữ cho hộp thư của bạn được đồng bộ hóa. Điều này bao gồm viết và lưu trữ email nháp cũng như các hành động khác mà bạn có thể thực hiện (ví dụ: gắn nhãn email là Quan trọng hoặc gắn cờ email là Thư rác/Thư rác).

  3. Máy chủ trao đổi thư (thường được gọi là máy chủ "MX") nhận email gửi đến mới và lưu trữ vào hộp thư của bạn. Khi điều này xảy ra, ứng dụng email của bạn sẽ nhận được thông báo và đồng bộ hóa hộp thư của bạn. Máy chủ trao đổi thư của chúng tôi có thể chuyển tiếp email của bạn đến một hoặc nhiều người nhận (bao gồm cả webhook), lưu trữ email cho bạn trong bộ lưu trữ IMAP được mã hóa của bạn với chúng tôi, hoặc cả hai!

    Bạn muốn tìm hiểu thêm? Đọc cách thiết lập chuyển tiếp email, dịch vụ trao đổi thư của chúng tôi hoạt động như thế nào, hoặc xem hướng dẫn của chúng tôi.

  4. Đằng sau hậu trường, thiết kế lưu trữ email an toàn của chúng tôi hoạt động theo hai cách để giữ cho hộp thư của bạn được mã hóa và chỉ bạn mới có thể truy cập được:

    • Khi người gửi nhận được thư mới cho bạn, máy chủ trao đổi thư của chúng tôi sẽ ghi vào hộp thư cá nhân, tạm thời và được mã hóa cho bạn.

      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!
      
    • Khi bạn kết nối với máy chủ IMAP của chúng tôi bằng ứng dụng email của mình, mật khẩu của bạn sẽ được mã hóa trong bộ nhớ và được sử dụng để đọc và ghi vào hộp thư của bạn. Hộp thư của bạn chỉ có thể được đọc và ghi bằng mật khẩu này. Hãy nhớ rằng vì bạn là người duy nhất có mật khẩu này, Chỉ có bạn có thể đọc và ghi vào hộp thư của bạn khi bạn truy cập vào nó. Lần tới khi ứng dụng email của bạn cố gắng thăm dò thư hoặc đồng bộ hóa, thư mới của bạn sẽ được chuyển từ hộp thư tạm thời này và được lưu trữ trong tệp hộp thư thực tế bằng mật khẩu bạn đã cung cấp. Lưu ý rằng hộp thư tạm thời này sẽ bị xóa sạch và xóa sau đó để chỉ hộp thư được bảo vệ bằng mật khẩu của bạn mới có thư.

    • Nếu bạn được kết nối với IMAP (ví dụ: sử dụng ứng dụng email như Apple Mail hoặc Thunderbird), thì chúng tôi không cần ghi vào bộ lưu trữ đĩa tạm thời. Thay vào đó, mật khẩu IMAP được mã hóa trong bộ nhớ của bạn sẽ được tìm nạp và sử dụng. Trong thời gian thực, khi một tin nhắn đang cố gắng được gửi đến bạn, chúng tôi sẽ gửi yêu cầu WebSocket tới tất cả các máy chủ IMAP để hỏi xem họ có phiên hoạt động nào cho bạn không (đây là phần tìm nạp) và sau đó sẽ chuyển tiếp yêu cầu đó mật khẩu trong bộ nhớ được mã hóa – vì vậy chúng tôi không cần ghi vào hộp thư tạm thời, chúng tôi có thể ghi vào hộp thư được mã hóa thực tế bằng mật khẩu được mã hóa của bạn.

      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. Sao lưu các hộp thư được mã hóa của bạn được thực hiện hàng ngày. Bạn cũng có thể yêu cầu bản sao lưu mới bất kỳ lúc nào hoặc tải xuống bản sao lưu mới nhất từ Tài khoản của tôi Tên miền Bí danh. Nếu bạn quyết định chuyển sang một dịch vụ email khác thì bạn có thể dễ dàng di chuyển, tải xuống, xuất và xóa hộp thư cũng như bản sao lưu của mình bất kỳ lúc nào.

Công nghệ

Cơ sở dữ liệu

Chúng tôi đã khám phá các lớp lưu trữ cơ sở dữ liệu có thể có khác, tuy nhiên không có lớp nào đáp ứng yêu cầu của chúng tôi nhiều như SQLite đã làm:

Cơ sở dữ liệuMã hóa ở trạng thái nghỉĐược đóng hộp cát Hộp thưGiấy phépĐược sử dụng ở mọi nơi
SQLite✅ Có với SQLite3MultipleCipher✅ Miền công cộng
MongoDB"Chỉ có trong MongoDB Enterprise"❌ Cơ sở dữ liệu quan hệ❌ AGPL và SSPL-1.0
rqliteChỉ mạng❌ Cơ sở dữ liệu quan hệMIT
dqliteChưa được kiểm tra và chưa được hỗ trợ?Chưa được kiểm tra và chưa được hỗ trợ?LGPL-3.0-only
PostgreSQLĐúng❌ Cơ sở dữ liệu quan hệPostgreSQL (tương tự như BSD hoặc MIT)
MariaDBChỉ dành cho InnoDB❌ Cơ sở dữ liệu quan hệGPLv2BUSL-1.1
GiánDBTính năng chỉ dành cho doanh nghiệp❌ Cơ sở dữ liệu quan hệBUSL-1.1 và những người khác

Đây là bài đăng blog so sánh một số tùy chọn lưu trữ cơ sở dữ liệu SQLite trong bảng trên.

Bảo vệ

Lúc nào chúng tôi cũng sử dụng mã hóa ở trạng thái nghỉ ngơi (AES-256), mã hóa trong quá trình chuyển tiếp (TLS), DNS qua HTTPS ("DoH") sử dụng 🍊 Quýt, Và mưa đá (ChaCha20-Poly1305) mã hóa trên hộp thư. Ngoài ra, chúng tôi sử dụng xác thực hai yếu tố dựa trên mã thông báo (trái ngược với SMS có thể bị nghi ngờ là cuộc tấn công trung gian), khóa SSH được xoay vòng với quyền truy cập root bị vô hiệu hóa, quyền truy cập độc quyền vào máy chủ thông qua các địa chỉ IP bị hạn chế, v.v.

Trong trường hợp có một cuộc tấn công của cô hầu gái độc ác hoặc nhân viên lừa đảo từ nhà cung cấp bên thứ ba, hộp thư của bạn vẫn chỉ có thể được mở bằng mật khẩu bạn đã tạo. Hãy yên tâm, chúng tôi không dựa vào bất kỳ nhà cung cấp bên thứ ba nào ngoài nhà cung cấp máy chủ khiếu nại SOC Loại 2 của Cloudflare, Digital Ocean và Vultr.

Mục tiêu của chúng tôi là có càng ít điểm duy nhất của sự cố càng tốt.

Hộp thư

tldr; Máy chủ IMAP của chúng tôi sử dụng cơ sở dữ liệu SQLite được mã hóa riêng cho từng hộp thư của bạn.

SQLite là một công cụ cực kỳ phổ biến cơ sở dữ liệu nhúng – hiện đang chạy trên điện thoại và máy tính của bạn – và được sử dụng bởi gần như tất cả các công nghệ chính.

Ví dụ: trên các máy chủ được mã hóa của chúng tôi có hộp thư cơ sở dữ liệu SQLite dành cho linux@example.com, info@example.com, hello@example.com v.v. - mỗi người một cái như một .sqlite tập tin cơ sở dữ liệu. Chúng tôi cũng không đặt tên cho các tệp cơ sở dữ liệu bằng địa chỉ email – thay vào đó, chúng tôi sử dụng BSON ObjectID và UUID duy nhất được tạo để không chia sẻ hộp thư thuộc về ai hoặc địa chỉ email nào nằm trong đó (ví dụ: 353a03f21e534321f5d6e267.sqlite).

Mỗi cơ sở dữ liệu này đều được mã hóa bằng mật khẩu của bạn (chỉ bạn mới có) bằng cách sử dụng mưa đá (ChaCha20-Poly1305). Điều này có nghĩa là hộp thư của bạn được mã hóa riêng lẻ, khép kín, đóng hộp cát, và di động.

Chúng tôi đã tinh chỉnh SQLite như sau PRAGMA:

PRAGMAMục đích
cipher=chacha20Mã hóa cơ sở dữ liệu SQLite ChaCha20-Poly1305. Thẩm quyền giải quyết better-sqlite3-multiple-ciphers dưới Dự án để biết thêm thông tin chi tiết.
key="****************"Đây là mật khẩu duy nhất trong bộ nhớ đã được giải mã của bạn và được chuyển qua kết nối IMAP của ứng dụng email của bạn tới máy chủ của chúng tôi. Các phiên bản cơ sở dữ liệu mới được tạo và đóng cho mỗi phiên đọc và ghi (để đảm bảo hộp cát và cách ly).
journal_model=WALViết trước-nhật ký ("WAL") giúp tăng hiệu suất và cho phép truy cập đọc đồng thời.
busy_timeout=5000Ngăn chặn lỗi khóa ghi trong khi các hoạt động viết khác đang diễn ra.
synchronous=NORMALTăng độ bền của giao dịch không có nguy cơ tham nhũng dữ liệu.
foreign_keys=ONBuộc thực thi các tham chiếu khóa ngoài (ví dụ: mối quan hệ từ bảng này với bảng khác). Theo mặc định, tính năng này không được bật trong SQLite, nhưng để xác thực và toàn vẹn dữ liệu, nó phải được bật.
encoding='UTF-8'Mã hóa mặc định để sử dụng nhằm đảm bảo sự tỉnh táo của nhà phát triển.

Tất cả các giá trị mặc định khác là từ SQLite như được chỉ định từ tài liệu PRAGMA chính thức.

Đồng thời

tldr; Chúng tôi sử dụng rcloneWebSocket để đọc và ghi đồng thời vào hộp thư SQLite được mã hóa của bạn.

Đọc

Ứng dụng email khách trên điện thoại của bạn có thể giải quyết imap.forwardemail.net tới một trong các địa chỉ IP Digital Ocean của chúng tôi - và máy khách để bàn của bạn có thể phân giải một IP riêng biệt từ một địa chỉ IP khác các nhà cung cấp toàn bộ.

Bất kể ứng dụng email khách của bạn kết nối với máy chủ IMAP nào, chúng tôi muốn kết nối đọc từ cơ sở dữ liệu của bạn trong thời gian thực với độ chính xác 100%:

  • Điều này được thực hiện bằng cách sử dụng rclone với --vfs-cache-mode off (mặc định).

  • Thay vì sử dụng bộ đệm đĩa cục bộ, bộ đệm được đọc trực tiếp từ thiết bị gắn từ xa (cơ sở dữ liệu của bạn) trong thời gian thực.

  • Trong trường hợp không thể tìm thấy tệp cục bộ, điều này cho biết rằng rclone không gắn kết được hoặc có vấn đề. Trong trường hợp này chúng tôi sử dụng một WebSocket dự phòng cho các lần đọc (làm giảm hiệu suất một chút nhưng vẫn duy trì tính toàn vẹn của dịch vụ).

  • Mỗi máy chủ của chúng tôi được định cấu hình để gắn kết một cách nhất quán và cảnh báo cho chúng tôi theo thời gian thực về bất kỳ lỗi nào.

viết

Việc ghi vào cơ sở dữ liệu của bạn hơi khác một chút – vì SQLite là cơ sở dữ liệu được nhúng và hộp thư của bạn nằm trong một tệp duy nhất theo mặc định.

Chúng tôi đã khám phá các lựa chọn như litestream, rqlite, Và dqlite bên dưới – tuy nhiên không có cái nào trong số này thỏa mãn yêu cầu của chúng tôi.

Để thực hiện việc ghi bằng cách ghi nhật ký ghi trước ("WAL") được bật – chúng tôi cần đảm bảo rằng chỉ có một máy chủ ("Chính") chịu trách nhiệm thực hiện việc đó. WAL tăng tốc đáng kể sự đồng thời và cho phép một người viết và nhiều người đọc.

Primary đang chạy trên các máy chủ dữ liệu với các ổ đĩa được gắn chứa các hộp thư được mã hóa. Từ quan điểm phân phối, bạn có thể xem xét tất cả các máy chủ IMAP riêng lẻ đằng sau imap.forwardemail.net làm máy chủ phụ ("Phụ").

Chúng tôi thực hiện giao tiếp hai chiều với WebSockets:

  • Các máy chủ chính sử dụng một phiên bản của 'S WebSocketServer máy chủ.
  • Máy chủ thứ cấp sử dụng một phiên bản của 'S WebSocket khách hàng được gói bằng websocket-như đã hứakết nối lại-websocket. Hai trình bao bọc này đảm bảo rằng WebSocket kết nối lại và có thể gửi và nhận dữ liệu để ghi cơ sở dữ liệu cụ thể.

Sao lưu

tldr; Việc sao lưu các hộp thư mã hóa của bạn được thực hiện hàng ngày. Bạn cũng có thể yêu cầu ngay bản sao lưu mới hoặc tải xuống bản sao lưu mới nhất bất kỳ lúc nào từ Tài khoản của tôi Tên miền Bí danh.

Để sao lưu, chúng tôi chỉ cần chạy SQLite VACUUM INTO lệnh mỗi ngày trong quá trình xử lý lệnh IMAP, tận dụng mật khẩu được mã hóa của bạn từ kết nối IMAP trong bộ nhớ. Các bản sao lưu được lưu trữ nếu không phát hiện thấy bản sao lưu hiện có hoặc nếu SHA-256 hàm băm đã thay đổi trên tệp so với bản sao lưu gần đây nhất.

Lưu ý rằng chúng tôi sử dụng VACUUM INTO lệnh trái ngược với lệnh tích hợp backup lệnh vì nếu một trang được sửa đổi trong quá trình backup lệnh hoạt động, sau đó nó phải bắt đầu lại. Các VACUUM INTO lệnh sẽ chụp ảnh nhanh. Xem những nhận xét này trên GitHubtin tức hacker để biết thêm thông tin chi tiết.

Ngoài ra chúng tôi sử dụng VACUUM INTO như trái ngược với backup, bởi vì backup lệnh sẽ khiến cơ sở dữ liệu không được mã hóa trong một khoảng thời gian ngắn cho đến khi rekey được gọi (xem GitHub này bình luận để có cái nhìn sâu sắc).

Khối Trung học sẽ hướng dẫn Tiểu học về WebSocket kết nối để thực hiện sao lưu – và sau đó Chính sẽ nhận được lệnh để thực hiện việc đó và sau đó sẽ:

  1. Kết nối với hộp thư được mã hóa của bạn.
  2. Có được một khóa ghi.
  3. Chạy điểm kiểm tra WAL thông qua wal_checkpoint(PASSIVE).
  4. Chạy VACUUM INTO Lệnh SQLite.
  5. Đảm bảo rằng tệp đã sao chép có thể được mở bằng mật khẩu được mã hóa (bảo vệ/chống giả).
  6. Tải nó lên Cloudflare R2 để lưu trữ (hoặc nhà cung cấp của riêng bạn nếu được chỉ định).
  7. Nén tập tin sao lưu kết quả với gzip.
  8. Tải nó lên Cloudflare R2 để lưu trữ (hoặc nhà cung cấp của riêng bạn nếu được chỉ định).

Hãy nhớ rằng hộp thư của bạn được mã hóa – và mặc dù chúng tôi áp dụng các hạn chế IP và các biện pháp xác thực khác cho giao tiếp WebSocket – trong trường hợp có tác nhân xấu, bạn có thể yên tâm rằng trừ khi tải trọng WebSocket có mật khẩu IMAP của bạn, nó không thể mở cơ sở dữ liệu của bạn .

Tại thời điểm này, chỉ có một bản sao lưu được lưu trữ cho mỗi hộp thư, nhưng trong tương lai chúng tôi có thể cung cấp tính năng khôi phục tại thời điểm ("PITR").

Máy chủ IMAP của chúng tôi hỗ trợ SEARCH lệnh với các truy vấn phức tạp, biểu thức chính quy, v.v.

Hiệu suất tìm kiếm nhanh là nhờ FTS5sqlite-regex.

Chúng tôi lưu trữ Date các giá trị trong hộp thư SQLite như ISO 8601 dây qua Date.prototype.toISOString (với múi giờ UTC để so sánh đẳng thức hoạt động bình thường).

Các chỉ số cũng được lưu trữ cho tất cả các thuộc tính có trong truy vấn tìm kiếm.

Dự án

Đây là bảng phác thảo các dự án chúng tôi sử dụng trong mã nguồn và quy trình phát triển của mình (được sắp xếp theo thứ tự bảng chữ cái):

Dự ánMục đích
AnsibleNền tảng tự động hóa DevOps để duy trì, mở rộng quy mô và quản lý toàn bộ nhóm máy chủ của chúng tôi một cách dễ dàng.
BreeTrình lên lịch công việc cho Node.js và JavaScript với cron, ngày tháng, ms, muộn hơn và hỗ trợ thân thiện với con người.
CabinThư viện ghi nhật ký JavaScript và Node.js thân thiện với nhà phát triển với tính bảo mật và quyền riêng tư.
Thanh niênKhung công tác Node.js hỗ trợ toàn bộ kiến trúc và thiết kế kỹ thuật của chúng tôi với MVC và hơn thế nữa.
MongoDBGiải pháp cơ sở dữ liệu NoSQL mà chúng tôi sử dụng để lưu trữ tất cả dữ liệu khác bên ngoài hộp thư (ví dụ: tài khoản, cài đặt, tên miền và cấu hình bí danh của bạn).
cầy mangutMô hình hóa tài liệu đối tượng MongoDB ("ODM") mà chúng tôi sử dụng trên toàn bộ ngăn xếp của mình. Chúng tôi đã viết những người trợ giúp đặc biệt cho phép chúng tôi tiếp tục sử dụng Cầy mangut với SQLite 🎉
Node.jsNode.js là môi trường thời gian chạy JavaScript đa nền tảng, mã nguồn mở, chạy tất cả các quy trình máy chủ của chúng tôi.
Người gửi thư ghi chúGói Node.js để gửi email, tạo kết nối, v.v. Chúng tôi là nhà tài trợ chính thức cho dự án này.
làm lạiCơ sở dữ liệu trong bộ nhớ để lưu vào bộ nhớ đệm, xuất bản/đăng ký kênh và yêu cầu DNS qua HTTPS.
SQLite3MultipleCipherTiện ích mở rộng mã hóa cho SQLite để cho phép mã hóa toàn bộ tệp cơ sở dữ liệu (bao gồm cả nhật ký ghi trước ("WAL"), nhật ký, khôi phục,…).
SQLiteStudioTrình soạn thảo SQLite trực quan (bạn cũng có thể sử dụng) để kiểm tra, tải xuống và xem các hộp thư phát triển.
SQLiteLớp cơ sở dữ liệu nhúng để lưu trữ IMAP có thể mở rộng, khép kín, nhanh chóng và linh hoạt.
Máy quét thư rácCông cụ chống thư rác, lọc email và ngăn chặn lừa đảo của Node.js (giải pháp thay thế của chúng tôi cho Sát thủ thư rácthư rác).
QuýtYêu cầu DNS qua HTTPS với Node.js và bộ nhớ đệm bằng Redis – đảm bảo tính nhất quán toàn cầu và hơn thế nữa.
ThunderbirdNhóm phát triển của chúng tôi sử dụng điều này (và cũng đề xuất điều này) làm ứng dụng email ưa thích để sử dụng với Email chuyển tiếp.
UTMNhóm phát triển của chúng tôi sử dụng máy ảo tạo cho iOS và macOS này để kiểm tra các ứng dụng email khác nhau (song song) với máy chủ IMAP và SMTP của chúng tôi.
UbuntuHệ điều hành máy chủ dựa trên Linux nguồn mở hiện đại hỗ trợ tất cả cơ sở hạ tầng của chúng tôi.
Vịt trờiThư viện máy chủ IMAP – xem ghi chú của nó trên khử trùng lặp tệp đính kèmHỗ trợ giao thức IMAP.
tốt hơn-sqlite3-nhiều-mật mãThư viện API nhanh và đơn giản để Node.js tương tác với SQLite3 theo chương trình.
mẫu thư điện tửKhung email thân thiện với nhà phát triển để tạo, xem trước và gửi email tùy chỉnh (ví dụ: thông báo tài khoản và hơn thế nữa).
json-sqlTrình tạo truy vấn SQL sử dụng cú pháp kiểu Mongo. Điều này giúp nhóm phát triển của chúng tôi tiết kiệm thời gian vì chúng tôi có thể tiếp tục viết theo kiểu Mongo trên toàn bộ ngăn xếp bằng cách tiếp cận bất khả tri về cơ sở dữ liệu. Nó cũng giúp tránh các cuộc tấn công tiêm nhiễm SQL bằng cách sử dụng các tham số truy vấn.
knex-schema-thanh traTiện ích SQL để trích xuất thông tin về lược đồ cơ sở dữ liệu hiện có. Điều này cho phép chúng tôi dễ dàng xác thực rằng tất cả các chỉ mục, bảng, cột, ràng buộc, v.v. đều hợp lệ và 1:1 với việc chúng phải như thế nào. Chúng tôi thậm chí còn viết các trình trợ giúp tự động để thêm các cột và chỉ mục mới nếu có thay đổi đối với lược đồ cơ sở dữ liệu (có cả cảnh báo lỗi cực kỳ chi tiết).
knexTrình tạo truy vấn SQL mà chúng tôi chỉ sử dụng để di chuyển cơ sở dữ liệu và xác thực lược đồ thông qua knex-schema-inspector.
Quan thoạiTự động i18n dịch cụm từ có hỗ trợ Markdown bằng cách sử dụng API dịch thuật trên đám mây của Google.
kết nối mxGói Node.js để giải quyết và thiết lập kết nối với máy chủ MX và xử lý lỗi.
chiều2Trình quản lý quy trình sản xuất Node.js có bộ cân bằng tải tích hợp (tinh chỉnh để thực hiện).
máy chủ SMTPThư viện máy chủ SMTP – chúng tôi sử dụng thư viện này để trao đổi thư ("MX") và máy chủ SMTP gửi đi.
ImapTestCông cụ hữu ích để kiểm tra máy chủ IMAP dựa trên điểm chuẩn và khả năng tương thích giao thức IMAP đặc tả RFC. Dự án này được tạo ra bởi chuồng bồ câu nhóm (một máy chủ IMAP và POP3 mã nguồn mở đang hoạt động từ tháng 7 năm 2002). Chúng tôi đã thử nghiệm rộng rãi máy chủ IMAP của mình bằng công cụ này.

Bạn có thể tìm thấy các dự án khác mà chúng tôi sử dụng trong mã nguồn của chúng tôi trên GitHub.

Nhà cung cấp

Các nhà cung cấpMục đích
Đám mây bùng phátNhà cung cấp DNS, kiểm tra tình trạng, cân bằng tải và lưu trữ sao lưu bằng cách sử dụng Đám mây R2.
Đại dương kỹ thuật sốLưu trữ máy chủ chuyên dụng, lưu trữ khối SSD và cơ sở dữ liệu được quản lý.
VultrLưu trữ máy chủ chuyên dụng và lưu trữ khối SSD.

Suy nghĩ

Nguyên tắc

Forward Email được thiết kế theo những nguyên tắc sau:

  1. Luôn thân thiện với nhà phát triển, tập trung vào bảo mật và quyền riêng tư cũng như minh bạch.
  2. Tuân thủ MVC, Unix, KISS, DRY, YAGNI, Yếu tố thứ mười hai, dao cạo Occam, Và ăn thịt chó
  3. Nhắm mục tiêu phế liệu, bootstrapped và ramen có lãi nhà phát triển

Thí nghiệm

tldr; Cuối cùng, việc sử dụng bộ lưu trữ đối tượng tương thích với S3 và/hoặc Bảng ảo là không khả thi về mặt kỹ thuật vì lý do hiệu suất và dễ xảy ra lỗi do hạn chế về bộ nhớ.

Chúng tôi đã thực hiện một số thử nghiệm dẫn đến giải pháp SQLite cuối cùng như đã thảo luận ở trên.

Một trong số đó là thử sử dụng nhân bản và SQLite cùng với lớp lưu trữ tương thích với S3.

Thử nghiệm đó đã giúp chúng tôi hiểu sâu hơn và khám phá các trường hợp đặc biệt xung quanh rclone, SQLite và VFS cách sử dụng:

  • Nếu bạn kích hoạt --vfs-cache-mode writes gắn cờ bằng rclone thì việc đọc sẽ ổn, tuy nhiên việc ghi sẽ được lưu vào bộ đệm.
    • Nếu bạn có nhiều máy chủ IMAP được phân phối trên toàn cầu thì bộ đệm sẽ bị tắt trên chúng trừ khi bạn có một trình ghi và nhiều trình nghe (ví dụ: cách tiếp cận pub/sub).
    • Điều này cực kỳ phức tạp và việc thêm bất kỳ sự phức tạp bổ sung nào như thế này sẽ dẫn đến nhiều điểm lỗi đơn lẻ hơn.
    • Các nhà cung cấp dịch vụ lưu trữ tương thích với S3 không hỗ trợ thay đổi một phần tệp – có nghĩa là bất kỳ thay đổi nào về .sqlite tập tin sẽ dẫn đến thay đổi hoàn toàn và tải lên lại cơ sở dữ liệu.
    • Các giải pháp khác như rsync tồn tại, nhưng chúng không tập trung vào ghi-trước-log ("WAL") hỗ trợ – vì vậy cuối cùng chúng tôi đã xem xét Litestream. May mắn thay, việc sử dụng mã hóa của chúng tôi đã mã hóa WAL các tệp cho chúng tôi, vì vậy chúng tôi không cần phải dựa vào Litestream để làm việc đó. Tuy nhiên, chúng tôi chưa tin tưởng vào Litestream cho mục đích sử dụng sản xuất và có một số lưu ý bên dưới về điều đó.
    • Sử dụng tùy chọn này của --vfs-cache-mode writes (các chỉ một cách sử dụng SQLite rclone để ghi) sẽ cố gắng sao chép toàn bộ cơ sở dữ liệu từ đầu trong bộ nhớ – việc xử lý một hộp thư 10 GB là được, tuy nhiên việc xử lý nhiều hộp thư có dung lượng lưu trữ quá cao sẽ khiến máy chủ IMAP gặp phải các hạn chế về bộ nhớ và ENOMEM lỗi, lỗi phân đoạn và hỏng dữ liệu.
  • Nếu bạn cố gắng sử dụng SQLite Bàn ảo (ví dụ: sử dụng s3db) để có dữ liệu trực tiếp trên lớp lưu trữ tương thích với S3 thì bạn sẽ gặp phải một số vấn đề khác:
    • Đọc và ghi sẽ cực kỳ chậm vì các điểm cuối API S3 sẽ cần phải được truy cập bằng HTTP GET, PUT, HEAD, Và POST phương pháp.
    • Các thử nghiệm phát triển cho thấy việc vượt quá 500K-1M+ bản ghi trên Internet cáp quang vẫn bị hạn chế bởi thông lượng ghi và đọc đối với các nhà cung cấp tương thích với S3. Ví dụ: các nhà phát triển của chúng tôi đã chạy for các vòng lặp để thực hiện cả SQL tuần tự INSERT các câu lệnh và những câu lệnh viết số lượng lớn dữ liệu. Trong cả hai trường hợp, hiệu suất đều chậm một cách đáng kinh ngạc.
    • Bảng ảo không thể có chỉ mục, ALTER TABLE các tuyên bố và khác hạn chế – dẫn đến độ trễ lên tới 1-2 phút hoặc hơn tùy thuộc vào lượng dữ liệu.
    • Các đối tượng được lưu trữ không được mã hóa và không có sẵn hỗ trợ mã hóa gốc.
  • Chúng tôi cũng khám phá bằng cách sử dụng sqlite-s3vfs tương tự về mặt khái niệm và kỹ thuật với điểm đầu dòng trước đó (vì vậy nó có cùng vấn đề). Một khả năng có thể là sử dụng một tùy chỉnh sqlite3 xây dựng được bao bọc bằng mã hóa như wxSQLite3 (mà chúng tôi hiện đang sử dụng trong giải pháp của mình ở trên) thông qua chỉnh sửa tập tin cài đặt.
  • Một cách tiếp cận tiềm năng khác là sử dụng phần mở rộng đa kênh, tuy nhiên, điều này có giới hạn là 32 GB và sẽ khiến việc xây dựng và phát triển trở nên phức tạp.
  • ALTER TABLE các câu lệnh là bắt buộc (vì vậy điều này hoàn toàn loại trừ việc sử dụng Bảng ảo). Chúng tôi cần ALTER TABLE các câu lệnh để chúng ta có thể kết nối với knex-schema-inspector hoạt động bình thường – điều này đảm bảo rằng dữ liệu không bị hỏng và các hàng được truy xuất có thể được chuyển đổi thành tài liệu hợp lệ theo yêu cầu của chúng tôi mongoose định nghĩa lược đồ (bao gồm ràng buộc, loại biến và xác thực dữ liệu tùy ý).
  • Hầu hết tất cả các dự án tương thích với S3 liên quan đến SQLite trong cộng đồng nguồn mở đều bằng Python (chứ không phải JavaScript mà chúng tôi sử dụng cho 100% ngăn xếp của mình).
  • Thư viện nén như sqlite-zstd (nhìn thấy bình luận) có vẻ đầy hứa hẹn, nhưng có thể chưa sẵn sàng để sử dụng sản xuất. Thay vào đó, việc nén phía ứng dụng trên các loại dữ liệu như String, Object, Map, Array, Set, Và Buffer sẽ là một cách tiếp cận rõ ràng và dễ dàng hơn (và cũng dễ di chuyển hơn vì chúng ta có thể lưu trữ một Boolean cờ hoặc cột – hoặc thậm chí sử dụng PRAGMA user_version=1 để nén hoặc user_version=0 không nén dưới dạng siêu dữ liệu cơ sở dữ liệu).
    • May mắn thay, chúng tôi đã triển khai tính năng khử trùng lặp tệp đính kèm trong bộ lưu trữ máy chủ IMAP của mình – do đó, mọi thư có cùng tệp đính kèm sẽ không giữ bản sao của tệp đính kèm – thay vào đó, một tệp đính kèm được lưu trữ cho nhiều thư và chuỗi trong hộp thư (và một tệp đính kèm bên ngoài). tài liệu tham khảo sau đó được sử dụng).
  • Dự án Litestream, một giải pháp sao lưu và sao lưu SQLite rất hứa hẹn và rất có thể chúng tôi sẽ sử dụng nó trong tương lai.
  • Việc khôi phục sao lưu cần phải diễn ra suôn sẻ và đơn giản. Sử dụng giải pháp như MongoDB với mongodumpmongoexport không chỉ tẻ nhạt mà còn tốn thời gian và cấu hình phức tạp.
    • Cơ sở dữ liệu SQLite làm cho việc này trở nên đơn giản (đó là một tệp duy nhất).
    • Chúng tôi muốn thiết kế một giải pháp trong đó người dùng có thể lấy hộp thư của mình và rời đi bất cứ lúc nào.
      • Các lệnh Node.js đơn giản để fs.unlink('mailbox.sqlite')) và nó bị xóa vĩnh viễn khỏi bộ nhớ đĩa.
      • Tương tự, chúng ta có thể sử dụng API tương thích với S3 với HTTP DELETE để dễ dàng loại bỏ ảnh chụp nhanh và bản sao lưu cho người dùng.
    • SQLite là giải pháp đơn giản nhất, nhanh nhất và tiết kiệm chi phí nhất.

Thiếu lựa chọn thay thế

Theo hiểu biết của chúng tôi, không có dịch vụ email nào khác được thiết kế theo cách này và chúng cũng không phải là nguồn mở.

Chúng tôi nghĩ rằng điều này có thể là do tới các dịch vụ email hiện có sử dụng công nghệ cũ đang được sản xuất với mã spaghetti 🍝.

Hầu hết nếu không phải tất cả các nhà cung cấp dịch vụ email hiện tại đều là nguồn đóng hoặc quảng cáo dưới dạng nguồn mở, nhưng trên thực tế chỉ có giao diện người dùng của họ là nguồn mở.

Phần nhạy cảm nhất của email (tương tác lưu trữ/IMAP/SMTP thực tế) tất cả đều được thực hiện ở back-end (máy chủ) và không ở mặt trước (máy khách).

Hãy thử chuyển tiếp email

Đăng ký ngay hôm nay tại https://forwardemail.net! 🚀