As developers, we are constantly forced to trade our personal data for access. Whether you need to read a single article, test an API, or try out a new SaaS platform, a sign-up form almost always blocks your path.
The result? A primary inbox cluttered with marketing noise and tracker-heavy spam[cite: 1, 2].
To solve this for myself, I built Mailfo v2.0โa modern, temporary disposable email application for Android engineered entirely around privacy and speed[cite: 1, 2]. Here is a look under the hood at how I structured its data handling, caching layer, and reactive UI[cite: 1].
๐๏ธ The Architecture: Local-First & Reactive
The core engineering goal for v2.0 was to eliminate network-induced latency while providing an completely ephemeral footprint.
1. UI Layer (Jetpack Compose)
Older legacy views were completely ripped out in favor of a modern declarative UI framework[cite: 1, 2]. Using a single-activity architecture, the app relies on Compose's reactive state to dynamically toggle between native Light, Dark, and System theme configurations instantly[cite: 1].
2. Caching Layer (Room SQLite DB)
Instead of hammering external APIs every time a user switches tabs, Mailfo implements a local caching layer using a Room database[cite: 1].
- Inbox summaries and complete message details are cached locally[cite: 1].
- This enables seamless, instantaneous tab switching with zero network-pull delay[cite: 1].
- Pull-to-refresh architecture ensures data consistency when the user explicitly requests it[cite: 1].
3. Identity State Management
Unlike basic temporary mail generators that lose your email if the app crashes, Mailfo tracks your history[cite: 2]. The Profile tab exposes your local database of previously generated addresses[cite: 1]. If you need to complete a secondary verification step 20 minutes later, you can reactivate your previous custom or random email identity with a single tap[cite: 1].
โจ Deep-Dive Features
- ๐ Custom vs. Random Addresses: Generate random strings instantly or construct a custom username mapped against searchable active domains[cite: 1, 2].
- ๐ฌ Robust Email Operations: View incoming mail in real-time, apply read/unread filter states, star essential items, and leverage system intents to share or forward payloads[cite: 1].
- ๐ Global Localization: Fully localized with native app language selectors for English, Bangla, Hindi, Arabic, French, Spanish, German, Portuguese, and Turkish[cite: 1].
- ๐งผ Hard Data Control: Privacy apps shouldn't hold your data hostage. The settings menu includes a direct wipe function to clear all local Room database entries and cached message histories cleanly[cite: 1].
โ ๏ธ A Note on Use Cases
Mailfo is engineered for low-risk, disposable activities (testing sign-ups, sandboxing tools, and avoiding newsletters)[cite: 1]. Never use disposable addresses for sensitive operations like digital banking, legal documentation, or main account recoveries[cite: 1].
๐ ๏ธ Open Discussion & Feedback
The project is up and running right now. You can check out the landing page or grab it straight from the app store:
- ๐ Web Portal: https://mailfo.pages.dev/
- ๐ค Play Store Link: Get Mailfo on Google Play
I'd love to hear from other mobile engineers on how you handle ephemeral data caching or localization strings in Jetpack Compose! Let's talk architecture in the comments below. โ
Top comments (1)
Really like the local-first framing here โ caching inbox summaries in Room so tab switches don't hammer the API is the right call, and gating fresh pulls behind pull-to-refresh keeps the ephemeral promise honest without silent background sync.
The part I'd dig into is the wipe function, since on a privacy app that's the real trust boundary. Room's delete removes rows, but SQLite usually keeps the freed pages in the .db file until a VACUUM โ so message bodies can linger on disk after a "clear all." Turning on PRAGMA secure_delete (or running VACUUM right after the purge) is what makes the wipe match the user's mental model.
I ran into the exact same gap building a local-first Android camera app (Background Camera RemoteStream) โ "local-only storage" sounds airtight until you realize deletion semantics ARE the privacy guarantee. How are you handling the freed-page issue on the Room layer?