High-Voltage Serverless Disposable Email & Automated OTP Extraction Engine built on Cloudflare Edge (Workers, D1 SQLite & Anycast Email Routing).
RZero Mail is a production-ready, open-source temporary disposable email service engineered specifically for high-speed automated bot workflows, account registration pipelines, and privacy protection.
Unlike traditional disposable email systems that rely on heavy webmail UIs and complex POST payloads, RZero Mail offers a GET Method REST API, a context-aware Instant OTP Extractor, multi-domain Anycast routing with zero relay delays, PIN-secured private inboxes, and an opinionated Neo-Brutalism responsive web interface.
Layanan temporary email publik yang ada saat ini seringkali memiliki kendala mendasar:
- UI Lambat & Iklan Berlebihan: Webmail tradisional dipenuhi skrip pelacak dan iklan pop-up yang memperlambat browser.
- Akses API Terkunci / Berbayar: Sebagian besar penyedia mengunci akses API atau mewajibkan payload POST dan auth token rumit untuk sekadar membaca pesan masuk.
- Pemeliharaan Mail Server Konvensional yang Rumit: Mengelola server Postfix/Dovecot mandiri membutuhkan konfigurasi IP reputasi, pembersihan storage rutin, dan rentan terhadap serangan DDoS.
RZero Mail dirancang sebagai solusi infrastruktur email sementara modern:
- Serverless Edge-Native: Menggunakan Cloudflare Workers & Anycast Email Routing, memindahkan pemrosesan email langsung ke edge network global tanpa server fisik mail.
- Developer-First (100% GET REST API): Seluruh interaksi (generate email, custom inbox, list pesan, ambil OTP) dapat dilakukan via HTTP GET murniβsangat ramah untuk bot Telegram, Discord, cURL, maupun CLI.
- Ekstraksi OTP Otomatis: Dilengkapi regex engine yang langsung membedah dan mengisolasi 4β8 digit kode verifikasi dari isi email ke dalam field JSON terpisah.
- Multi-Domain Resiliency: Mendukung puluhan custom domain dengan pengecekan MX Dual-DoH (Cloudflare + Google DoH) dan auto-resolver Host DNS.
| Kategori | Kelebihan (Pros) | Kekurangan (Cons) |
|---|---|---|
| Kecepatan & Latensi | Anycast Edge Speed (<20ms): Berjalan di ratusan data center Cloudflare global; penerimaan email dan response API terjadi seketika tanpa jeda antrean server konvensional. | Inbound Only: Dikhususkan untuk penerimaan email & verifikasi akun; tidak mendukung fitur kirim email keluar (outbound SMTP). |
| Integrasi Developer | 100% GET Method REST API: Tidak memerlukan API key untuk endpoint publik dan tanpa payload JSON rumit. Cukup panggil URL via browser, bot, atau script terminal. | Ketergantungan Ekosistem Cloudflare: Terikat pada Cloudflare Workers, Cloudflare D1, dan Email Routing; butuh adaptasi jika ingin dipindahkan ke VPS biasa. |
| Biaya & Pemeliharaan | Zero Server Maintenance: Tanpa perlu konfigurasi Postfix/Dovecot atau manajemen storage disk VPS; otomatis auto-scale di infrastruktur Cloudflare. | Batas Concurrent Write D1: SQLite D1 memiliki batas throughput write tertentu saat menghadapi lonjakan masif ribuan email masuk secara bersamaan dalam 1 detik. |
| UI & Keamanan | Neo-Brutalism & Triple-Lock Admin: Tampilan responsif super ringan tanpa framework berat, serta konsol admin terlindungi autentikasi berlapis dan Dual-DoH validator. | Retensi Temporer: Data pesan dirancang untuk penggunaan sementara (disposable) dan tidak ditujukan sebagai arsip surat elektronik permanen. |
- Live Webmail Production: https://rzmail.my.id/
- Live Interactive API Docs: https://rzmail.my.id/docs
[ Inbound Email (Canva / Discord / Social) ]
β
βΌ
[ Cloudflare Anycast 3-MX Servers ]
(route1 / route2 / route3.mx.cloudflare.net)
β
βΌ
[ Cloudflare Email Worker ]
βββ Inbound MIME Parser (postal-mime)
βββ Contextual OTP Extractor (Regex Engine)
βββ D1 SQLite Storage Engine (rzero-db)
β
βββββββββββββ΄ββββββββββββ
βΌ βΌ
[ REST API Layer ] [ Web Client (Edge CDN) ]
βββ GET Methods βββ Neo-Brutalism UI
βββ Anti-DDoS Limiter βββ Reactive Auto-Refresh
βββ Triple-Lock Admin βββ Live API Docs (/docs)
- GET Method REST API: Create addresses, list messages, and retrieve OTP codes directly via simple HTTP GET requests. Perfect for bots, curl commands, and browser address bar access.
- Automated Contextual OTP Extractor: Built-in algorithmic regex parser isolates 4β8 digit verification codes from incoming message bodies (Canva, Discord, social media, crypto faucets, APK services) directly into clean JSON fields.
- Leaderboard Inbound Provider (Admin Exclusive): Realtime analytics and classification of email senders (Google, Canva, Alight Motion, Discord, Shopee, Steam, AWS, dll.) with comprehensive metrics and an 'Other' sender drawer for inspecting unidentified sender addresses.
- Defensive Hardened Security & PIN Lockout: Multi-tier security engine featuring a 5-strike brute-force lockout guard (15-minute temporary freeze) stored in D1, strict lock guard enforcement across all message endpoints (including shorthand
/api/messages), secure RFC-compliantDELETEwith cross-account IDOR validation, and 250KB bounded payload ingestion to prevent storage exhaustion DoS. - Cloudflare Anycast 3-MX Redundancy & Gateway SMTP: Multi-server failover routing prevents bounce-backs and ensures instant delivery under high traffic, with dual-path support for both Cloudflare Email Routing and internal VPS SMTP gateway (
mail.rzmail.my.id). - D1 High-Performance Composite Indexing: Sub-15ms query latency under heavy inbox loads powered by composite index keys (
idx_messages_inbox_received,idx_pin_attempts_address,idx_session_inboxes_lookup). - Permanent Inboxes & PIN Security: Inboxes do not expire unless explicitly unlinked. Users can lock their custom mailboxes with a 4β6 digit PBKDF2 PIN.
- Multi-Domain Support: Seamlessly manage dozens of active domains with live DNS MX inspection and status badges.
- Triple-Lock Admin Console: Multi-tier administration console secured with username, master password, secondary security key, and cryptographically signed session cookies.
- Ad & Sponsor Management: Built-in CRUD support for custom promo banners, sponsored script units (e.g. A-ADS), and conversion click-tracking.
- Zero Framework Bloat: Frontend built with pure vanilla HTML5, CSS3, and JavaScriptβzero build steps, zero bloated client-side bundles.
βββ src/
β βββ index.ts # Main Cloudflare Worker entrypoint & static router
β βββ email-handler.ts # Postal-Mime inbound processor & D1 storage
β βββ api/
β β βββ routes.ts # GET public API endpoints
β βββ admin/
β β βββ admin-handler.ts # Triple-lock admin RPC controller & MX verifier
β βββ db/
β β βββ schema.sql # Cloudflare D1 SQLite schema & migration
β β βββ queries.ts # Prepared SQL query abstractions
β βββ middleware/
β β βββ anti-ddos.ts # Sliding-window rate limiter & IP protection
β βββ utils/
β β βββ crypto.ts # SHA-256 hashers & OTP extraction regex
β β βββ random-address.ts # Memorable random inbox name generator
β βββ web/
β βββ index.html # Webmail client (Neo-Brutalism)
β βββ docs.html # Interactive REST API docs & live tester
β βββ admin.html # Admin console & DNS routing manager
β βββ styles.css # Neo-Brutalism design system stylesheet
β βββ app.js # Realtime polling & reactive UI controller
βββ wrangler.toml.example # Cloudflare Wrangler configuration template
βββ .env.example # Local environment variables template
βββ package.json # Project dependencies and deployment scripts
βββ tsconfig.json # TypeScript compiler configuration
βββ LICENSE # MIT License
Ikuti panduan langkah demi langkah di bawah ini untuk menjalankan RZero Mail dari nol sampai live di Cloudflare Workers.
Pastikan kamu sudah menginstal:
- Node.js (versi 18 LTS atau 20/22 LTS): Cek via
node -v - NPM atau PNPM: Cek via
npm -v - Akun gratis di Cloudflare
- Minimal 1 domain aktif yang sudah diarahkan Nameserver-nya ke Cloudflare (misal:
domainkamu.com).
β οΈ ATURAN WAJIB AKUN CLOUDFLARE (SAME-ACCOUNT ZONE):
Semua domain yang ingin kamu gunakan di RZero Mail (baik domain utama maupun multi-domain tambahan yang dimasukkan lewat panel/admin) WAJIB berada di dalam Zone akun Cloudflare yang SAMA dengan akun Cloudflare tempat Worker di-deploy.
Fitur Cloudflare Email Routing (Catch-all -> Send to Worker) tidak mengizinkan perutean lintas akun (cross-account). Jadi pastikan setiap domain baru sudah ditambahkan ke dashboard Cloudflare akun yang sama sebelum memasang 3 MX record dan mendaftarkannya di panel admin.
Buka terminal dan jalankan:
git clone https://github.com/rndsa/rzero-mail.git
cd rzero-mail
npm installHubungkan terminal kamu dengan akun Cloudflare:
npx wrangler loginBrowser akan terbuka otomatis. Klik tombol Allow / Authorize untuk memberikan izin akses.
- Buat database D1 baru bernama
rzero-db:
npx wrangler d1 create rzero-db- Terminal akan menampilkan output seperti ini:
[[d1_databases]]
binding = "DB"
database_name = "rzero-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
- Buka file
wrangler.toml(atau copy dariwrangler.toml.example):
cp wrangler.toml.example wrangler.tomlLalu tempelkan nilai database_id yang kamu dapatkan tadi ke dalam wrangler.toml.
- Jalankan Migrasi Database (Buat Tabel SQL): Eksekusi file skema database ke Cloudflare D1:
# Migrasi ke server produksi Cloudflare D1:
npx wrangler d1 execute rzero-db --remote --file=./src/db/schema.sql(Perintah ini akan otomatis membuat tabel inboxes, messages, domains, ads, dan traffic_logs).
Supaya Worker bisa menerima email masuk dari Canva, Discord, dll:
π‘ Penting: Pastikan domain ini berada di akun Cloudflare yang sama dengan Worker kamu. Untuk setiap domain baru yang ingin kamu tambahkan ke multi-domain, ulangi langkah setup Email Routing ini pada domain tersebut di akun Cloudflare yang sama.
- Buka Cloudflare Dashboard β Pilih domain kamu.
- Klik menu Email Routing di sidebar sebelah kiri β Klik Get Started / Enable Email Routing.
- Tambahkan 3 record DNS MX resmi Cloudflare (Anycast Failover):
| Tipe | Nama Host | Target Server MX | Prioritas |
|---|---|---|---|
| MX | @ |
route1.mx.cloudflare.net |
10 |
| MX | @ |
route2.mx.cloudflare.net |
20 |
| MX | @ |
route3.mx.cloudflare.net |
30 |
| TXT | @ |
v=spf1 include:_spf.mx.cloudflare.net ~all |
- |
- Buka tab Routing Rules β cari bagian Catch-all address:
- Status: Enabled (Aktifkan)
- Action: Pilih Send to Worker
- Destination: Pilih Worker
rzero-mail(atau nama worker yang ada diwrangler.toml). - Klik Save.
Sesuaikan variabel environment di dalam wrangler.toml:
name = "rzero-mail"
main = "src/index.ts"
compatibility_date = "2025-06-01"
workers_dev = true
# (Opsional) Jika ingin pasang custom domain utama:
routes = [
{ pattern = "domainkamu.com", custom_domain = true }
]
[[d1_databases]]
binding = "DB"
database_name = "rzero-db"
database_id = "PASTE_DATABASE_ID_DARI_LANGKAH_4"
[email]
action = "process"
[vars]
APP_NAME = "RZero Mail"
MAIL_DOMAIN = "domainkamu.com"
WEB_HOST = "domainkamu.com"
# Kredensial Admin Panel (/admin)
ADMIN_USERNAME = "admin"
ADMIN_PASSWORD = "password_rahasia_kamu"
ADMIN_V2L_KEY = "kunci_kedua_rahasia"
ADMIN_SECRET = "secret_jwt_hmac_acak"
[assets]
directory = "./src/web"
[observability]
enabled = trueJika ingin menguji tampilan UI dan API di localhost terlebih dahulu:
# Buat tabel di database D1 lokal:
npx wrangler d1 execute rzero-db --local --file=./src/db/schema.sql
# Jalankan server lokal:
npm run dev
# atau:
npx wrangler devBuka browser di http://localhost:8787.
Untuk mempublikasikan ke seluruh server Cloudflare di dunia:
npx wrangler deployBegitu selesai, terminal akan menampilkan URL live worker kamu:
Uploaded rzero-mail
Deployed rzero-mail triggers:
https://rzero-mail.<subdomain>.workers.dev
domainkamu.com (custom domain)
- Buka URL webmail kamu di browser:
https://domainkamu.com/ - Coba buat email baru atau tembak API:
curl -s "https://domainkamu.com/api/create"- Buka halaman dokumentasi API di:
https://domainkamu.com/docs - Buka admin console di:
https://domainkamu.com/admin(login menggunakan kredensial yang kamu set diwrangler.toml).
Base URL: https://yourdomain.com/api
GET /api/create?domain=yourdomain.comResponse (200 OK):
{
"success": true,
"address": "swiftfox88@yourdomain.com",
"isLocked": false,
"isOwner": true,
"created": true
}GET /api/custom/mybot@yourdomain.comAtau menggunakan query parameters (PIN tidak lagi diterima di query β kirim lewat body JSON):
GET /api/custom?name=mybot&domain=yourdomain.comUntuk langsung mengunci inbox dengan PIN, gunakan method POST dengan body JSON:
POST /api/custom
Content-Type: application/json
{"name": "mybot", "domain": "yourdomain.com", "pin": "123456"}Response (200 OK):
{
"success": true,
"address": "mybot@yourdomain.com",
"isLocked": false,
"isOwner": true,
"created": true
}GET /api/otp/mybot@yourdomain.comResponse (200 OK):
{
"success": true,
"address": "mybot@yourdomain.com",
"has_otp": true,
"otp": "482910",
"from": "messages-noreply@canva.com",
"subject": "482910 adalah kode masuk Canva Anda",
"received_at": "2026-09-26 10:04:03"
}(Tambahkan ?raw=1 untuk mendapatkan string angka saja 482910 tanpa JSON)
GET /api/messages?address=mybot@yourdomain.comCatatan Keamanan: Jika inbox dikunci dengan PIN, sertakan header x-inbox-pin: 123456. PIN tidak lagi diterima lewat query parameter ?pin= maupun ?session_id= β nilai sensitif di URL bocor ke access log, header Referer, dan riwayat browser. Identitas sesi dikirim lewat header x-session-id (atau cookie). Permintaan tanpa PIN pada inbox terkunci akan ditolak dengan HTTP 403 INBOX_LOCKED.
Response (200 OK):
{
"success": true,
"address": "mybot@yourdomain.com",
"isLocked": false,
"count": 1,
"messages": [
{
"id": "msg_canva_user_01",
"from_address": "messages-noreply@canva.com",
"subject": "482910 adalah kode masuk Canva Anda",
"snippet": "Halo! Gunakan kode masuk 482910 ini untuk melanjutkan ke Canva...",
"otp_code": "482910",
"received_at": "2026-09-26 10:04:03"
}
]
}GET /api/inboxes/mybot@yourdomain.com/messages/:idDELETE /api/inboxes/mybot@yourdomain.com/messages/:idMemerlukan kepemilikan sesi yang sah atau header x-inbox-pin yang cocok. Endpoint memverifikasi IDOR agar pesan hanya dapat dihapus oleh pemilik inbox yang bersangkutan.
POST /api/inboxes/mybot@yourdomain.com/lock
Content-Type: application/json
x-session-id: <session_id>
{
"pin": "123456"
}DELETE /api/inboxes/mybot@yourdomain.com
x-session-id: <session_id>GET /api/domainsPanel admin (/admin) menggunakan autentikasi 3 lapis:
- Lapis 1: Admin username & SHA-256 hashed password.
- Lapis 2: Secondary passkey verification (
ADMIN_V2L_KEY). - Lapis 3: HMAC-SHA256 cryptographically signed session cookie pada setiap pemanggilan endpoint RPC internal.
Fitur admin mencakup:
- Leaderboard Provider Email Masuk: Pemantauan volume dan peringkat pengirim email masuk secara realtime (Google, Canva, Alight Motion, Discord, Shopee, Steam, AWS, dll.) dengan klasifikasi otomatis dan drawer rincian sender untuk kategori Other.
- Realtime DNS DoH 3-MX Inspection: Dual-DoH validator (Cloudflare + Google DoH) untuk verifikasi otomatis status routing domain.
- Manajemen Domain: Tambah, verifikasi, aktifkan/nonaktifkan, dan hapus domain.
- Manajemen Slot Iklan & Sponsor: Pengaturan banner sponsor dan pelacakan klik konversi.
- Traffic Logs & Rate Limiting: Pengawasan IP, counter hit, dan audit jejak request.
- PIN Attempt Lockout Guard: Pencatatan otomatis di D1; jika terjadi 5 kali kegagalan input PIN berturut-turut pada inbox, sistem mengunci verifikasi alamat tersebut selama 15 menit.
Project ini telah diaudit dan diperkuat terhadap vektor serangan edge modern, session hijacking, dan injection:
-
Inbox Ownership Guard (Anti-Takeover):
- Endpoint
POST /api/inboxesdan/api/customsecara ketat memverifikasi kepemilikan sesi (owner_session_id). - Alamat email aktif milik sesi lain ditolak dengan status HTTP 409
INBOX_TAKENdan tidak dapat diklaim tanpa PIN resmi pemilik.
- Endpoint
-
Third-Party Script Ad Isolation (Zero-Trust Sandbox):
- Skrip iklan dinamis pihak ketiga (A-ADS, dsb.) diisolasi ke dalam sub-frame
<iframe sandbox="allow-scripts">tanpa atributallow-same-origin. - Mengeliminasi risiko Stored XSS dari eksekusi skrip iklan di konteks dokumen utama; skrip iklan tidak memiliki akses ke cookie, session token, maupun API internal.
- Skrip iklan dinamis pihak ketiga (A-ADS, dsb.) diisolasi ke dalam sub-frame
-
Email Content Strict Sandbox Boundary:
- Iframe pratinjau pesan email (
modalIframe) mencabut izinallow-same-origin, memutus akses dokumen HTML email dari origin domain utama (rzmail.my.id). - Tautan email dipaksa terbuka di tab baru (
target="_blank"denganrel="noopener noreferrer").
- Iframe pratinjau pesan email (
-
Linear ReDoS Stripper Engine:
- Pembersih markup HTML pada ekstraksi OTP diganti dari regex bertingkat ke pemindai linear
$O(n)$ berbasis indeks (indexOf) dengan batas aman 100.000 karakter. - Kebal terhadap serangan Regular Expression Denial of Service (ReDoS) / catastrophic backtracking pada payload email berukuran besar.
- Pembersih markup HTML pada ekstraksi OTP diganti dari regex bertingkat ke pemindai linear
-
URL Credential Stripping (CWE-598 Mitigation):
- Parameter sensitif (
?pin=dan?session_id=) dicabut dari query string URL pada seluruh endpoint. - Autentikasi dialihkan ke header standar (
x-inbox-pin,x-session-id) untuk mencegah kebocoran kredensial di log server dan riwayat browser.
- Parameter sensitif (
-
Triple-Lock Admin Session Revocation:
- Cookie sesi admin terikat pada
epochgenerasi di database D1. Pemanggilan aksi adminrevoke_sessionsmenaikkan epoch dan secara instan menganulir seluruh sesi admin aktif.
- Cookie sesi admin terikat pada
Audit keamanan terhadap rzmail.my.id menemukan 46 celah. Seluruhnya sudah ditutup dan diverifikasi di produksi.
| Temuan | Perbaikan |
|---|---|
ADMIN_PASSWORD, ADMIN_SECRET, ADMIN_V2L_KEY tersimpan sebagai literal di kode & ikut ter-commit |
Semua literal dihapus dari source; nilai dirotasi; kode jadi fail-closed (HTTP 503 kalau secret belum di-set, bukan memakai nilai default) |
Satu ADMIN_SECRET dipakai untuk 3 fungsi berbeda (HMAC sesi admin, bypass rate limit, otorisasi /api/inbound) |
Dipisah jadi ADMIN_SECRET + INBOUND_SECRET β satu bocor tidak membuka tiga pintu |
authHeader.includes(secret) β substring apa pun yang memuat secret dianggap sah |
Diganti perbandingan constant-time atas nilai utuh |
| Temuan | Perbaikan |
|---|---|
| PIN di-hash dengan SHA-256 + salt statis global β 10.000 PIN bisa di-precompute, hash sama muncul di banyak inbox | Diganti PBKDF2-SHA256 (25.000 iterasi) + salt 16-byte acak per-inbox; hash lama tetap diverifikasi lalu di-upgrade otomatis saat unlock berhasil |
| 8 endpoint memakai verifikasi PIN mentah (tanpa lockout) | Semua dialihkan ke verifyPinGuarded() β 5 gagal β 429, terkunci 15 menit |
| Increment lockout non-atomik (baca lalu tulis) β burst paralel melewati batas | Increment atomik via UPSERT; lockout ditentukan dari nilai hasil tulis |
session_id diterima lewat query param β bocor via URL, Referer, log proxy |
Hanya header x-session-id / cookie |
Cookie user & admin tanpa HttpOnly / Secure |
Keduanya kini HttpOnly + Secure + SameSite |
| Token admin tidak bisa dicabut (stateless, TTL 30 hari) | Token membawa ver; logout menaikkan versi β semua token beredar langsung mati; TTL turun ke 12 jam |
| Inbox bisa dibajak: sesi lain mengunci inbox yang belum terkunci | Cek kepemilikan (owner_session_id) sebelum lock/unlock |
| Temuan | Perbaikan |
|---|---|
| Header keamanan kosong total | HSTS (preload), CSP, X-Frame-Options: DENY, nosniff, Referrer-Policy, Permissions-Policy, COOP |
/admin/action tanpa rate limit (middleware hanya ter-mount di /api/*) |
Rate limit 10 percobaan / 5 menit / IP + jail 30 menit |
XSS tersimpan dari skrip iklan (innerHTML di dokumen utama) |
Skrip iklan dieksekusi di <iframe sandbox="allow-scripts"> tanpa allow-same-origin |
| Input tak terbatas pada body email | Batas 250 KB per body |
| Temuan | Perbaikan |
|---|---|
Validasi alamat lemah (../../etc@domain, 300 karakter, newline lolos) |
Regex ketat + sanitasi di setiap cabang pembuatan alamat |
/api/inbound menerima domain sembarang & format email tidak valid |
Wajib email valid + domain terdaftar |
| Detail error internal bocor ke respons (CWE-209) | Pesan error generik; detail hanya ke log |
traffic_logs tanpa indeks (90 ribu baris) & tanpa pruning |
3 index + pruneOldData() berbasis LIMIT, default nonaktif |
Query agregat tanpa LIMIT |
Dibatasi (LIMIT 200) |
| Kuota D1 habis β HTTP 500 buram | Terdeteksi β 503 dengan pesan jelas; halaman statis tetap 200 |
decodeURIComponent melempar URIError pada escape rusak |
safeDecode() dengan fallback ke nilai mentah |
Semua pengujian dijalankan terhadap Worker lokal (wrangler dev --local) dan produksi:
- Kredensial lama: login 401, forge token 401, inbound 401, substring bypass 401
- Rate limit admin: 429 setelah 10 percobaan
- Semua jalur PIN (5 endpoint): 429 setelah 5 gagal
- Race lockout paralel 20Γ: 4 lolos (batas 4)
- 3 inbox dengan PIN identik β 3 hash berbeda (bukti salt per-inbox)
npx tsc --noEmit: bersih- Produksi: 20/20 PASS

