Добавить в корзинуПозвонить
Найти в Дзене

Как я перестал кормить SMS-агрегатор и отправляю сообщения через Android-смартфон

Однажды утром я проснулся, открыл кабинет SMS-агрегатора и увидел там прекрасное: баланс ноль. Не «почти закончился», не «пора пополнить», а именно ноль. Деньги, которые еще несколько дней назад должны были спокойно жить на балансе, ушли в закат. Причем не на рекламную рассылку по всей стране, не на маркетинговую кампанию века, а на обычные рабочие SMS: клиенту пришел код, клиенту пришло уведомление, клиенту сообщили статус заказа. И тут я поймал себя на мысли: мы живем в странное время. У магазина есть свой номер телефона, есть тариф у оператора, есть пакет SMS, который уже включен в абонентскую плату. Но при этом веб-приложение отправляет сообщения через посредника, где одна SMS иногда стоит как маленькая чашка кофе. А если сообщения уходят часто, то этот кофе пьет уже не программист, а агрегатор. Некоторые SMS через агрегаторов сейчас доходят до 20-50 рублей за штуку. Для бизнеса, особенно в нынешнем режиме «считаем каждую операционную мелочь», это уже не мелочь. Это строка расходов
Оглавление

Однажды утром я проснулся, открыл кабинет SMS-агрегатора и увидел там прекрасное: баланс ноль.

Не «почти закончился», не «пора пополнить», а именно ноль. Деньги, которые еще несколько дней назад должны были спокойно жить на балансе, ушли в закат. Причем не на рекламную рассылку по всей стране, не на маркетинговую кампанию века, а на обычные рабочие SMS: клиенту пришел код, клиенту пришло уведомление, клиенту сообщили статус заказа.

И тут я поймал себя на мысли: мы живем в странное время. У магазина есть свой номер телефона, есть тариф у оператора, есть пакет SMS, который уже включен в абонентскую плату. Но при этом веб-приложение отправляет сообщения через посредника, где одна SMS иногда стоит как маленькая чашка кофе. А если сообщения уходят часто, то этот кофе пьет уже не программист, а агрегатор.

Некоторые SMS через агрегаторов сейчас доходят до 20-50 рублей за штуку. Для бизнеса, особенно в нынешнем режиме «считаем каждую операционную мелочь», это уже не мелочь. Это строка расходов, которая тихо растет, пока ты занят более важными задачами.

И я решил: хватит!

Идея простая: отправлять SMS с телефона магазина

схема отправки СМС
схема отправки СМС

Суть решения очень бытовая, почти смешная: берем Android-смартфон, ставим на него SMS Gateway, подключаем его к веб-приложению, и Laravel отправляет SMS не через агрегатора, а через этот телефон.

Сначала я внедрил это решение в своё Laravel-приложение, где работают сотрудники. Это внутренняя система для обработки заказов, клиентов и уведомлений и многое другое. Сотрудник нажимает кнопку в веб-интерфейсе, а SMS фактически отправляется через Android-смартфон с SIM-картой магазина.


Потом я сделал такую же интеграцию для платформы
Docpart.
Docpart часто используют магазины автозапчастей: там заказы, клиенты, статусы, уведомления, подбор деталей и вся повседневная рутина. А где есть заказы, там почти всегда нужны SMS. К тому же у меня уже был большой опыт в реализации нестандартных решений в данной платформе, самые интересные это Телеграм бот, интеграция с Авито, сканирование внутренних штрих-кодов прямо смартфоном и много другое.

Там сделал обычную для этой платформы настройку, чтобы администратор мог задать параметры шлюза без танцев в коде. Для таких систем это особенно важно: решение должно выглядеть не как лабораторный эксперимент, а как понятная настройка в админке.

Настройка шлюза отправки Docpart
Настройка шлюза отправки Docpart


Проблема в том, что через агрегаторы такие сообщения стали стоить слишком дорого. Когда одна SMS внезапно выходит в 20-50 рублей, это уже не “мелкие расходы на связь”, а отдельная статья затрат, которая начинает раздражать.

Я использовал проект:

https://github.com/capcom6/android-sms-gateway/releases
На смартфон ставится приложение, оно поднимает HTTP API, а сервер обращается к нему как к обычному внешнему сервису. Только вместо очередного агрегатора где-то далеко сообщение физически уходит с SIM-карты магазина.

Для клиента это даже лучше: SMS приходит с реального номера магазина. Не с абстрактного имени, не с короткого номера, не от «INFO», а с того телефона, который можно сохранить, узнать и при необходимости набрать.

Получается довольно честная схема:

• пока действует пакет SMS от оператора, сообщения уходят фактически в рамках уже оплаченного тарифа;

• когда пакет заканчивается, включается обычная тарификация оператора;

• стоимость все равно часто ниже, чем у агрегатора;

• номер отправителя принадлежит магазину;

• нет зависимости от баланса агрегатора, который умеет исчезать внезапно и драматично.

Как это выглядит в Laravel

В Laravel я сделал отдельный сервис для отправки SMS. Ничего космического: Guzzle, конфиг, basic auth при необходимости, POST-запрос на endpoint message.

Примерно так:

$response = $this->client->post('message', [
'json' => [
'deviceId' => config('sms_gate.device_id'),
'phoneNumbers' => [$phone],
'message' => $message,
'withDeliveryReport' => (bool) config('sms_gate.with_delivery_report', true),
],
]);
Сервис возвращает не просто true или false, а нормальную метаинформацию:
[
'ok' => true,
'message_id' => $messageId,
'error' => null,
]

Это важно. В реальном приложении «отправили SMS» не должно быть черной магией. Нужно понимать:

• ушел ли запрос;

• какой вернулся статус;

• есть ли message_id;

• что именно сломалось, если отправка не удалась;

• можно ли повторить попытку.

Я специально оставил send() как простой метод для мест, где нужен только boolean, и sendWithMeta() для нормального учета, логов и диагностики.

Почему не надо отправлять SMS прямо из контроллера

Вот тут начинается часть для программистов, чтобы было понятно: это не «прикрутил кнопку, которая дергает телефон».

SMS нельзя отправлять синхронно прямо из пользовательского запроса, особенно если это рабочее приложение для сотрудников. Сотрудник нажал кнопку, приложение должно быстро ответить. А телефон в этот момент может быть занят, сеть может задуматься, Android может проснуться не сразу, оператор может принимать SMS с задержкой.

Поэтому правильный путь — очередь.

Контроллер или бизнес-логика создают задачу:

SendSmsJob::dispatch($phone, $message);

А уже worker спокойно выполняет отправку в фоне.

Это дает несколько преимуществ:

1. Интерфейс не тормозит

Сотрудник не ждет, пока смартфон, оператор и мобильная сеть договорятся между собой.

2. Можно делать retry

Если телефон временно недоступен, задача повторится. Например, через 30 секунд, потом через 2 минуты, потом через 5 минут.

3. Можно ограничивать скорость

Не надо вываливать на телефон 500 SMS за одну секунду. Очередь позволяет отправлять сообщения дозированно.

4. Можно логировать результат

У каждой попытки есть статус: создано, отправляется, отправлено, ошибка, повторная попытка.

5. Можно разделить каналы

Например, обычные уведомления идут через Android Gateway, а критичные сообщения при аварии можно временно переключить на агрегатора.

Именно очередь превращает эту идею из «прикольного хака» в нормальный рабочий инструмент.

Что я добавил вокруг отправки

Чтобы схема была пригодна для бизнеса, одной функции sendSms() мало. Нужна обвязка.

Я вынес настройки в конфиг:

• URL SMS Gateway;

• логин и пароль;

• device_id;

• timeout;

• включать ли delivery report.

Это удобно для Laravel: меняешь .env, чистишь конфиг, и приложение работает с другим телефоном или другим адресом шлюза.

Где здесь экономия?

Экономия появляется не из воздуха, а из здравого смысла.

У многих магазинов уже есть корпоративная SIM-карта. На ней может быть пакет SMS. Этот пакет часто просто лежит мертвым грузом, потому что сайт и CRM отправляют сообщения через агрегатора.

В итоге бизнес платит дважды:

• оператору связи за тариф;

• агрегатору за каждую SMS.

После подключения Android SMS Gateway часть сообщений начинает уходить через уже оплаченный пакет. Когда пакет заканчивается, включается обычная тарификация оператора. Даже тогда это может быть гораздо дешевле, чем 20-50 рублей за SMS у посредника.

Для больших объемов надо считать отдельно. Для банковских OTP, массовых рассылок и юридически чувствительных сценариев агрегаторы все еще могут быть нужны. Но для рабочих уведомлений магазина, статусов заказов, сообщений сотрудникам и клиентских сервисных SMS такой подход отлично ложится в реальность малого и среднего бизнеса.

Что важно не забыть

Такое решение требует дисциплины.

Телефон должен быть постоянно включен, заряжен и подключен к сети. Лучше поставить его на отдельное место, дать нормальное питание и не использовать как личный аппарат.

Также нужно следить за безопасностью:

• закрыть доступ к SMS Gateway извне;

• использовать авторизацию;

• ограничить доступ по IP или VPN;

• не хранить пароль в коде;

• логировать отправки;

• не отправлять лишние персональные данные в SMS.

И, конечно, надо помнить про правила операторов. Если начать рассылать тысячи рекламных SMS, оператор может быстро объяснить, что тариф был не для этого. Но для транзакционных сообщений и внутренних рабочих уведомлений схема выглядит вполне жизнеспособно.

Итог

В итоге я получил простую и полезную систему: веб-приложение отправляет SMS через Android-смартфон, Laravel работает с ним как с HTTP API, отправка идет через очередь, результаты логируются, а бизнес перестает каждый раз вздрагивать при виде баланса агрегатора.

Самое приятное — клиент получает сообщение с номера магазина. Это повышает узнаваемость и доверие. А магазин экономит деньги, потому что использует уже оплаченный пакет оператора, а не покупает каждую SMS у посредника по цене маленького сувенира.

История началась с утреннего «почему баланс опять ноль?», а закончилась нормальным техническим решением, которое уже работает и экономит деньги. Иногда для оптимизации бизнеса не нужен большой рефакторинг, новая CRM или магический SaaS. Иногда достаточно старого Android-смартфона, нормальной очереди в Laravel и желания перестать оплачивать чужой праздник жизни.