If you have a Turkish phone number, you know the problem. Betting sites that are illegal in Turkey buy leaked phone number lists and blast them with SMS — deneme bonusu, güncel giriş adresimiz, a shortened link, ten times a week. Then the calls start.
smspam is an iPhone app that drops those messages into the Junk folder before they ever buzz your phone. It runs entirely on your device, talks to no server, collects nothing, and costs nothing.
I built it because the app I was using went subscription-only. This one can't, because you have the source.
Not a mockup — that image is generated by actually running the engine
(python3 Tools/make_demo_svg.py), so it can never drift from the real rules.
- Scores every SMS from an unknown sender against a Turkish betting/spam rule set and files the junk away silently.
- Survives the tricks. Spammers write
b o n u s,b.o.n.u.s,d3n3m3 b0nusu,BOOONUUUS, and sprinkle zero-width characters between letters. Everything is normalized to one canonical form before scoring. - Protects the messages that matter. Negative-weight rules for doğrulama kodu,
kargonuz, faturanız, bank loyalty points, and the İYS opt-out footer
(
Ret için B001) that every legitimate Turkish commercial sender must include. - Updates its rule list from this repository — no App Store release needed.
- Optionally blends in a small on-device Core ML text classifier you train on your own messages.
- Blocks specific phone numbers via a Call Directory extension.
This is the part most READMEs leave out. These are Apple's limits, not bugs:
| Limit | What it means |
|---|---|
| Unknown senders only | Messages from people in your Contacts never reach the filter. |
| SMS/MMS only | iMessage is never passed to a filter extension. |
| No network in the extension | The filter cannot call out. The containing app fetches rules and hands them over through an App Group. |
| No writes from the extension | It cannot log what it caught, so there are no "blocked today" stats. |
| Junk, not delete | The best available outcome is the Junk folder with no notification. |
| Calls need exact numbers | The Call Directory API takes a sorted list of full numbers — no wildcards, no patterns. Combine it with Settings → Apps → Phone → Silence Unknown Callers, which is what actually stops the call flood. |
Each message gets a score. Keyword rules carry weights; regex rules catch
link shorteners, Telegram/WhatsApp invites, domains containing bet/bahis/casino,
throwaway TLDs (.xyz .top .cfd .click), mirror domains like site123.com, and
%500 bonus patterns. Sender signals add a little more: foreign numbers,
alphanumeric sender IDs that read like a casino brand.
Turkish is agglutinative, so rules match on the word stem — the kupon rule
also catches kuponlarımı.
Three sensitivity modes ship in the app: Loose (9.0), Balanced (6.0), Strict (4.0).
Run on every push (see ci.yml):
| Dataset | Mode | Spam caught | False positives |
|---|---|---|---|
dataset.csv — 50 spam / 50 legit |
Balanced | 50/50 | 0 |
dataset_hard.csv — evasion tricks + trap legit messages |
Balanced | 6/8 | 0 |
dataset_hard.csv |
Strict | 8/8 | 1 |
The first row is optimistic: the rules were tuned on that set. The hard set was written afterwards and never used for tuning, which is why it is the number worth watching. The two misses there are messages that read like a friend texting you a bare Telegram link — genuinely ambiguous, and Strict mode catches both at the cost of one false positive.
You need a Mac with Xcode, an iPhone on iOS 16+, and an Apple ID.
git clone https://github.com/ekrmsnr/smspam.git
cd smspam
./bootstrap.sh # generates the Xcode project via XcodeGen and opens itThen change com.ekrem.smspam to your own bundle prefix in
Shared/RuleStore.swift, project.yml, and the three .entitlements files,
re-run ./bootstrap.sh, pick your iPhone, and hit ⌘R.
On the phone: Settings → Apps → Messages → Unknown & Spam → SMS Filtering → smspam, and Settings → Apps → Phone → Call Blocking & Identification → smspam.
Free Apple ID: the signature expires every 7 days and App Groups are not available, so rule updates stay inside the app instead of reaching the extension. A paid account ($99/yr) removes both limits. Start free and see whether you like it.
Full walkthrough, including the manual Xcode setup if you'd rather skip XcodeGen: README.tr.md.
A spam SMS got through? Open an issue. That is the single most useful contribution to this project. Every reported message becomes a rule and a test case, and every install picks it up on the next update.
A real message got marked as spam? That's higher priority. Missing a bank code because of a bad rule is a real cost; missing a betting ad is not.
Editing rules yourself is a one-file change — see CONTRIBUTING.md.
rules/rules.json is the single source of truth; the Swift rule table is generated
from it and CI fails if the two drift apart or if a change makes the benchmarks worse.
- Real screenshots in this README
- Wider rule coverage for phishing/cargo scam SMS, not just betting
- A pre-trained Core ML model shipped in releases, so people can skip training
- Community rule sets for other countries
MIT — see LICENSE. Do what you want with it. If you ship it, a link back is appreciated but not required.
