Skip to content

Repository files navigation

Clear SMS

Android CI Latest release F-Droid Downloads License Rules Stars Forks

Clear SMS is an open-source, privacy-first SMS app for Android that automatically organizes your inbox. It categorizes messages (Important / Promotional / Personal / OTP), extracts transactions into a personal finance dashboard, surfaces bill reminders, and handles OTPs intelligently - all completely offline, on your device.

Download

Get it on GitHub Get it on F-Droid
  • GitHub: a signed ClearSMS.apk is attached to every release. It runs on any device: Clear SMS itself contains no native code, and the one APK carries every ABI variant of the two small native helpers AndroidX brings in (DataStore's shared counter and Compose's path parser, ~60 KB in total), so a single universal APK covers every CPU.
  • F-Droid: available at f-droid.org/packages/app.clearsms. The F-Droid build is reproducible and carries the same signature as the GitHub APK, so you can install from one source and update from the other.

Screenshots

Smart inbox Finance Alerts
Inbox Finance dashboard Alerts
Account detail Extracted transaction Search
Account detail Extracted transaction Search
Parsed notifications OTP notification Balance lock Dark theme
Parsed transaction notifications OTP notification Biometric balance lock Dark theme

Features

  • Smart inbox - messages are automatically sorted into Important, Promotional, Personal, Unknown, and OTP using a transparent, regex-based rules engine (no ML black box).
  • MMS receive & send - picture messages download automatically and can be sent from the compose bar (attach from the photo picker, camera, or any file; images are compressed to carrier limits on-device). Both directions ride the Android system's MMS service, over the carrier network only - see Privacy Principles. Image bubbles, a full-screen viewer, and attachment files stored app-privately. You can also share an image straight from your gallery into a new message. Group MMS is attributed to its sender; a dedicated group-conversation UI is not built yet, and MMS delivery reports are not supported (sent messages cap at "Sent").
  • Finance dashboard - debit/credit transactions are extracted from bank SMS into accounts, credit cards, and spend summaries with hand-rolled Compose charts.
  • Bills & reminders - upcoming bills and payment due dates in one Alerts view.
  • OTP handling - big, copyable OTP notifications, optional auto-copy, and configurable auto-delete (24h / 3d / 7d / never).
  • Scam awareness - heuristic flagging of likely scam/fraud messages.
  • Material You - dynamic color on Android 12+, with a curated teal/indigo palette on older devices. Light, dark, and system themes.
  • Community rules - categorization rules are plain JSON, bundled with the app and maintained by the community in this repository.

Feature checklist

Everything shipped, and what's on the roadmap:

Messaging

  • SMS send & receive (default-SMS-app role, catch-up import when the role is regained)
  • MMS receive (auto-download, image bubbles, full-screen viewer, retry on failure)
  • MMS send (photo picker / camera / any file, on-device compression, SIM-aware)
  • Dual-SIM (per-recipient SIM memory, SIM tags on messages); the compose bar shows the slot that will send, long-press names it, and it takes the system's own SIM colour where that stays legible
  • Message scheduling (long-press Send; survives reboots)
  • Optional delay before sending, with a Cancel that puts the text back for editing (off by default; survives the app being killed)
  • Opens sms:, smsto:, mms: and mmsto: links from other apps, with recipient and body prefilled
  • Per-thread drafts with inbox preview
  • Expand the compose box to fill the screen for long messages (both the standalone composer and a conversation)
  • Delivery status: Sending / Sent / Delivered (real reports only) / Not sent + retry
  • Share & forward selected messages; share text or images from other apps into a new message
  • Per-message details (type, to/from, sent & received time, delivery time when a real report exists, failure reason)
  • Tappable links, phone numbers and UPI payment links in messages (tapping a number opens the dialer; scam-flagged messages warn first)
  • Undo for delete & archive (Gmail-style snackbar)
  • Strip accents before sending, so one diacritic does not turn a single SMS into several (opt-in setting; applies silently, and only when it actually saves a message)
  • Configurable swipe dead zone with a live translucent preview, for phones where scrolling triggered swipe actions
  • Swipe-away in-app notification bars ("Message sent", schedule confirmations); swiping an UNDO bar keeps the deletion
  • Recycle bin (on by default, 30-day retention, restore & delete-forever; tap a binned message to read it in full first)
  • Call button in a conversation, and tap-the-name to view or create the contact (service senders explain themselves instead of doing nothing)
  • Pinned conversations
  • Blocked senders & blocked keywords (both go straight to the bin, silently; blocking also bins the existing conversation)
  • Contact names (instead of bare numbers) in the blocked-senders list
  • Group-MMS conversation UI (group messages currently attribute to their sender)
  • MMS delivery reports
  • Attachments persisted in drafts
  • Scheduling for messages with attachments (currently SMS-only)
  • Blocked keywords applied to MMS bodies
  • Video compression for MMS (oversized videos are refused with a clear message; real transcoding needs MediaCodec/Media3 Transformer)

Smart inbox

  • Automatic categorization: Important / Promotional / Personal / OTP / Unknown (460+ community rules + 715k sender directory)
  • Automatic full re-sort after an app update ships new rules, with a progress banner in the inbox
  • A rule added from a message applies to that sender's existing messages at once (body-only rules point you at the full re-sort instead)
  • Category filter pills (reorderable) with tags hidden under single-category filters
  • Hide whole sections you do not use (Inbox, Finance or Alerts) from Settings - the tab disappears and its notifications stop; at least one stays on
  • Full-text search with category & time filters, matching contact and sender names as well as message text
  • Tapping a search result opens the conversation at that message and highlights it, however old it is
  • Scam-awareness flagging
  • Rule manager: search, enable/disable, tap-to-edit your rules, duplicate bundled ones
  • Contact suggestions while typing a recipient (compose) or a sender to block
  • Alphabet fast-scroll in the contact list

Finance & alerts

  • Transactions extracted into accounts, cards & wallets with spend charts
  • Balance tracking with biometric balance lock
  • Bills, autopay, insurance & credit-card due reminders (CRED, BOBCARD statements and undated bills included)
  • Train & flight journeys in Alerts (including compact Indian Railways PNR messages)
  • Deliveries with courier & tracking id
  • Time-aware alerts with a complete, restorable "Older" archive
  • Cross-bank UPI duplicate collapsing; retirement contributions as credits
  • Conversation details screen (per-sender rename, category & finance view)
  • Per-conversation custom notifications

Notifications & OTP

  • Parsed transaction notifications with semantic colors and brand logos
  • Big copyable OTP notifications, auto-copy, auto-delete policies, one-shot cleanup
  • Always-visible Copy OTP button on OTP messages in a conversation
  • Notifications clear when messages are read in-app (recycle-bin-aware actions)
  • Missed-message notifications after signal loss or default-app switches
  • Messages from unrecognised senders get their own notification category, on by default
  • A Settings shortcut into Android's own per-category notification settings
  • App-wide biometric/PIN lock (today the lock covers Finance balances)

Data & privacy

  • Fully offline: no INTERNET permission (sole exception: the system's carrier MMS transaction)
  • Local backup & restore for messages AND settings (timestamped files, chosen folder, scheduled)
  • Settings backup with security-sensitive keys excluded by design
  • Encrypted backups

Privacy Principles

  • Offline by design. The app requests no INTERNET permission and makes no network calls of its own - no servers, no telemetry, no analytics. The one exception is inherent to MMS: retrieving a picture message is a transaction the Android system's MMS service performs with your carrier's MMSC over the carrier network. That transaction is how the MMS protocol works, never leaves the carrier network, and involves no third party.
  • No proprietary dependencies. No Firebase, no Play Services - pure AOSP compatible.
  • Your data stays on your device. Backups are local files you control.
  • Transparent categorization. Every rule is human-readable JSON you can inspect, edit, export, and contribute back.

Building

Requirements: JDK 17+ and the Android SDK (compileSdk 35).

git clone https://github.com/itsluminous/ClearSMS.git
cd ClearSMS
# point to your SDK if ANDROID_HOME is not set:
echo "sdk.dir=$HOME/Library/Android/sdk" > local.properties
./gradlew assembleDebug

Run checks the same way CI does:

./gradlew ktlintCheck lintDebug testDebugUnitTest

./gradlew assembleRelease produces a single universal APK under app/build/outputs/apk/release/ (Clear SMS has no native code of its own - the only .so files come from AndroidX's DataStore and graphics-path helpers - so per-ABI splits would save about 45 KB and cost an extra artifact to verify). Without signing environment variables (see below) it is unsigned. Release APKs are shrunk with R8 and resource shrinking but not obfuscated (-dontobfuscate in app/proguard-rules.pro), keeping the shipped APK auditable and the build reproducible for F-Droid verification.

Follow-up: Gradle dependency verification / lockfiles are not yet configured; CI validates the Gradle wrapper checksum but does not yet pin dependency hashes.

Release signing (CI)

CI builds release APKs on every push. If signing secrets are not configured (e.g. on forks), it still succeeds and produces unsigned APKs - signed publishing activates automatically once the secrets exist.

One-time keystore generation (keep this file and its passwords private; it is never committed - *.jks is gitignored):

keytool -genkeypair -v -keystore clearsms-release.jks -alias clearsms \
  -keyalg RSA -keysize 4096 -validity 10000

Then configure four repository secrets under Settings → Secrets and variables → Actions:

Secret Value
SIGNING_KEYSTORE_BASE64 base64 -i clearsms-release.jks output
SIGNING_KEYSTORE_PASSWORD the keystore password
SIGNING_KEY_ALIAS the key alias (e.g. clearsms)
SIGNING_KEY_PASSWORD the key password

Or with the GitHub CLI:

gh secret set SIGNING_KEYSTORE_BASE64 --body "$(base64 -i clearsms-release.jks)"
gh secret set SIGNING_KEYSTORE_PASSWORD
gh secret set SIGNING_KEY_ALIAS --body "clearsms"
gh secret set SIGNING_KEY_PASSWORD

Pushing a tag matching v* (e.g. v0.1.0) creates a GitHub Release with the signed ClearSMS.apk attached, with auto-generated release notes. Before tagging, add a changelog file for the new versionCode at fastlane/metadata/android/en-US/changelogs/<versionCode>.txt - F-Droid shows it as the "What's New" text (see docs/publishing-fdroid.md).

Contributing Rules

Categorization rules live under rules/ and are bundled into the APK at build time - every app update ships the latest community rules. See docs/adding-rules.md for a step-by-step walkthrough and CONTRIBUTING.md for the JSON schema.

Two ways to contribute:

  1. Pull request - add or edit a JSON file under rules/<region>/<category>/ and open a PR (use the "Rule contribution" issue template if you prefer filing an issue).
  2. Email from the app - in the app, go to Settings → Rules → Share rules with developer. This composes an email with your exported rules JSON attached; reviewed submissions are incorporated into the next release. There are no runtime rule downloads - the app stays fully offline.

Want a fully populated app for testing or screenshots without using real messages? Replay the synthetic demo corpus into an emulator - see scripts/demo/.

Finding missing rules using your own messages

The most useful contribution is telling us which of your messages the app fails to categorize. scripts/audit_rule_coverage.py replays the bundled rules and the sender-ID directory against a real SMS corpus and reports exactly that. It runs on your computer, needs no app build, and masks all digits by default so the output is safe to share.

1. Install the prerequisites

  • Python 3.8 or newer (python3 --version)
  • adb, from the Android SDK platform-tools (macOS: brew install android-platform-tools)
  • This repository: git clone https://github.com/itsluminous/ClearSMS.git && cd ClearSMS

2. Enable USB debugging on the phone

  • Settings → About phone → Software information and tap Build number seven times to unlock Developer options
  • Settings → Developer options → USB debugging → on
  • Connect the phone by USB and accept the "Allow USB debugging?" prompt
  • Confirm it is visible: adb devices should list your device as device (not unauthorized)

3. Run the check

python3 scripts/audit_rule_coverage.py --from-device

The script reads your SMS through adb into memory only - it writes no copy of your messages anywhere. Expect it to take a minute or two on a large inbox.

4. Read the report

  • Coverage - the share of messages that got a confident category.
  • Per-rule hit counts - which rules are doing the work.
  • Unmatched messages - grouped by sender and body shape, ranked by how often they occur. This is the list worth reporting: the senders at the top are the biggest gaps.
  • generic-* rule breakdown - messages caught only by the catch-all rules, listed per sender. Generic rules are a last-resort safety net, so anything here ideally deserves a sender-specific rule.

Useful flags: --top N (how many unmatched groups to print), --generic-top N (senders listed per generic rule), --no-generic-breakdown, and --min-coverage N (exit non-zero below a threshold, so the audit can gate CI).

5. Share the findings

Open an issue using the Rule contribution template and paste the unmatched groups and generic breakdown sections. Before posting, read what you are about to share:

  • Digits are masked as X, but check the text anyway - names, email addresses, URLs and order references are not masked.
  • Never pass --no-redact on anything you post publicly.
  • Do not attach a full corpus dump, and keep any corpus file outside this repository.
  • Better still, send a pull request: rules are plain JSON under rules/, and the schema is documented in CONTRIBUTING.md.

Rules must contain only generic patterns and public brand/sender names - never your account numbers, amounts or personal details.

If you would rather not use a computer at all, the app can do a simpler version of this: Settings → Rules → Share rules with developer emails your exported rules JSON, which tells us what you have had to add by hand.

Auditing from a file instead of a phone

If you already have a corpus exported as JSONL (one {"sender": ..., "body": ...} object per line):

python3 scripts/audit_rule_coverage.py corpus.jsonl --min-coverage 80

Sender ID database

The community-maintained sender ID directory lives at rules/sender_ids/india_sender_ids.json.gz. It is compiled into the SQLite asset the app ships (app/src/main/assets/sender_ids.db) with:

python3 scripts/build_sender_db.py \
  rules/sender_ids/india_sender_ids.json.gz \
  app/src/main/assets/sender_ids.db

After editing the JSON, rebuild the .db and include both files in your PR.

For small fixes to wrong upstream entries (e.g. a sender ID mapped to an unrelated business), you do not need to regenerate the large .db asset: add the corrected entry to rules/sender_ids/corrections.json and copy it to app/src/main/assets/sender_id_corrections.json (a unit test keeps the two identical). Corrections are consulted before the bundled directory, so they always win for the same normalized sender ID.

Brand identity table

Sender avatars for well-known brands are drawn from a curated table at rules/brands/brands.json, bundled into the APK as app/src/main/assets/brands.json (a unit test keeps the two copies identical - edit the rules/brands/ master and copy it over). For brands without bundled logo artwork (see below) the app renders an original mark from these facts - a circular tile in the brand's published primary color, a short monogram, and a category badge - with text color chosen by WCAG luminance so it stays legible.

Each entry looks like:

{
  "key": "hdfc",
  "name": "HDFC Bank",
  "category": "BANK",
  "color": "#004C8F",
  "monogram": "H",
  "senders": ["HDFCBK", "HDFCB"],
  "aliases": ["HDFC", "HDFC BANK"]
}
  • key - unique lowercase identifier (also the bundled-logo filename key).
  • category - one of BANK, CARD, WALLET, TELECOM, ECOMMERCE, DELIVERY, GOVERNMENT, UTILITY, INVESTMENT, HEALTH, TRAVEL, OTHER.
  • color - the brand's widely-published primary color as #RRGGBB.
  • monogram - 1–3 characters drawn on the tile.
  • senders - exact sender IDs after TRAI normalization (VM-HDFCBKHDFCBK).
  • aliases - whole-word names matched against resolved display names.

Bundled sender logos

The APK ships real logo artwork for 27 of the curated brands under app/src/main/assets/logos/ (~180 KB total, PNG, max 256 px). The images are assembled by scripts/build_logo_pack.py --bundle from the latest commits of two MIT-licensed projects (auraveni/global-bank-logos and cashfree/payments-icons-library); the exact commits each build used are recorded in the manifest, so the committed asset set stays traceable. Per-file provenance lives in app/src/main/assets/logos/MANIFEST.md; the upstream MIT licence texts are reproduced in NOTICE.

On the legal position: the upstream MIT licences cover those projects' packaging of the files - the logos themselves remain trademarks of the banks and merchants they identify, and are bundled solely to label message senders in your own inbox. Logos are never fetched at runtime (the app requests no network permission); brands without bundled artwork get the generated brand tiles described above.

The avatar fallback chain, in order: contact photo → bundled logo → generated brand tile → category glyph → letter avatar. All of it is gated behind Settings → Appearance → Show logos and contact photos, and every avatar renders as the same circular tile across the inbox, conversations, search, Finance and Alerts.

License

Apache License 2.0

About

Privacy-first Smart SMS app for Android that automatically organizes your inbox. It categorizes messages (Important / Promotional / Personal / OTP), extracts transactions into a personal finance dashboard, surfaces bill reminders, and handles OTPs intelligently - all completely offline, on your device.

Resources

Contributing

Stars

57 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages