The problem
Someone running GrapheneOS has already made up their mind about privacy. The app warns them at onboarding that SMS is not secure (#218), and they agree — that is why they are here. The person who has not been convinced is at the other end of the thread, and nothing in the app ever reaches them.
That asymmetry is the reason people stay on SMS. It is rarely the GrapheneOS user's choice; it is a contact who won't move. Every mechanism the app currently has points at the one person who already knows.
The proposal
An optional short note appended to outgoing SMS, inviting the recipient onto an encrypted messenger. User-editable, defaulting to:
Texts feel private. They aren't: signal.org
The wording deliberately avoids "SMS", "carrier" and "encrypted". The reader is not the person who already cares about this, and those are the words of someone who does; naming the belief before correcting it says the same thing without requiring any vocabulary. A handful of alternatives ship alongside it so that changing the note doesn't mean composing one:
You can't whisper over text: signal.org
Groups are more fun on Signal: signal.org
Photos look better on Signal: signal.org
Ever wish you could take a text back? signal.org
I'm on Signal too: signal.org
None of them claim an advantage the reader could get by switching to a different green-bubble app instead. Reactions were dropped from that list for exactly this reason — they work in iMessage and in Google Messages over RCS, and only the SMS fallback between them cannot carry one. Taking a message back survives the test, because the message the note is attached to is an SMS.
I'm aware of how that sounds, so the design is deliberately constrained:
- Off by default, opt-in, with per-conversation control.
- Segment-neutral. Appended only when the message still occupies the same number of SMS segments. If it would create a second segment, it isn't added, so it can never cost the sender money. This one rule also does the work of the alphabet check: a note carrying anything outside GSM-7 forces the whole message into UCS-2 and a segment from 160 characters down to 70, which shows up as an extra segment and is refused — no reasoning about encodings needed.
- Rate-limited to once per conversation per week. Repetition is what turns an invitation into spam, both for the person reading it and for the carrier filters watching a number that keeps sending the same link. A note that appears on every message is one that gets read once and ignored after.
- A note that did not fit does not start the clock, or one long message would silence it for a week without anyone having seen it.
- Sending fails open: anything unexpected sends the message exactly as written. A message is worth more than a note attached to it.
The segment count is asked of SmsMessage.calculateLength rather than reimplemented.
Why in the bundled app rather than a fork
The project's stated position is that this app should be avoided and people should use a real secure messenger. This is the only mechanism in the app that acts on that. Onboarding warnings and in-app banners inform someone who already agrees; this is the one lever available for actually reducing how much unencrypted messaging GrapheneOS users do, and it works by moving the other party rather than lecturing our own.
Status
Implemented and passing this repository's checks — build, ktlint, detekt and the unit test coverage gate. It is small and self-contained: the send path gains one call, plus a preference, a rate limit and the segment rule. Happy to open a PR if this is wanted, or to change any of the design first.
Questions
- Is this acceptable in principle, or out of scope for the bundled app regardless of how it's built?
- If the outbound form is unacceptable, is a dismissible in-app prompt in insecure threads worth having instead? It aims at the person already convinced, which is why I'm not leading with it.
- Any preference on where the setting lives — app settings, per-conversation settings, or both?
The problem
Someone running GrapheneOS has already made up their mind about privacy. The app warns them at onboarding that SMS is not secure (#218), and they agree — that is why they are here. The person who has not been convinced is at the other end of the thread, and nothing in the app ever reaches them.
That asymmetry is the reason people stay on SMS. It is rarely the GrapheneOS user's choice; it is a contact who won't move. Every mechanism the app currently has points at the one person who already knows.
The proposal
An optional short note appended to outgoing SMS, inviting the recipient onto an encrypted messenger. User-editable, defaulting to:
The wording deliberately avoids "SMS", "carrier" and "encrypted". The reader is not the person who already cares about this, and those are the words of someone who does; naming the belief before correcting it says the same thing without requiring any vocabulary. A handful of alternatives ship alongside it so that changing the note doesn't mean composing one:
None of them claim an advantage the reader could get by switching to a different green-bubble app instead. Reactions were dropped from that list for exactly this reason — they work in iMessage and in Google Messages over RCS, and only the SMS fallback between them cannot carry one. Taking a message back survives the test, because the message the note is attached to is an SMS.
I'm aware of how that sounds, so the design is deliberately constrained:
The segment count is asked of
SmsMessage.calculateLengthrather than reimplemented.Why in the bundled app rather than a fork
The project's stated position is that this app should be avoided and people should use a real secure messenger. This is the only mechanism in the app that acts on that. Onboarding warnings and in-app banners inform someone who already agrees; this is the one lever available for actually reducing how much unencrypted messaging GrapheneOS users do, and it works by moving the other party rather than lecturing our own.
Status
Implemented and passing this repository's checks — build, ktlint, detekt and the unit test coverage gate. It is small and self-contained: the send path gains one call, plus a preference, a rate limit and the segment rule. Happy to open a PR if this is wanted, or to change any of the design first.
Questions