Featured image of post I Wanted to Build My Own SMS Verification Code Platform — So I Scrubbed the Entire Internet for Open-Source Solutions

I Wanted to Build My Own SMS Verification Code Platform — So I Scrubbed the Entire Internet for Open-Source Solutions

Searched 243 repositories across 6 parallel queries with the GitHub API maxed out, then deep-dived into 33 open-source projects, reading each README and codebase one by one. The conclusion was stark: no open-source project is a true 'verification code platform' — they all solve only a single layer.

All star counts, licenses, and last-activity timestamps in this article are based on direct measurements via gh api repos/OWNER/REPO (2026-09-15), and one discrepancy was caught and corrected through adversarial review from a skeptic’s perspective. I read the README and main code directories of all 32 projects individually. This is a technical research report; it does not cover any methods to evade detection or gray-area operations.

I Wanted to Self-Host an SMS Receiving Platform, and Rummaged Through the Entire Open-Source Ecosystem

The motivation was simple: I wanted to centralize the SMS verification codes for several of my phone numbers—on one hand, it’s more convenient to receive codes across multiple numbers in one place; on the other, I’m done with the privacy exposure that comes from public SMS-receiving websites. I assumed the open-source world already had a ready-made solution for this—just pull a docker-compose and run it. Instead, a glaring fact emerged after searching:

There is not a single open-source project that is truly an “SMS receiving platform.”

By “truly an SMS receiving platform,” I mean a system that has all five core features: phone number pool management + number renting/retrieval + incoming message display + multi-user system + billing and orders—the kind of product you’d see from sms-activate, 5sim, or SMSPool that sells numbers and receives SMS for external users. None of these five features have a ready-made open-source implementation. Every project only solves one layer: the forwarding layer, the device layer, the protocol layer, the gateway layer, or the upstream aggregation layer. To build one yourself, you need to assemble these layers on your own.

How I Searched

Six parallel search tracks: GitHub (both Chinese and English) via gh search repos using dozens of keyword groups (sms receiving/SMS forwarding/virtual number/sms-activate/virtual number/SMS gateway/SIM bank, etc.), Tavily, Grok, Metaso (秘塔) Chinese sources, plus discussions on Hacker News, Reddit, V2EX, and Linux.do, as well as the awesome-selfhosted list. Initial screening yielded 243 repositories. I used gh api to batch-fetch stars, last-push dates, and archived status for tiered sorting, then deep-dived into the top 16 by reading READMEs and code. A “completeness critic” agent was used to fill gaps, which led to 8 additional low-star repositories that seemed to have platform-like characteristics, bringing the total to 33. Final adversarial review caught and corrected one discrepancy. Another 226 low-star repositories were placed on a deferral list with links at the end for those who want to explore further.

Overview at a Glance

The table below covers 19 projects directly relevant to “self-hosted SMS receiving.” ✓/✗ indicates presence/absence of a capability; “Number Pool” = phone number pool management (number retrieval/renting/scheduling by number for receiving SMS); “Billing” = balance/orders/per-SMS billing.

Project⭐LicenseTech StackSMS SourceWeb UIMulti-UserNumber PoolBillingAPIDockerActivityMaturity
SmsForwarder27983BSD-2Kotlin/AndroidAndroid real device✗✗✗✗✓✗ActiveProduction
android-sms-gateway5719Apache-2Kotlin+GoAndroid real device✓ (self-host)✗✗✗✓✓ActiveProduction
httpSMS5100AGPL-3Go+Kotlin+TSAndroid real device✓✓✗✓ (quota)✓✓ActiveProduction
textbee3096MITTS/Next+NestAndroid real device✓✓✗✓ (optional)✓✓ActiveProduction
telegram-sms1957BSD-3KotlinAndroid real device✗✗✗✗✗✗ActiveProduction
chenxuuu/sms_forwarding1502MITC++/ESP32SIM card modem✓ (device UI)✗✗✗✗✗ActiveMinimal
gosms1467GPL-2GoSIM modem (send only)✓✗✗✗✓✓ (stale)Abandoned ‘21Abandoned
playSMS881GPL-3PHP+MySQLGSM modem/SMSC✓✓✗✓✓—ActiveProduction
SMSSync1214LGPL-3Java/AndroidAndroid real device✗✗✗✗✗✗Abandoned ‘21Abandoned
Jasmin1200Apache-2PythonUpstream SMPP/HTTP✗✓✗✓ (Redis)✓✓Active since ‘04Production gateway
SMSGate1188Apache-2Java/NettyCarrier CMPP/SMPP✗✗✗✗✗✗Active since ‘07Protocol library
SMSHub (juancresc)276NoneKotlinAndroid real device✗✗✗✗✓✗Abandoned ‘21Minimal
SMSBazaar333MITReact+Express+SQLiteUpstream SMS APIs (7 providers)✓✗✗✗✓CF WorkersActiveMinimal
MaDao29AGPL-3Rust+Tauri2+React19Upstream SMS APIs (HeroSms/5Sim/SMSBower)✓✗✗✗✓✓Inactive since ‘05Client (half-finished)
Kalkun237GPL-2PHP+gammuGSM modem✓✓✗✗✓—Active since ‘08Production
go-smpp255MITGoUpstream SMPP✗✗✗✗✗✗Active since ‘04Protocol library
smstools35GPL-2CSIM modem✗✗✗✗✗✗Inactive since ‘17Legacy production
Kannel (mirror)63BSD-likeCGSM modem/SMPP✗✓ (static)✗✗✓✗Inactive since ‘18Legacy production
smshub (profullstack)3UnclaimedNext16+SupabaseTwilio/Telnyx✓✓✗✗✓—NewToy demo

Note the Number Pool column: all 19 are ✗. This is the empirical proof of that glaring conclusion from the introduction—no project treats “number pool” as a first-class citizen. Only a handful brush against billing: httpSMS (quota-based, not payment), textbee (optional Polar integration), Jasmin (Redis billing engine), and playSMS (credit-based), none of which support a consumer-facing SMS-receiving sales flow.

The Five Layers, in Detail

Layer 1: Forwarding—Using Real Devices/Apps as Probes to Push SMS Out

This is the most active layer in open source. The core idea is consistent: run an app on a spare Android phone with a SIM card, and forward incoming SMS messages somewhere. The differences lie in the forwarding destination and whether a server component exists.

SmsForwarder (27983★, BSD-2) is the undisputed king—28K stars, actively maintained. Install it on a spare phone to forward SMS/calls/notifications to 20+ channels including DingTalk, WeChat Work, Feishu, Telegram, and Webhooks. Since V3.0 it also embeds an HTTP server for remote SMS sending/querying, with built-in frpc for NAT traversal. But it’s a single-device, single-number forwarder, not a platform: no web admin panel, no multi-user support, no number pool, no billing, and no server/Docker deployment. Its proper use is as an “SMS source endpoint”—run one instance per spare phone and push verification codes to your own upper-layer system via Webhooks. Pitfalls: Android background keep-alive is notoriously unreliable; manufacturers silently kill the app and drop forwarded messages. Exposing the remote SMS API to the public internet (especially with frpc) is a high-risk attack surface—token leakage means SMS interception.

The next step up is turning “phone→API/Web” into a server-backed system. Three projects in this tier are particularly solid:

android-sms-gateway (5719★, Apache-2) turns your phone into an SMS gateway with REST API send/receive, webhook push, multi-SIM/multi-device support, end-to-end encryption, and SMPP v3.4. Three modes: local device HTTP (LAN direct), official cloud, and self-hosted private server (Go-based server + MySQL + optional Web Dashboard, all open source). The private server push chain depends on Firebase FCM, which is blocked by the GFW in China—a hard limitation.

httpSMS (5100★, AGPL-3) is the closest to a “platform” in this batch: Go (Fiber) + Postgres/Redis + Nuxt web frontend + Kotlin app. It has a web UI, multi-user/API key auth, webhook forwarding for received SMS, end-to-end AES-256 encryption, send-rate backpressure, and a commercial hosted version at httpsms.com. But its billing is only a monthly quota per subscription tier—no payment processing, no number pool or rental concept. One phone, one number. Self-hosting is tedious: Firebase (FCM), SMTP, and Cloudflare Turnstile all need configuration, and the Android app must be self-compiled. AGPL-3.0 has viral licensing implications—if you modify it and provide it as a service externally, you must open-source your changes.

textbee (3096★, MIT) uses a full TypeScript stack (Next.js + NestJS + MongoDB + Redis + Kotlin client). It offers a web dashboard, REST API, multi-user, multi-device, CSV bulk send, receive webhook, and even an official MCP server for AI agent integration. It supports both sending and receiving (can receive OTPs). Billing is an optional Polar integration. Like httpSMS, self-hosting requires compiling your own Android app (configure Firebase, globally replace domain names), and FCM connectivity is equally blocked in China.

telegram-sms (1957★, BSD-3) takes a minimalist approach: the app listens for SMS and pushes to a Telegram bot, supports remote SMS sending via chat commands, and USSD execution. No web UI, no API, no billing—one instance per phone. The main repo’s releases stopped in 2021; newer versions are in a separate nightly repo with incompatible signing, requiring uninstall and reinstall (data loss risk).

For the absolute lowest hardware cost, check chenxuuu/sms_forwarding (1502★, MIT): an $4 ESP32C3 + ML307R 4G module (¥28), with one Nano SIM per device. The firmware forwards received SMS via 8 channels including Bark, DingTalk, and Feishu, with a built-in web config page. It’s the “minimal unit of a SIM card pool gateway”—one device, one card. Multiple numbers = multiple hardware units, no centralized management. The README explicitly states “for receiving SMS only.” Multi-card control, open API, and automation “will never be supported.” Using it as the core of an SMS receiving platform will hit a wall. Default web credentials are admin/admin123—changing the password is a prerequisite for going live. China Telecom SIMs are only supported in the official kit; DIY builds work with China Mobile/Unicom only.

Layer 2: SIM Card Pool / Modem Gateways—Hardware Send/Receive with Web Management

This layer uses GSM modems (USB dongles, multi-SIM GoIP devices) with SIM cards, sending and receiving SMS via AT commands, with a web management layer on top. The characteristics are “can send and receive, has a web UI, supports multi-user,” but again, no number pool or SMS-receiving business logic.

playSMS (881★, GPL-3) is the most mature in this tier: a veteran PHP web SMS gateway that connects to GSM modems or external SMSCs via backends like Gammu, Kannel, or Jasmin. It can send and receive, with multi-user support, credit-based billing, multi-domain, API, and a plugin system. Received SMS can be forwarded to email or user phones. It’s only missing “number pool + number retrieval + OTP extraction + receiving orders”—a bundle of business logic that the plugin system does support you extending toward. The PHP stack is somewhat dated; security hardening is your responsibility. It depends on an external SMSC backend for receiving SMS, so you need your own GSM hardware or carrier channel.

Kalkun (237★, GPL-2) is a lighter counterpart to playSMS: based on gammu-smsd, with web management (inbox/outbox/conversations/contacts/scheduling/templates/bulk send/multi-language), multi-user + multi-modem + API. No billing/subscriptions/voting features, but core send/receive and multi-user are solid. If you only need “GSM modem send/receive + web management,” it’s leaner than playSMS.

gosms (1467★, GPL-2) is a Go-written local sending gateway that drives GSM modems via serial AT commands for SMS sending, with queue/retry/throttling/HTTP API and a simple web dashboard. But it only sends, doesn’t receive—misaligned with the SMS receiving direction. Unmaintained since 2021; the Dockerfile is based on Ubuntu 14.04 and essentially dead. Useful only as an architectural reference.

Deeper legacy projects: smstools3 (5★, GPL-2) is a C daemon since 2000, directly connecting to up to 64 modems via AT commands, with file spool I/O extensible through eventhandler scripts. It ran in Linux production for years, but this repo is just a 2017 manual mirror; upstream is defunct. Kannel (63★, BSD-like) is a veteran C gateway since 1998, routing SMS between GSM modem/SMPP/CIMD2/EMI protocols and HTTP interfaces. Can send and receive but has no web UI, number pool, or billing. The mirror stopped in 2018. Today, the more common choices are to use playSMS/Kalkun directly or skip them altogether.

Layer 3: Protocol Stack—SMPP/CMPP for Carrier/SMS Gateway Integration

When your upstream is a carrier or SMS service provider’s SMSC (Short Message Service Center), you need a protocol stack to receive and send messages. This layer is further from “SMS receiving”—it’s infrastructure.

Jasmin (1200★, Apache-2) is a battle-tested open-source A2P SMS gateway: dual SMPP/HTTP protocols, multi-user + credentials + quotas, Redis-based billing/rate API, Failover/Least-cost enterprise routing, Celery + AMQP store-and-forward, and Grafana/Prometheus monitoring. It solves “routing SMS and billing,” but provides no number assets—the number pool, OTP extraction, and rental orders for SMS receiving all need to be self-built. Management is via the jcli command line on Telnet 8990, with no web interface, making operations steep. No SQL database; config is file-based (pickle store). SMPP ecosystem barriers: upstream requires direct connection to a carrier or virtual number provider’s SMSC. Individual users without direct access can only use it as an HTTP forwarding engine.

SMSGate (1188★, Apache-2) is a Java protocol core library (Maven dependency sms-core), built on Netty 4, implementing parsing for the three major Chinese carrier enterprise SMS protocols: CMPP, SMPP, SGIP, and SMGP. Supports long SMS segmentation/concatenation, flash SMS, and WAP SMS. Prerequisite: you already have an enterprise SMS channel account from a carrier—this itself requires SP licensing and signature registration, which is a different scenario from “SMS receiving” (receiving verification codes). Netty knowledge required. The author also provides sms-client (send-only) and smsServer (Spring Boot gateway) as companion projects.

go-smpp (255★, MIT) is a Go SMPP 3.4 protocol library with Transceiver binding, PDU encoding/decoding, GSM 7-bit/UCS-2 text encoding, and a test server. Pure protocol component—you need to add the author’s sms-api-server separately for HTTP API access.

Layer 4: Upstream Aggregation Panels—Bridging sms-activate-Style APIs

This layer is closest to the “SMS receiving ecosystem,” but本质上 it’s a price comparison tool/frontend shell—the core number retrieval and SMS receiving still calls upstream APIs.

SMSBazaar (333★, MIT) aggregates 7 SMS receiving platforms (Hero SMS, SMSBower, 5sim, NexSMS, GrizzlySMS, SMS Verification Number, SMSPool), providing real-time price (CNY+USD) and stock comparison dashboards, specifically targeting OpenAI/ChatGPT verification code scenarios. Supports filtering by country/platform/status, four business modes (OAuth registration/OAuth binding/recommended country/WhatsApp), auto-refreshes every minute, and deploys on both VPS and Cloudflare Workers. Still actively updated as of 2026-09. It is not an SMS receiving platform itself—it’s a price comparison layer for SMS receiving platforms. No number pool, no number retrieval, no SMS receiving, no multi-user. It just calls upstream APIs to check prices and stock and displays them. The Cloudflare Workers free tier has a KV write limit (1,000 writes/day).

profullstack/smshub (3★, Unclaimed) was created in 2026-09. The tech stack is extremely modern (Next.js 16 + React 19 + Supabase + Expo + Electron) with full-platform coverage, but it sends/receives via Twilio/Telnyx commercial APIs—no number pool, no billing, no OTP extraction. The README mentions “Coming Soon: phonenumbers.bot,” hinting at a potential pivot toward SMS receiving. For now, it’s just an architecturally elegant toy demo.

MaDao (29★, AGPL-3) added per user request. It’s the most complete number-retrieval routing client in this tier: a Rust+Tauri 2 desktop app (also supports Docker web console + HTTP API), aggregating three upstreams (HeroSms, 5Sim, SMSBower). It implements the full SMS receiving client business flow: “route planning by service/country/carrier, multi-round failover, price filtering, retrieve number → poll for OTP → release ticket, webhook callback for verification codes, number reuse pool (TTL/usage limits), real-time dashboard,” plus optional anonymous aggregate statistics (Cloudflare Worker + D1). But it’s a client, not a platform—it doesn’t own a single number or number pool; all numbers are rented from upstream SMS providers. Billing happens upstream; locally it only displays balance. AGPL-3 is highly viral. Essentially inactive since 2026-05 (small 29★ project; use with caution). If you want to self-build an “retrieve number + route + receive code” SMS receiving client, this is the most reference-worthy open-source implementation in this tier. If you want to self-build a “platform,” it won’t help.

Layer 5: Exclusions—Commonly Searched but Irrelevant

These projects keep appearing in search results with decent star counts, but are unrelated to “self-hosted SMS receiving platforms.” Including them in the table would mislead selection:

  • Cloud phones / real-device farms (no SMS capability): docker-android (15848★, Android emulator Dockerized; its only SMS feature is adb-injected virtual SMS), redroid (6813★, cloud Android containers; SMS capability depends on installed apps), openstf/stf (13941★, real-device remote control farm; zero SMS references across the entire repo, abandoned), DeviceFarmer/stf (4559★, active STF successor, also no SMS), Sonic (2210★, cloud real-device testing platform; entire org archived H1 2025), phonebox (1★, multi-tenant emulator cloud, no SMS). Their only relevance: if you go the real-device/cloud-phone-with-SIM route, you can use them to manage device clusters and remotely view verification codes on screen—but that’s manual viewing via remote desktop, not automated SMS receiving, and would require significant additional development.
  • Send-only (opposite direction from receiving): TextBelt (3386★, email-to-SMS sending, abandoned 2024, effectively defunct), overtrue/easy-sms (3337★, PHP sending SDK aggregating 30+ providers), SMS4J (1282★, Java sending SDK). Direction is opposite, but their multi-gateway abstraction design is worth studying.
  • OTP sending/verification (reverse direction): otpgateway (549★, sends OTP and verifies user input; does not receive SMS).
  • Crawlers / directories / articles (no code): tmpsms (1083★, CLI to scrape Upmasked free SMS receiving sites; author states it’s already dead), sms-jiema (364★, pure Markdown SMS receiving website directory), free-sms-receivers (1138★, article recommending 16 third-party platforms), eSIM-Tools (2113★, Giffgaff/Simyo eSIM conversion tool, unrelated).

How to Self-Host: Three Viable Routes

Assembling the layers above, three feasible routes exist depending on your goal.

Route 1: Personal use only, lightweight and cheap. You just want to centralize verification codes for your own numbers, not serve others. The cheapest option is the ~¥28 ESP32+4G module solution from chenxuuu/sms_forwarding—one card per device, stack N devices, and write your own webhook aggregator to funnel each device’s pushes into one database. Or for less effort, install SmsForwarder on several old Android spares and webhook-push to your Telegram or custom endpoint. Number pool scheduling? Not needed for personal use—one number, one channel is fine.

Route 2: Public-facing service, but numbers are your own. You want a platform with a web UI, multi-user support, and APIs, but the SMS comes from实体 SIM cards you own. Base it on httpSMS or textbee—their multi-phone ingestion, multi-user, API, and webhook capabilities are ready; you just need to self-build the number pool/orders/billing layer on top. The biggest pitfalls are FCM dependency (hard blocker in China), horizontal scaling limits of one-phone-one-number (stacking real devices), and Android background-kill missed messages. If AGPL (httpSMS) is a concern, also watch open-source obligations.

Route 3: SIM card pool hardware route. You have a GSM modem pool (multi-SIM GoIP/dongle devices) and want direct modem send/receive. Use playSMS or Kalkun as the web management layer + Gammu/smstools3/Kannel as the modem send/receive engine, with Jasmin optionally handling SMPP routing and billing. This route has the heaviest maintenance burden (modem drivers, carrier risk control, 3G/4G partial GSM SMS channels being decommissioned), but your number source is fully self-owned and independent of FCM. The SMS receiving business logic (number pool, number retrieval, OTP extraction) still needs custom plugin development.

Route 4 (gray area, pointed out but not expanded): Upstream API integration. Directly integrate with SMS receiving platform APIs like sms-activate, 5sim, SMSPool, using SMSBazaar as the price-comparison layer, and self-build a frontend for number retrieval + SMS receiving + billing—this is the fastest path to a real “SMS receiving platform"形态, but the numbers are upstream-owned, not self-owned, and upstream number sources are largely gray-market. This route has the lightest tech stack but the heaviest compliance risk. See the next section.

Compliance and Risk Boundaries (Must Be Stated Clearly)

This section does not expand on any operations—only draws lines. Receiving SMS on your own phone numbers is legal—receiving verification codes for your own numbers is perfectly legitimate, and Routes 1–3 in this article all fall on this side of the line.

But operating a public SMS receiving platform and renting numbers to others for bulk account registration is a completely different matter: it violates the Terms of Service of virtually every platform, and in China carries criminal risk under Article 287-2 of the Criminal Law—“crime of assisting information network criminal activities” (帮信罪)—where knowing that others are using information networks to commit crimes and still providing assistance (number sources, technical support) constitutes an offense. Upstream number sources for SMS receiving platforms themselves come largely from gray/black markets (stolen accounts, fraudulent real-name registration, overseas black-market SIMs), and carrier/platform risk control has tightened considerably in recent years. Cloud phone solutions also face app-side container-environment detection and account bans. So this article’s positioning is purely technical research: which open-source projects solve which layer, and how to assemble them. Assembling them into a public, number-selling SMS receiving service and operating it—that’s a separate matter, and not what this article teaches.

Selection Conclusions (By Scenario)

  • Personal multi-number code receiving → SmsForwarder (old phones) or chenxuuu/sms_forwarding (¥28 hardware); write your own webhook aggregator. Don’t try to platformize it.
  • Want a web UI / multi-user / API platform with self-owned numbers → httpSMS as the base (closest to platform形态), self-build the number pool/orders/billing layer; if AGPL/FCM is unacceptable, look at textbee.
  • Have a modem pool, want hardware-based send/receive → playSMS or Kalkun + Gammu; write custom plugins for SMS receiving business logic.
  • Need SMPP/CMPP protocol stack integration with carriers → Jasmin (mature gateway) or SMSGate (Chinese protocol stack); source your own number assets.
  • Want to compare upstream SMS receiving prices → SMSBazaar (aggregates 7 APIs)—but recognize it’s a dashboard, not a platform.

One-sentence summary: The open-source world has no ready-made SMS receiving platform—only a pile of scattered parts. Routes 1–3 can all be deployed within the legal personal-use boundary. If you want to directly clone an sms-activate to sell numbers publicly, the open-source world doesn’t have that wheel—and the gray-area nature of that path is something you should think through carefully before anything else.


The complete link list for the 226 deferred low-star repositories (including gammu, pysim, otpgateway, Kalkun, SMSHub variants, asterisk-chan-dongle, GoIP series, etc.) has been archived with the research. Space constraints prevent individual commentary; interested readers can reproduce the search using the keywords in this article via gh search repos. Star counts were sampled on 2026-09-15. Open-source project star counts and activity levels change over time—please re-run gh api to verify before making selections.