DEV Community

mrmaskbd247
mrmaskbd247

Posted on

๐Ÿ›ก๏ธ Privacy by Design: How I Built a Local-First Disposable Email Client for Android

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:

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)

Collapse
 
superfunicular profile image
Super Funicular

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?