A focused React Native Gmail client — fast inbox, AI summaries, on-device LLM, full-text search, TTS playlist for unread mail
In development since March 2026
The reason it exists
Gmail's mobile app is dense. It tries to be email + calendar + chat + meet + spaces, and the inbox is fighting for screen real estate against half a dozen other surfaces. Mail App is the opposite: it does email, fast, with just enough AI to make the long unread list manageable.
The architecture
The app is a development build — Expo Go doesn't work because Google Sign-In needs the native module that ships with @react-native-google-signin/google-signin. After the OAuth flow, the access token is stored in the secure keystore and used to talk to the Gmail API directly from the device. There is no application backend.
Sync is incremental. The first launch pulls the recent inbox in pages; subsequent launches use Gmail's History API to fetch only what changed. Headers and metadata land in a local SQLite database via Drizzle ORM; full message bodies are fetched on demand and cached.
Search is the part where the design has the most opinion. The local FTS index in SQLite handles instantaneous matches against subjects, sender names, and snippets. When the user is looking for something specific, a parallel Gmail API search runs in the background, and a small reranker fuses both result sets so the user gets the local hit fast and the canonical hit a second later if they were different.
✨ Key Features
- Google OAuth sign-in via
@react-native-google-signin/google-signin. - Gmail inbox with thread view, label filters, and incremental sync via the Gmail History API.
- Compose, reply, forward, with attachment upload through
expo-document-picker. - AI email summaries — short bullet summary of the unread top of the inbox, generated either via cloud APIs or on-device through llama.rn for privacy-sensitive contexts.
- On-device LLM inference with downloadable GGUF model files (small Llama 3 quantisation), so summaries can run airplane-mode.
- Hybrid search combining local Drizzle FTS with Gmail API search and a reranker that fuses results by relevance score.
- Polish TTS playlist via Sherpa ONNX — taps a button, the app reads out the unread email summaries one after another, useful while commuting.
- Email statistics dashboard: senders by volume, threads by activity, response time histogram.
- Contact ranking: surface the people you actually correspond with at the top of the autocomplete instead of in alphabetical order.
- Crash reporting through Sentry with PII scrubbing on the breadcrumb pipeline.
- High-performance lists via Shopify FlashList; threaded message rendering uses Skia for the avatar bubbles.
🛠️ Tech Stack
| Category | Stack |
|---|---|
| Client | React Native via Expo SDK 54, development build |
| Auth | @react-native-google-signin/google-signin |
| Database | SQLite + Drizzle ORM (local cache + FTS index) |
| State / data | TanStack Query for server state, Zustand for UI |
| Lists | @shopify/flash-list |
| Graphics | @shopify/react-native-skia (avatar bubbles, gesture-based read animations) |
| AI | llama.rn for on-device, OpenAI-compatible cloud API for cloud summaries |
| TTS | Sherpa ONNX with a Polish voice model bundle |
| Observability | @sentry/react-native |
| Language | TypeScript |
Engineering notes
Drizzle was chosen over Prisma because Prisma's mobile-RN story is fragile (no first-class SQLite-on-React-Native runtime). Drizzle compiles to plain SQL strings, runs on expo-sqlite via a thin adapter, and produces TypeScript types from the schema definition.
The hybrid search reranker is small but punches above its weight. Local FTS is fast but indexes only what the device has already pulled, so a search for an old email returns nothing if it was archived before the local cache started. Gmail API search is slower but canonical. Running both in parallel and reranking by a combined score (lexical match strength × recency × sender frequency) gets the speed of local plus the completeness of remote.
The TTS playlist started as a curiosity and ended as the most-used feature in the early-tester cohort. Listening to a five-line summary of each unread email while making coffee is meaningfully different from reading them — the bar for "do I need to respond to this" goes way up when it's spoken aloud, which is exactly the right calibration.
Mail App is a React Native Gmail client built on Expo SDK 54 with a development build (Google Sign-In requires native modules). It connects to the Gmail API for inbox sync, supports AI-powered email summaries via cloud APIs and on-device llama.rn, runs a hybrid search combining a local Drizzle FTS index with Gmail API queries and a reranker, plays unread email summaries through Polish TTS via Sherpa ONNX, and surfaces email statistics and contact ranking. Built with React Native, Expo, Drizzle ORM, TanStack Query, Sentry, and TypeScript. In development since March 2026.