Letterbox – An Android app for opening and inspecting .eml email files
Letterbox is an Android application built with Jetpack Compose that opens and inspects .eml email files. It delegates parsing to a Rust core library (exposed via UniFFI and JNA), renders message bodies and attachments, and keeps a local, deduplicated history backed by Room or an in-memory store for tests.
- Opens
.emlfiles shared viaACTION_VIEWandACTION_SENDintents declared inapp/src/main/AndroidManifest.xml. - Parses messages through the
letterbox-coreRust crate using UniFFI bindings (parseEml,parseEmlFromPath) to extract headers, bodies, inline resources, and attachments. - Displays message content with Jetpack Compose screens (
MainActivity,EmailDetailScreen) and supports sharing the currently opened email via a FileProvider. - Stores recent files with a content-addressable history that deduplicates blobs and enforces limits (
HistoryRepository, Room entities indata/). - Provides product flavors (
prod,staging) and hooks to build native libraries for multiple ABIs withcargo ndkwhen enabled via a Gradle property.
app/: Android application module, Compose UI, Room data layer, UniFFI bindings, and Gradle tasks to build native artifacts.rust/letterbox-core/: Rust library that parses emails withmail-parserand exposes UniFFI bindings for Kotlin/Android.gradle/,build.gradle.kts,settings.gradle.kts: Gradle wrapper and version catalog configuration for the Android project.Cargo.toml: Rust workspace definition pointing torust/letterbox-core.LICENSE: MIT license for the project.
# Run Rust tests for the core library
cargo test
# Run Android unit tests (builds the host Rust library first)
./gradlew test
# Build an installable APK for the prod debug variant
./gradlew :app:assembleProdDebug
# (Optional) Build and embed Rust libraries for Android ABIs using cargo-ndk
./gradlew :app:assembleProdDebug -PrustBuild=true- The
rustBuildGradle property controls whethercargo ndkruns (cargoNdkBuildtask) to emit.sofiles intoapp/src/main/jniLibs; enable it when producing device-ready builds with native parsing. - Unit tests depend on
cargoHostBuild, which compiles a hostlibletterbox_core.soand setsuniffi.component.letterbox_core.libraryOverrideandjna.library.pathso JNA can load it. - Product flavors (
prod,staging) exist under thechanneldimension; assemble the desired variant (e.g.,:app:assembleStagingDebug) as needed.
- Override the native library path for tests with
LETTERBOX_CORE_LIB_PATHor theuniffi.component.letterbox_core.libraryOverridesystem property (used byRustFfiIntegrationTest). - Gradle uses
gradle.propertiesdefaults (org.gradle.jvmargs,android.useAndroidX, Kotlin code style) andgradle/libs.versions.tomlfor dependency versions.
- Rust core:
cargo test. - Android unit tests (all flavors):
./gradlew test. - Instrumented tests (connected device):
./gradlew :app:connectedAndroidTest. - Instrumented tests (managed device - used in CI):
./gradlew pixel7Api34StagingDebugAndroidTest.
See docs/troubleshooting.md for common test issues and solutions.
For detailed troubleshooting information and solutions to common issues, see docs/troubleshooting.md.
Quick fixes:
- If Android builds cannot find the native library, ensure
cargo-ndkis installed and rebuild with-PrustBuild=truesocargoNdkBuildemits ABI-specific.sofiles. - If host-side FFI tests cannot load the library, verify
target/release/libletterbox_core.soexists (built bycargoHostBuild) or setLETTERBOX_CORE_LIB_PATHto the compiled library. - If the app crashes when opening email files, ensure you're running the latest version with the WebView request interception fix.
This project is licensed under the MIT License (see LICENSE).
Note: The Letterbox app icon is not covered by the MIT License and remains proprietary. See the LICENSE file for details.