อีเมลที่ทนทานต่อควอนตัม: วิธีที่เราใช้กล่องจดหมาย SQLite ที่เข้ารหัสเพื่อรักษาอีเมลของคุณให้ปลอดภัย

คำนำ
Important
บริการอีเมลของเราเป็นแบบ โอเพ่นซอร์ส 100% และเน้นความเป็นส่วนตัวผ่านกล่องจดหมาย SQLite ที่ปลอดภัยและเข้ารหัส
ก่อนที่เราจะเปิดตัว การรองรับ IMAP เราใช้ MongoDB สำหรับความต้องการจัดเก็บข้อมูลถาวรของเรา
เทคโนโลยีนี้น่าทึ่งมากและเรายังคงใช้มันอยู่จนถึงทุกวันนี้ แต่เพื่อให้มีการเข้ารหัสแบบไม่มีสะดุดกับ MongoDB คุณจะต้องใช้ผู้ให้บริการที่เสนอ MongoDB Enterprise เช่น Digital Ocean หรือ Mongo Atlas หรือจ่ายเงินสำหรับใบอนุญาตระดับองค์กร (และจากนั้นต้องทำงานกับความล่าช้าของทีมขาย)
ทีมงานของเราที่ ส่งต่ออีเมล์ ต้องการโซลูชันการจัดเก็บข้อมูลสำหรับกล่องจดหมาย 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:
ฐานข้อมูล | การเข้ารหัสขณะพัก | Sandboxed กล่องจดหมาย | ใบอนุญาต | Used Everywhere |
---|---|---|---|---|
SQLite :ดาว: | ✅ ใช่ด้วย SQLite3MultipleCiphers | :เครื่องหมายถูกสีขาว: | ✅ สาธารณสมบัติ | :เครื่องหมายถูกสีขาว: |
MongoDB | ❌ เซลล์_ลิงค์_0 | ❌ ฐานข้อมูลเชิงสัมพันธ์ | ❌ AGPL และ SSPL-1.0 |
❌ |
rqlite | ❌ เซลล์_ลิงค์_0 | ❌ ฐานข้อมูลเชิงสัมพันธ์ | :เครื่องหมายถูกสีขาว: รหัสเซลล์_0 | ❌ |
dqlite | ❌ เซลล์_ลิงค์_0 | ❌ เซลล์_ลิงค์_0 | :เครื่องหมายถูกสีขาว: รหัสเซลล์_0 | ❌ |
PostgreSQL | :เครื่องหมายถูกสีขาว: Yes | ❌ ฐานข้อมูลเชิงสัมพันธ์ | ✅ PostgreSQL (คล้ายกับ BSD หรือ MIT ) |
❌ |
MariaDB | :เครื่องหมายถูกสีขาว: For InnoDB only | ❌ ฐานข้อมูลเชิงสัมพันธ์ | ✅ GPLv2 และ BUSL-1.1 |
❌ |
CockroachDB | ❌ เซลล์_ลิงค์_0 | ❌ ฐานข้อมูลเชิงสัมพันธ์ | ❌ BUSL-1.1 และอื่นๆ |
❌ |
นี่คือ โพสต์บล็อกที่เปรียบเทียบตัวเลือกการจัดเก็บฐานข้อมูล SQLite หลายตัว ในตารางด้านบน
ความปลอดภัย
เราใช้ การเข้ารหัสขณะพัก (AES-256), การเข้ารหัสระหว่างการขนส่ง (TLS), DNS ผ่าน HTTPS ("DoH") ตลอดเวลา โดยใช้การเข้ารหัส 🍊 ส้มแมนดาริน และ สแควร์ (ชาชา20-โพลี1305) บนกล่องจดหมาย นอกจากนี้ เรายังใช้การยืนยันตัวตนแบบสองปัจจัยโดยใช้โทเค็น (ต่างจาก SMS ซึ่ง การโจมตีแบบ man-in-the-middle สงสัยว่าเป็นไปได้) คีย์ SSH แบบหมุนเวียนที่ปิดใช้งานสิทธิ์การเข้าถึงรูท การเข้าถึงเซิร์ฟเวอร์แบบเอกสิทธิ์เฉพาะผ่านที่อยู่ IP ที่ถูกจำกัด และอื่นๆ อีกมากมาย
ในกรณีที่มี แม่บ้านชั่วร้ายโจมตี หรือพนักงานปลอมจากผู้ให้บริการบุคคลที่สาม กล่องจดหมายของคุณจะยังคงเปิดได้โดยใช้รหัสผ่านที่คุณสร้างขึ้นเท่านั้น โปรดมั่นใจว่าเราไม่ได้พึ่งพาผู้ให้บริการบุคคลที่สามใด ๆ นอกเหนือจากผู้ให้บริการเซิร์ฟเวอร์ร้องเรียน SOC ประเภท 2 ของเรา ได้แก่ Cloudflare, DataPacket, Digital Ocean และ Vultr
เป้าหมายของเราคือการมี จุดล้มเหลวเพียงจุดเดียว น้อยที่สุดเท่าที่จะเป็นไปได้
กล่องจดหมาย
tldr; เซิร์ฟเวอร์ IMAP ของเราใช้ฐานข้อมูล SQLite ที่เข้ารหัสเฉพาะตัวสำหรับกล่องจดหมายแต่ละกล่องของคุณ
ฐานข้อมูลฝัง SQLite เป็นที่นิยมอย่างมาก – ขณะนี้กำลังทำงานอยู่บนโทรศัพท์และคอมพิวเตอร์ของคุณ – และถูกใช้โดยเทคโนโลยีหลักเกือบทั้งหมด
ตัวอย่างเช่น บนเซิร์ฟเวอร์ที่เข้ารหัสของเรามีกล่องจดหมายฐานข้อมูล SQLite สำหรับ linux@example.com
, info@example.com
, hello@example.com
และอื่นๆ โดยแต่ละไฟล์จะถูกสร้างเป็นไฟล์ฐานข้อมูล .sqlite
เราไม่ได้ตั้งชื่อไฟล์ฐานข้อมูลด้วยที่อยู่อีเมล แต่จะใช้ BSON ObjectID และ UUID เฉพาะที่สร้างขึ้น ซึ่งจะไม่แชร์ว่ากล่องจดหมายนั้นเป็นเจ้าของโดยใคร หรืออยู่ภายใต้ที่อยู่อีเมลใด (เช่น 353a03f21e534321f5d6e267.sqlite
)
ฐานข้อมูลเหล่านี้แต่ละฐานข้อมูลจะถูกเข้ารหัสด้วยรหัสผ่านของคุณ (ซึ่งคุณเท่านั้นที่มี) โดยใช้ สแควร์ (ชาชา20-โพลี1305) ซึ่งหมายความว่ากล่องจดหมายของคุณจะถูกเข้ารหัสแยกกัน เป็นแบบแยกส่วน [แซนด์บ็อกซ์](https://en.wikipedia.org/wiki/Sandbox_\(computer_security\) และพกพาได้
เราปรับแต่ง SQLite ด้วย PRAGMA ดังต่อไปนี้:
PRAGMA |
วัตถุประสงค์ |
---|---|
cipher=chacha20 |
ChaCha20-Poly1305 SQLite database encryption อ้างอิง better-sqlite3-multiple-ciphers ภายใต้ Projects เพื่อดูข้อมูลเชิงลึกเพิ่มเติม |
key="****************" |
นี่คือรหัสผ่านแบบ in-memory ที่คุณถอดรหัสแล้ว ซึ่งจะถูกส่งผ่านการเชื่อมต่อ IMAP ของไคลเอนต์อีเมลของคุณไปยังเซิร์ฟเวอร์ของเรา อินสแตนซ์ฐานข้อมูลใหม่จะถูกสร้างขึ้นและปิดลงสำหรับเซสชันการอ่านและเขียนแต่ละครั้ง (เพื่อให้แน่ใจว่ามีการแซนด์บ็อกซ์และการแยกข้อมูล) |
journal_model=WAL |
บันทึกการเขียนล่วงหน้า ("WAL") which boosts performance and allows concurrent read access |
busy_timeout=5000 |
ป้องกันข้อผิดพลาดการล็อคการเขียน while other writes are taking place |
synchronous=NORMAL |
เพิ่มความทนทานของธุรกรรม without data corruption risk. |
foreign_keys=ON |
บังคับใช้การอ้างอิงคีย์ต่างประเทศ (เช่น ความสัมพันธ์จากตารางหนึ่งไปยังอีกตารางหนึ่ง) By default this is not turned on in SQLite แต่สำหรับการตรวจสอบและความสมบูรณ์ของข้อมูล ควรเปิดใช้งาน |
encoding='UTF-8' |
Default encoding เพื่อใช้เพื่อให้แน่ใจว่านักพัฒนามีสุขภาพจิตดี |
ค่าเริ่มต้นอื่นๆ ทั้งหมดมาจาก SQLite ตามที่ระบุไว้ใน เอกสาร PRAGMA อย่างเป็นทางการ
การทำงานพร้อมกัน
tldr; เราใช้
WebSocket
สำหรับการอ่านและเขียนพร้อมกันไปยังกล่องจดหมาย SQLite ที่เข้ารหัสของคุณ
อ่าน
ไคลเอนต์อีเมลบนโทรศัพท์ของคุณอาจแก้ไข imap.forwardemail.net
เป็นหนึ่งในที่อยู่ IP ของ Digital Ocean ของเรา และไคลเอนต์เดสก์ท็อปของคุณอาจแก้ไข IP แยกจาก ผู้ให้บริการ ที่แตกต่างกันโดยสิ้นเชิง
ไม่ว่าไคลเอนต์อีเมลของคุณจะเชื่อมต่อกับเซิร์ฟเวอร์ IMAP ตัวใด เราต้องการให้การเชื่อมต่ออ่านข้อมูลจากฐานข้อมูลของคุณแบบเรียลไทม์ด้วยความแม่นยำ 100% ซึ่งทำได้ผ่าน WebSockets
เขียน
การเขียนลงในฐานข้อมูลของคุณนั้นแตกต่างออกไปเล็กน้อย เนื่องจาก SQLite เป็นฐานข้อมูลแบบฝังตัว และเมลบ็อกซ์ของคุณจะอยู่ในไฟล์เดียวตามค่าเริ่มต้น
เราได้สำรวจตัวเลือกต่างๆ เช่น litestream
, rqlite
และ dqlite
ด้านล่างนี้ อย่างไรก็ตาม ไม่มีตัวเลือกใดเลยที่ตอบสนองความต้องการของเรา
หากต้องการเขียนข้อมูลโดยเปิดใช้งาน write-ahead-logging ("WAL") เราต้องแน่ใจว่ามีเพียงเซิร์ฟเวอร์เดียว ("Primary") เท่านั้นที่รับผิดชอบการดำเนินการดังกล่าว WAL ช่วยเพิ่มความเร็วในการทำงานพร้อมกันอย่างมาก และอนุญาตให้มีผู้เขียนหนึ่งคนและผู้อ่านหลายคน
เซิร์ฟเวอร์หลักกำลังทำงานบนเซิร์ฟเวอร์ข้อมูลที่มีโวลุ่มที่เมาท์ซึ่งมีกล่องจดหมายที่เข้ารหัสอยู่ จากมุมมองของการกระจาย คุณสามารถพิจารณาเซิร์ฟเวอร์ IMAP แต่ละตัวที่อยู่เบื้องหลัง imap.forwardemail.net
ให้เป็นเซิร์ฟเวอร์รอง ("รอง") ได้
เราบรรลุการสื่อสารสองทางด้วย เว็บซ็อกเก็ต:
- เซิร์ฟเวอร์หลักใช้อินสแตนซ์ของเซิร์ฟเวอร์
WebSocketServer
ของ ดับบลิวเอส - เซิร์ฟเวอร์รองใช้อินสแตนซ์ของไคลเอ็นต์
WebSocket
ของ ดับบลิวเอส ซึ่งถูกรวมไว้ด้วย เว็บซ็อกเก็ตตามที่สัญญาไว้ และ การเชื่อมต่อเว็บซ็อกเก็ตใหม่ แรปเปอร์ทั้งสองนี้ช่วยให้มั่นใจว่าWebSocket
จะเชื่อมต่อใหม่อีกครั้ง และสามารถส่งและรับข้อมูลสำหรับการเขียนฐานข้อมูลเฉพาะได้
การสำรองข้อมูล
tldr; การสำรองข้อมูลกล่องจดหมายที่เข้ารหัสของคุณจะดำเนินการทุกวัน คุณยังสามารถขอการสำรองข้อมูลใหม่ได้ทันทีหรือดาวน์โหลดการสำรองข้อมูลล่าสุดได้ตลอดเวลาจาก บัญชีของฉัน โดเมน นามแฝง
สำหรับการสำรองข้อมูล เราเพียงรันคำสั่ง SQLite VACUUM INTO
ทุกวันระหว่างการประมวลผลคำสั่ง IMAP ซึ่งใช้ประโยชน์จากรหัสผ่านที่เข้ารหัสของคุณจากการเชื่อมต่อ IMAP ในหน่วยความจำ การสำรองข้อมูลจะถูกเก็บไว้หากไม่พบข้อมูลสำรองที่มีอยู่ หรือหากแฮช SHA-256 ในไฟล์มีการเปลี่ยนแปลงเมื่อเทียบกับการสำรองข้อมูลครั้งล่าสุด
โปรดทราบว่าเราใช้คำสั่ง VACUUM INTO
แทนคำสั่ง backup
ในตัว เพราะหากมีการแก้ไขหน้าระหว่างการดำเนินการคำสั่ง backup
จะต้องเริ่มต้นใหม่ คำสั่ง VACUUM INTO
จะบันทึกสแนปช็อต ดูความคิดเห็นเหล่านี้เกี่ยวกับ GitHub และ ข่าวแฮกเกอร์ สำหรับข้อมูลเชิงลึกเพิ่มเติม
นอกจากนี้ เรายังใช้ VACUUM INTO
แทน backup
เนื่องจากคำสั่ง backup
จะทำให้ฐานข้อมูลไม่เข้ารหัสเป็นระยะเวลาสั้นๆ จนกว่าจะมีการเรียกใช้ rekey
(ดู GitHub ความคิดเห็น นี้สำหรับข้อมูลเชิงลึก)
รองจะสั่งให้หลักดำเนินการสำรองข้อมูลผ่านการเชื่อมต่อ WebSocket
จากนั้นหลักจะได้รับคำสั่งให้ดำเนินการดังกล่าว และจะดำเนินการดังต่อไปนี้:
- เชื่อมต่อกับกล่องจดหมายที่เข้ารหัสของคุณ
- รับการล็อกการเขียน
- เรียกใช้จุดตรวจสอบ WAL ผ่าน
wal_checkpoint(PASSIVE)
- เรียกใช้คำสั่ง
VACUUM INTO
SQLite - ตรวจสอบให้แน่ใจว่าไฟล์ที่คัดลอกสามารถเปิดได้ด้วยรหัสผ่านที่เข้ารหัส (safeguard/dummyproofing)
- อัปโหลดไปยัง 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, เวอร์ชันใหม่กว่า และรองรับการใช้งานกับมนุษย์ |
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 | ตัวแก้ไข Visual SQLite (ซึ่งคุณยังสามารถใช้ได้อีกด้วย) เพื่อทดสอบ ดาวน์โหลด และดูกล่องจดหมายการพัฒนา |
SQLite | เลเยอร์ฐานข้อมูลฝังตัวสำหรับการจัดเก็บ IMAP ที่ปรับขนาดได้ เป็นอิสระ รวดเร็ว และยืดหยุ่น |
Spam Scanner | เครื่องมือป้องกันสแปม การกรองอีเมล และฟิชชิ่งของ Node.js (ทางเลือกของเราสำหรับ Spam Assassin และ rspamd) |
Tangerine | การร้องขอ DNS ผ่าน HTTPS ด้วย Node.js และการแคชโดยใช้ Redis ซึ่งรับประกันความสอดคล้องทั่วโลกและอื่น ๆ อีกมากมาย |
Thunderbird | ทีมพัฒนาของเราใช้สิ่งนี้ (และแนะนำสิ่งนี้ด้วย) เป็น ไคลเอนต์อีเมลที่แนะนำให้ใช้กับการส่งต่ออีเมล |
UTM | ทีมพัฒนาของเราใช้เครื่องเสมือนที่สร้างขึ้นนี้สำหรับ iOS และ macOS เพื่อทดสอบไคลเอนต์อีเมลต่างๆ (แบบคู่ขนาน) กับเซิร์ฟเวอร์ IMAP และ SMTP ของเรา |
Ubuntu | ระบบปฏิบัติการเซิร์ฟเวอร์โอเพ่นซอร์สที่ทันสมัยบนพื้นฐาน Linux ซึ่งขับเคลื่อนโครงสร้างพื้นฐานทั้งหมดของเรา |
WildDuck | ไลบรารีเซิร์ฟเวอร์ IMAP – ดูหมายเหตุเกี่ยวกับ attachment de-duplication และ IMAP protocol support |
better-sqlite3-multiple-ciphers | ไลบรารี API ที่รวดเร็วและเรียบง่ายสำหรับ Node.js เพื่อโต้ตอบกับ SQLite3 ด้วยโปรแกรม |
email-templates | กรอบงานอีเมลที่เป็นมิตรต่อนักพัฒนาเพื่อสร้าง ดูตัวอย่าง และส่งอีเมลที่กำหนดเอง (เช่น การแจ้งเตือนบัญชีและอื่นๆ) |
json-sql-enhanced | ตัวสร้างคิวรี SQL ที่ใช้ไวยากรณ์แบบ Mongo วิธีนี้ช่วยประหยัดเวลาของทีมพัฒนา เพราะเราสามารถเขียนแบบ Mongo ต่อไปได้ตลอดทั้งสแต็ก โดยไม่ขึ้นกับฐานข้อมูล นอกจากนี้ยังช่วยหลีกเลี่ยงการโจมตีแบบ SQL Injection ด้วยการใช้พารามิเตอร์คิวรี |
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 พร้อมตัวปรับสมดุลการโหลดในตัว (fine-tuned เพื่อประสิทธิภาพ) |
smtp-server | ไลบรารีเซิร์ฟเวอร์ SMTP – เราใช้สิ่งนี้สำหรับการแลกเปลี่ยนอีเมล ("MX") และเซิร์ฟเวอร์ SMTP ขาออก |
ImapTest | เครื่องมือที่มีประโยชน์สำหรับการทดสอบเซิร์ฟเวอร์ IMAP เทียบกับเกณฑ์มาตรฐานและความเข้ากันได้ของโปรโตคอล IMAP ตามข้อกำหนด RFC โปรเจ็กต์นี้สร้างขึ้นโดยทีม Dovecot (เซิร์ฟเวอร์ IMAP และ POP3 โอเพนซอร์สที่ใช้งานจริงตั้งแต่เดือนกรกฎาคม พ.ศ. 2545) เราได้ทดสอบเซิร์ฟเวอร์ IMAP ของเราอย่างละเอียดด้วยเครื่องมือนี้ |
คุณสามารถค้นหาโครงการอื่นๆ ที่เราใช้ใน ซอร์สโค้ดของเราบน GitHub
ผู้ให้บริการ
ผู้ให้บริการ | วัตถุประสงค์ |
---|---|
Cloudflare | ผู้ให้บริการ DNS การตรวจสอบสุขภาพ ตัวปรับสมดุลการโหลด และที่เก็บข้อมูลสำรองโดยใช้ Cloudflare R2 |
Digital Ocean | การโฮสต์เซิร์ฟเวอร์เฉพาะและฐานข้อมูลที่ได้รับการจัดการ |
Vultr | การโฮสต์เซิร์ฟเวอร์เฉพาะ |
DataPacket | การโฮสต์เซิร์ฟเวอร์เฉพาะ |
ความคิด
หลักการ
การส่งต่ออีเมลได้รับการออกแบบตามหลักการเหล่านี้:
- เป็นมิตรกับนักพัฒนาเสมอ เน้นความปลอดภัยและความเป็นส่วนตัว และมีความโปร่งใส
- ปฏิบัติตาม MVC, ยูนิกซ์, KISS, DRY, YAGNI, สิบสองปัจจัย, มีดโกนของอ็อกแคม และ การทดลองใช้ผลิตภัณฑ์อาหารสุนัข
- กำหนดเป้าหมายนักพัฒนาที่ขาดความคิดสร้างสรรค์ นักพัฒนาที่เริ่มต้นด้วยตนเอง และนักพัฒนาที่ ราเมนทำกำไร
การทดลอง
tldr; ในที่สุดแล้ว การใช้ที่จัดเก็บวัตถุที่เข้ากันได้กับ S3 และ/หรือตารางเสมือนนั้นไม่สามารถทำได้จริงในทางเทคนิคเนื่องด้วยเหตุผลด้านประสิทธิภาพ และมีแนวโน้มที่จะเกิดข้อผิดพลาดเนื่องจากข้อจำกัดของหน่วยความจำ
เราได้ทำการทดลองหลายครั้งจนนำไปสู่โซลูชัน SQLite ขั้นสุดท้ายตามที่ได้กล่าวไว้ข้างต้น
วิธีหนึ่งคือการลองใช้ rclone และ SQLite ร่วมกับเลเยอร์การจัดเก็บข้อมูลที่รองรับ S3
การทดลองดังกล่าวทำให้เราเข้าใจและค้นพบกรณีขอบที่เกี่ยวข้องกับการใช้งาน rclone, SQLite และ VFS มากขึ้น:
- หากคุณเปิดใช้งานแฟล็ก
--vfs-cache-mode writes
ด้วย rclone การอ่านจะไม่มีปัญหา แต่การเขียนจะถูกแคชไว้ - หากคุณมีเซิร์ฟเวอร์ IMAP หลายเครื่องกระจายอยู่ทั่วโลก แคชจะถูกปิดบนเซิร์ฟเวอร์เหล่านั้น เว้นแต่คุณจะมีผู้เขียนเพียงรายเดียวและผู้รับข้อมูลหลายราย (เช่น วิธี pub/sub)
- เรื่องนี้มีความซับซ้อนมาก และการเพิ่มความซับซ้อนเพิ่มเติมเช่นนี้จะส่งผลให้เกิดจุดล้มเหลวแบบจุดเดียวมากขึ้น
- ผู้ให้บริการพื้นที่จัดเก็บข้อมูลที่รองรับ S3 ไม่รองรับการเปลี่ยนแปลงไฟล์บางส่วน ซึ่งหมายความว่าการเปลี่ยนแปลงใดๆ ในไฟล์
.sqlite
จะส่งผลให้เกิดการเปลี่ยนแปลงทั้งหมดและอัปโหลดฐานข้อมูลใหม่อีกครั้ง - มีโซลูชันอื่นๆ เช่น
rsync
แต่ไม่ได้มุ่งเน้นไปที่การรองรับ write-ahead-log ("WAL") ดังนั้นเราจึงได้ตรวจสอบ Litestream โชคดีที่การเข้ารหัสของเราได้เข้ารหัสไฟล์ WAL ไว้แล้ว ดังนั้นเราจึงไม่จำเป็นต้องใช้ Litestream อย่างไรก็ตาม เรายังไม่มั่นใจใน Litestream สำหรับการใช้งานจริง และขออธิบายเพิ่มเติมด้านล่าง - การใช้ตัวเลือก
--vfs-cache-mode writes
(วิธี เดียว ในการใช้ SQLite แทนrclone
สำหรับการเขียน) จะพยายามคัดลอกฐานข้อมูลทั้งหมดตั้งแต่ต้นในหน่วยความจำ – การจัดการกล่องจดหมายขนาด 10 GB หนึ่งกล่องนั้นทำได้ แต่การจัดการกล่องจดหมายหลายกล่องที่มีพื้นที่เก็บข้อมูลสูงเกินไปจะทำให้เซิร์ฟเวอร์ IMAP ประสบปัญหาหน่วยความจำไม่เพียงพอ และเกิดข้อผิดพลาดENOMEM
, ความผิดพลาดในการแบ่งเซกเมนต์ และข้อมูลเสียหาย - หากคุณพยายามใช้ SQLite ตารางเสมือนจริง (เช่น ใช้ s3db) เพื่อให้ข้อมูลอยู่บนเลเยอร์จัดเก็บข้อมูลที่เข้ากันได้กับ S3 คุณจะพบกับปัญหาเพิ่มเติมหลายประการ:
- การอ่านและเขียนจะช้ามาก เนื่องจากปลายทาง API ของ S3 จะต้องถูกโจมตีด้วยเมธอด HTTP
.sqlite
0,.sqlite
1,.sqlite
2 และ.sqlite
3 - การทดสอบการพัฒนาแสดงให้เห็นว่าการบันทึกข้อมูลเกิน 500,000-1 ล้านเรคคอร์ดบนอินเทอร์เน็ตไฟเบอร์ยังคงถูกจำกัดด้วยปริมาณงานของการเขียนและการอ่านไปยังผู้ให้บริการที่เข้ากันได้กับ S3 ตัวอย่างเช่น นักพัฒนาของเราได้รันลูป
.sqlite
4 เพื่อทำทั้งคำสั่ง SQL.sqlite
5 แบบต่อเนื่อง และคำสั่งที่เขียนข้อมูลจำนวนมากพร้อมกัน ซึ่งในทั้งสองกรณี ประสิทธิภาพการทำงานนั้นช้าอย่างน่าตกใจ - ตารางเสมือน ไม่สามารถมีดัชนี, คำสั่ง
.sqlite
6 และคำสั่ง.sqlite
7.sqlite
8 ซึ่งทำให้เกิดความล่าช้า 1-2 นาทีหรือมากกว่า ขึ้นอยู่กับปริมาณข้อมูล - อ็อบเจ็กต์ถูกจัดเก็บไว้โดยไม่เข้ารหัส และไม่มีการรองรับการเข้ารหัสแบบเนทีฟที่พร้อมใช้งาน
- เราได้ศึกษาการใช้
.sqlite
9 ซึ่งมีความคล้ายคลึงกันทั้งในด้านแนวคิดและเทคนิคกับหัวข้อย่อยก่อนหน้า (จึงมีปัญหาเดียวกัน) ความเป็นไปได้คือการใช้บิลด์rsync
0 แบบกำหนดเองที่ห่อหุ้มด้วยการเข้ารหัส เช่นrsync
1 (ซึ่งเรากำลังใช้ในโซลูชันข้างต้น) ผ่านrsync
2 - อีกวิธีหนึ่งที่เป็นไปได้คือการใช้
rsync
3 อย่างไรก็ตาม วิธีนี้จะมีข้อจำกัดที่ 32 GB และจะต้องสร้างและพัฒนาที่ซับซ้อน - จำเป็นต้องใช้คำสั่ง
rsync
4 (ดังนั้นจึงตัดการใช้ Virtual Tables ออกไปโดยสิ้นเชิง) เราจำเป็นต้องใช้คำสั่งrsync
5 เพื่อให้ hook ของเรากับrsync
6 ทำงานได้อย่างถูกต้อง ซึ่งจะช่วยให้มั่นใจได้ว่าข้อมูลจะไม่เสียหาย และแถวที่ดึงมาสามารถแปลงเป็นเอกสารที่ถูกต้องตามข้อกำหนด schemarsync
7 ของเรา (ซึ่งรวมถึงข้อจำกัด ประเภทตัวแปร และการตรวจสอบความถูกต้องของข้อมูลตามอำเภอใจ) - โปรเจกต์ที่เข้ากันได้กับ S3 เกือบทั้งหมดที่เกี่ยวข้องกับ SQLite ในชุมชนโอเพนซอร์สนั้นเขียนด้วยภาษา Python (ไม่ใช่ JavaScript ซึ่งเราใช้สำหรับสแต็กทั้งหมด 100%)
- ไลบรารีการบีบอัดข้อมูล เช่น
rsync
8 (ดูrsync
9) ดูมีแนวโน้มดี แต่ __PROTECTED_LINK_189__0 การบีบอัดข้อมูลฝั่งแอปพลิเคชันบนชนิดข้อมูลต่างๆ เช่น __PROTECTED_LINK_189__1, __PROTECTED_LINK_189__2, __PROTECTED_LINK_189__3, __PROTECTED_LINK_189__4, __PROTECTED_LINK_189__5 และ __PROTECTED_LINK_189__6 จะเป็นแนวทางที่สะอาดและง่ายกว่า (และง่ายต่อการย้ายข้อมูลด้วย เนื่องจากเราสามารถจัดเก็บแฟล็กหรือคอลัมน์ __PROTECTED_LINK_189__7 หรือแม้แต่ใช้ __PROTECTED_LINK_189__8 __PROTECTED_LINK_189__9 สำหรับการบีบอัดข้อมูล หรือ __PROTECTED_LINK_190__0 สำหรับเมตาดาต้าฐานข้อมูลที่ไม่มีการบีบอัด) - โชคดีที่เราได้ติดตั้งระบบกำจัดไฟล์แนบซ้ำซ้อนในพื้นที่จัดเก็บเซิร์ฟเวอร์ IMAP ของเราแล้ว ดังนั้นทุกข้อความที่มีไฟล์แนบเดียวกันจะไม่เก็บสำเนาของไฟล์แนบไว้ แต่จะมีการจัดเก็บไฟล์แนบเดียวสำหรับข้อความและเธรดหลายรายการในกล่องจดหมาย (และจะใช้การอ้างอิงภายนอกในภายหลัง)
- โปรเจ็กต์ Litestream ซึ่งเป็นโซลูชันการจำลองและสำรองข้อมูล SQLite มีแนวโน้มที่ดีมาก และเรามีแนวโน้มที่จะนำไปใช้ในอนาคต
- ไม่ได้มีเจตนาจะดูหมิ่นผู้เขียน เพราะเราชื่นชอบผลงานและการมีส่วนร่วมของพวกเขาในโอเพนซอร์สมากว่าทศวรรษแล้ว อย่างไรก็ตาม จากการใช้งานจริง พบว่ามี __PROTECTED_LINK_190__1 และ __PROTECTED_LINK_190__2
- การกู้คืนข้อมูลสำรองต้องราบรื่นและง่ายดาย การใช้โซลูชันเช่น MongoDB กับ __PROTECTED_LINK_190__3 และ __PROTECTED_LINK_190__4 ไม่เพียงแต่น่าเบื่อ แต่ยังใช้เวลานานและมีความซับซ้อนในการกำหนดค่า
- ฐานข้อมูล SQLite ทำให้มันง่าย (เป็นไฟล์เดียว)
- เราต้องการออกแบบโซลูชันที่ผู้ใช้สามารถนำกล่องจดหมายของตนออกไปและออกจากระบบได้ทุกเมื่อ
- คำสั่ง Node.js ง่ายๆ สำหรับ __PROTECTED_LINK_190__5 และจะถูกลบออกจากพื้นที่จัดเก็บข้อมูลบนดิสก์อย่างถาวร
- เราสามารถใช้ API ที่เข้ากันได้กับ S3 ร่วมกับ HTTP __PROTECTED_LINK_190__6 เพื่อลบสแนปช็อตและการสำรองข้อมูลสำหรับผู้ใช้ได้อย่างง่ายดาย
- SQLite เป็นโซลูชันที่ง่ายที่สุด รวดเร็วที่สุด และคุ้มค่าที่สุด
ขาดทางเลือก
เท่าที่เรารู้ บริการอีเมลอื่น ๆ ไม่ได้ถูกออกแบบมาในลักษณะนี้ และไม่ได้เป็นโอเพนซอร์สด้วย
เรา คิดว่านี่อาจเป็นเพราะ บริการอีเมลที่มีอยู่มีเทคโนโลยีเก่าในการผลิตด้วย รหัสสปาเก็ตตี้ 🍝
ผู้ให้บริการอีเมลที่มีอยู่ส่วนใหญ่หรือเกือบทั้งหมดเป็นผู้ให้บริการแบบปิดหรือโฆษณาว่าเป็นโอเพนซอร์ส แต่ในความเป็นจริง มีเพียงส่วนหน้าของพวกเขาเท่านั้นที่เป็นโอเพนซอร์ส
ส่วนที่ละเอียดอ่อนที่สุดของอีเมล (การโต้ตอบระหว่างพื้นที่เก็บข้อมูลจริง/IMAP/SMTP) จะทำทั้งหมดในส่วนของแบ็กเอนด์ (เซิร์ฟเวอร์) และ ไม่ใช่ ในส่วนของฟรอนต์เอนด์ (ไคลเอนต์)
ทดลองใช้การส่งต่ออีเมล
ลงทะเบียนวันนี้ที่ https://forwardemail.net! 🚀