A typed, asynchronous mail engine for Rust, Python, and Android. Rusted Mail combines IMAP, SMTP, JMAP, provider discovery, local storage, and offline operations behind native Rust and Kotlin APIs.
The engine is independent of JNI. Rust applications can use rusted-mail
directly, while Android applications use the coroutine-based Kotlin API backed
by the same engine.
Project status: Rusted Mail is pre-1.0. It is suitable for integration and evaluation, but public APIs may evolve before a stable release.
- One mail engine: IMAP receive and management, SMTP sending, and JMAP workflows share a consistent model.
- Typed public APIs: Rust callers use builders, owned sessions, request types, and structured errors rather than the internal JSON protocol.
- Android-ready: Kotlin suspending functions and
FlowAPIs are packaged with native libraries for common Android ABIs. - Offline-capable: local message storage, search, queued operations, and replay support are built into the engine.
- Secure defaults: TLS-first server configuration, private-network target controls, bounded requests, and redacted credential debug output.
- Small default surface: JNI, Android packaging, Turso synchronization, OpenPGP, and S/MIME are opt-in boundaries.
| Package or module | Purpose | Intended consumer |
|---|---|---|
rusted-mail |
Protocol, discovery, storage, and message engine | Rust applications and libraries |
rusted-mail-jni |
JNI exports and asynchronous callback bridge | Native integration layers |
rusted-mail-android |
Android cdylib producing libmail_jni.so |
Android packaging |
rusted-mail-python |
Async Python extension and typed facade | Python 3.10+ applications |
android |
Kotlin coroutine API and core AAR | Android applications |
android/turso-store |
Encrypted account/credential store and Turso sync helpers | Android applications using MailManager |
android/turso-cloud |
Turso Cloud administrative API client | Android applications managing Turso resources |
The separation keeps the core crate publishable on crates.io without a JNI or
Android dependency. Patched IMAP and JMAP code is internalized in
rusted-mail, so published packages do not rely on local Cargo patches.
Add the engine and an async runtime:
[dependencies]
rusted-mail = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }Create an account, connect, fetch mail, and send a message:
use rusted_mail::{
AccountConfig, Credentials, FetchOptions, MailEngine, Message, ServerConfig,
};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let account = AccountConfig::builder("alice@example.com")
.credentials(Credentials::password("application-password"))
.imap(ServerConfig::tls("imap.example.com", 993))
.smtp(ServerConfig::start_tls("smtp.example.com", 587))
.build()?;
let engine = MailEngine::new();
let session = engine.connect_imap(account).await?;
let messages = session
.fetch(FetchOptions::new("1:*").mailbox("INBOX").limit(25))
.await?;
println!("Fetched {} messages", messages.len());
let message = Message::builder()
.to("bob@example.com")
.subject("Hello")
.text("Sent with Rusted Mail")
.build()?;
session.send(message).await?;
session.close().await?;
Ok(())
}The Rust API also provides JMAP sessions, provider discovery, mailbox management, typed searches and message actions, attachment helpers, and structured error codes. See the engine guide and generated rustdoc for the complete public surface.
The rusted-mail Python distribution provides native asyncio bindings and a
fully typed standard-library facade:
import asyncio
from rusted_mail import AccountConfig, MailEngine, PasswordCredentials, ServerConfig
async def main() -> None:
account = AccountConfig(
email="alice@example.com",
credentials=PasswordCredentials("application-password"),
imap=ServerConfig("imap.example.com", 993),
)
engine = MailEngine()
async with await engine.connect_imap(account) as mail:
for message in await mail.fetch():
print(message.subject)
asyncio.run(main())See the Python package guide for source installation, SMTP and JMAP examples, structured errors, and development commands.
Rusted Mail's Android API supports API 23 and newer and uses Kotlin coroutines.
The core module loads libmail_jni.so automatically. Initialize the runtime
once, then open and own a client for each account session:
MailClient.init(RuntimeConfig(logLevel = "info"))
val client = MailClient.open(
AccountConfig(
email = "alice@example.com",
username = "alice@example.com",
credential = Credential.Password(appPassword),
imap = ServerConfig("imap.example.com", 993, TlsMode.Tls),
smtp = ServerConfig("smtp.example.com", 587, TlsMode.StartTls),
)
)
try {
val messages = client.fetchMessages(
FetchQuery(mailbox = "INBOX", limit = 25)
)
client.send(
SendRequest(
to = listOf("bob@example.com"),
subject = "Hello",
text = "Sent with Rusted Mail",
)
)
} finally {
client.close()
}Mailbox changes are available as a cancellable Flow:
client.watchMailboxEvents(IdleRequest(mailbox = "INBOX")).collect { event ->
// Refresh summaries, flags, or local state.
}See the Android integration guide for AAR packaging, configuration, lifecycle rules, and more examples. The complete Kotlin API is documented in docs/API.md.
| Area | Included functionality |
|---|---|
| IMAP | mailbox listing and selection, search, sort, thread, fetch, flags, move/copy, archive, spam, trash, expunge, quota, namespace, and mailbox event polling |
| SMTP | send, reply, forward, drafts, and send-and-save workflows |
| JMAP | session discovery, mailboxes, email queries, import, keyword updates, mailbox assignment, and destroy operations |
| Attachments | metadata, fetching, and chunked streaming with configurable size limits |
| Discovery | built-in provider presets, Thunderbird autoconfig, ISPDB, DNS SRV, and conventional-host probing |
| Local data | JSON-backed cache, encrypted local Turso storage, local search, offline operation queue, and replay |
| Account management | Kotlin MailManager, unified IMAP/JMAP models, observable state, and encrypted account/credential storage |
| Integration | OAuth token hooks, structured logging, stable error codes, Python asyncio, and Kotlin coroutine adapters |
| Message security | feature-gated OpenPGP and S/MIME signing, encryption, decryption, verification, and trust policy |
No optional feature is enabled by default.
| Feature | Effect | Notes |
|---|---|---|
turso-native-sync |
Enables Turso Cloud synchronization | Pulls Turso's native-TLS sync transport; the default build remains rustls-only |
crypto-openpgp |
Enables OpenPGP message processing | Preview; forwarded by JNI, Android, and Python packages |
crypto-smime |
Enables S/MIME message processing | Preview; forwarded by JNI, Android, and Python packages |
maik-integration exists only for the optional SMTP integration test suite; it
is not an application feature.
Host development requires Rust 1.95 or newer. Android builds additionally
require Java 21, Android SDK 36, Android NDK 28.2.13676358, and
cargo-ndk.
Run the Rust host checks:
cargo fmt --all -- --check
cargo check --locked --workspace --all-targets
cargo test --locked --workspaceWith the Android prerequisites installed, run the Kotlin/JVM checks:
./gradlew :android:testDebugUnitTest :android-turso-store:testDebugUnitTest :android-turso-cloud:testDebugUnitTest checkNoRawNativeClientAccess --no-daemonRelease-oriented Rust checks:
RUSTDOCFLAGS="-D warnings" cargo doc --locked --workspace --no-deps
cargo package --locked --allow-dirty -p rusted-mailBuild the Android AAR:
cargo install cargo-ndk
./gradlew :android:assembleReleaseThe AAR task invokes scripts/build-android.sh through the
buildAndroidNativeLibs dependency. Run the script directly only when native
libraries are needed without assembling the AAR.
The native build produces libmail_jni.so for arm64-v8a, armeabi-v7a,
and x86_64. The library name intentionally remains mail_jni for
System.loadLibrary("mail_jni") compatibility. Android currently targets
minSdk 23 and compiles against SDK 36.
Rust application ──────────────────────────────> rusted-mail
Python application
└─ typed asyncio API (`rusted-mail` distribution)
└─ native extension (`rusted-mail-python`)
└─ protocol engine (`rusted-mail`)
Android application
└─ Kotlin coroutine API (`android`)
├─ optional encrypted store (`android-turso-store`)
├─ optional Turso administration (`android-turso-cloud`)
└─ libmail_jni.so (`rusted-mail-android`)
└─ JNI bridge (`rusted-mail-jni`)
└─ protocol and storage engine (`rusted-mail`)
- Credentials are redacted from Rust debug output and should never be written to application logs.
- TLS or STARTTLS is required by the typed server configuration.
- Private, local, link-local, and otherwise restricted network targets are rejected by default. Use exact runtime allowlist entries for intentional enterprise endpoints instead of globally permitting private targets.
- Request, response, message, attachment, and chunk limits are configurable through the runtime API; apply tighter app-side limits to untrusted UI, IPC, plugin, import, and WebView inputs.
- The JSON local store is plaintext. Applications storing sensitive mail should use the encrypted Turso-backed option and keep database paths under app-private storage. Existing JSON data is not migrated automatically.
- Outbound attachment paths should be disabled when unnecessary or constrained
to an app-private
attachmentRootbefore accepting requests from untrusted callers. - CI runs RustSec auditing and dependency review. The documented temporary
advisory exception is recorded in
audit.toml. - OpenPGP and S/MIME support is feature-gated and considered preview quality.
crates/rusted-mail/ Rust engine and public API
crates/rusted-mail-jni/ JNI bindings
crates/rusted-mail-android/ Android shared-library target
android/ Kotlin API and AAR module
android/turso-store/ Encrypted Android store and sync integration
android/turso-cloud/ Turso Cloud administrative client
docs/ Kotlin API reference
scripts/ Native build helpers
Issues and pull requests are welcome. Keep changes scoped to the appropriate package boundary, add tests for behavior changes, and run the Rust and Android checks relevant to your change before opening a pull request.
Rusted Mail is available under the MIT License.