Недоставка SMS через SMPP чаще всего связана с неверными параметрами команды, ошибкой в номере, кодировкой, лимитом скорости или фильтрацией на стороне оператора. В этой статье разберём, как читать submit_sm, проверять PDU, сопоставлять message_id с DLR и отличать временный сбой от окончательного отказа. После проверки вы сможете собрать короткий технический отчёт для разработчика или поставщика SMS-шлюза, не ограничиваясь сообщением «SMS не пришло».
С чего начать диагностику доставки SMS через SMPP?
Сначала определите, на каком участке пропало сообщение. В цепочке участвуют ваша система, SMPP-шлюз, SMSC, сеть оператора и телефон получателя. Если в журнале нет ответа на submit_sm, проблема начинается с соединения или параметров bind. Если шлюз вернул ошибку, SMSC не принял сообщение. Если submit_sm прошёл, но пользователь ничего не получил, нужен DLR и его статус.
Для каждой попытки отправки сохраните отдельную запись с временем, внутренним идентификатором сообщения, номером в нормализованном формате, текстом или его контрольной суммой, message_id от шлюза и итоговым статусом. Полный текст в техническом журнале хранить необязательно, если для расследования достаточно длины, кодировки и хеша. Главное, чтобы одну попытку можно было найти сразу в логах приложения, SMPP-клиента и поставщика.
Проверьте также состояние bind. Для постоянной отправки обычно используют режим transceiver, который позволяет отправлять сообщения и получать отчёты в одном соединении. При нестабильной сети соединение с SMSC может прерываться, а неверный сервер, порт, логин или пароль не позволят пройти bind. Практические проверки соединения и его стабильности собраны в материале как проверить скорость и стабильность SMPP-шлюза.
Что показывает submit_sm и где искать ошибку в PDU?
Команда submit_sm передаёт SMS-шлюзу параметры сообщения. Для диагностики смотрите не только текст, но и service_type, source_addr_ton, source_addr_npi, source_addr, dest_addr_ton, dest_addr_npi, destination_addr, esm_class, data_coding, registered_delivery, short_message или message_payload. Ошибка в одном поле иногда выглядит как недоставка, хотя оператор вообще не получил корректную команду.
Номер назначения сверяйте с исходным значением в бизнес-системе. Уберите пробелы, скобки и дефисы, затем проверьте международный формат, который ожидает ваш провайдер. Отдельно сравните TON и NPI с настройками подключения: при несовпадении шлюз может отклонить адрес ещё на этапе submit_sm.
Кириллический текст требует особого контроля. В SMPP для него обычно применяют UCS2, data_coding 0x08, а данные передают в UTF-16BE. При такой кодировке длина одного SMS составляет 70 символов, поэтому длинный текст разбивается на части. Если приложение считает длину как для однобайтовой кодировки или неправильно формирует UDH, получатель может получить обрезанное сообщение, несколько частей в неверном порядке либо отказ при обработке.
Для теста отправьте короткую фразу на один контрольный номер, затем отдельное сообщение на кириллице и длинный текст. В каждом случае сохраните исходный PDU в шестнадцатеричном виде и значения data_coding, esm_class, registered_delivery и sequence_number. Такой набор позволяет сравнить рабочую и проблемную отправку побайтно, а не искать причину по одному скриншоту из приложения.
Как читать ответ submit_sm и ошибку ESME_RSUBMITFAIL?
Ответ submit_sm содержит command_status и message_id. При успешном приёме команды статус обычно указывает на отсутствие ошибки, а message_id нужен для связи отправки с последующим DLR. Если система получила ESME_RSUBMITFAIL, SMS-шлюз не принял запрос на отправку. Искать причину доставки на телефоне в этот момент рано: сначала разберите параметры команды, текст ошибки и журнал шлюза.
Запишите полный ответ, включая числовой код и текст, если поставщик его передаёт. Само название ESME_RSUBMITFAIL слишком общее. Внутри конкретного шлюза отказ может быть связан с неверным адресом, недоступным маршрутом, ограничением скорости, параметром сообщения или временной ошибкой SMSC. Сравните неудачный запрос с тем, который получил успешный message_id.
| Что видно в журнале | Где искать причину | Следующая проверка |
|---|---|---|
| Нет ответа на bind или submit_sm | Сеть, сервер, порт, тайм-аут, состояние соединения | Проверить TCP-сессию, повторное подключение и журнал SMPP-клиента |
| Пришёл ESME_RSUBMITFAIL | Поля submit_sm, лимиты, маршрут, состояние SMSC | Сравнить PDU с успешным запросом и уточнить код у поставщика |
| Есть message_id, но DLR не приходит | registered_delivery, формат отчёта, канал получения DLR | Проверить настройки отчётов и чтение deliver_sm |
| DLR сообщает rejected или failed | Номер, сеть оператора, фильтрация, срок действия сообщения | Провести повторный тест с другим номером и коротким текстом |
| DLR сообщает delivered, но клиент не видит SMS | Телефон, SIM, приложение сообщений или особенности отображения | Проверить время доставки, папку сообщений и другой аппарат |
Как использовать DLR, чтобы отделить сбой отправки от недоставки?
DLR, или Delivery Receipt, приходит после submit_sm и сообщает, что произошло с конкретным message_id. Отчёт нужно связывать с исходной отправкой по идентификатору, а не по номеру телефона или времени. Один номер может получить несколько сообщений, а часы вашей системы и шлюза могут отличаться.
В deliver_sm проверьте esm_class, source_addr, destination_addr и поле с текстом отчёта либо TLV, которое использует поставщик. Формат DLR различается: один шлюз передаёт строку с id и stat, другой добавляет err, submit date и done date. Поэтому парсер лучше строить по документированному формату конкретного подключения и сохранять исходный deliver_sm до разбора.
Разделяйте статусы на группы. DELIVRD означает, что сеть передала сообщение на устройство или в конечный сегмент маршрута согласно правилам шлюза. EXPIRED указывает на истечение срока доставки. UNDELIV и REJECTD требуют анализа причины отказа. Статус ENROUTE ещё не подтверждает доставку: сообщение находится в обработке маршрута.
Если DLR не приходит, проверьте registered_delivery в submit_sm. Затем убедитесь, что клиент принимает deliver_sm и не отвечает на него ошибкой. При режиме transceiver входящие отчёты должны обрабатываться тем же соединением; при раздельной схеме нужен отдельный bind_receiver. Полезно также проверить, не теряются ли сообщения после перезапуска приложения и не отбрасывает ли их очередь из-за неизвестного message_id.
Какие причины недоставки встречаются чаще всего?
Технический сбой оператора или SMSC может временно остановить доставку. Операторы проводят работы и обновляют оборудование, поэтому серия ошибок за короткий период требует проверки аварий и маршрута у поставщика. Повторная отправка без ограничения приведёт к дублям, если первая попытка уже принята и DLR задерживается.
Отдельная причина — лимит скорости. При превышении throughput шлюз начинает отклонять submit_sm или возвращает ошибки, связанные с ограничением rate. Сопоставьте время отказов с числом запросов в секунду, очередью и настройкой submit_sm на одном bind. Для проверки снизьте скорость тестовой отправки и посмотрите, меняется ли command_status.
Фильтрация операторами также влияет на результат. Повторяющийся текст, подозрительные конструкции, ошибочный отправитель или неподходящий маршрут могут привести к отказу. Сравните короткий нейтральный тест с рабочим шаблоном, но не делайте вывод по одному номеру: нужен небольшой набор контрольных отправок, согласованный с поставщиком.
Какие типичные ошибки мешают найти причину?
- Система считает отправку успешной сразу после вызова API и не ждёт submit_sm_resp.
- message_id от шлюза не сохраняется, поэтому DLR невозможно связать с заказом или заявкой.
- Кириллица отправляется с data_coding 0x00 вместо UCS2 0x08.
- Приложение не принимает deliver_sm или отвечает на него с неверным sequence_number.
- Команда отправляется быстрее установленного лимита, а повторная попытка создаёт дубли.
- Разработчик проверяет только текст ошибки и не сохраняет полный PDU с параметрами.
Для малого бизнеса в Беларуси практичная схема выглядит так: приложение ставит SMS в очередь, SMPP-клиент сохраняет submit_sm_resp, отдельный обработчик принимает DLR, а мониторинг показывает долю успешных, отложенных и отклонённых сообщений. Если собственный разработчик подключает новый шлюз, параметры сервера, порта, TON/NPI, режима transceiver и лимитов лучше зафиксировать в одной конфигурации, а тестовые SMS и DLR провести до запуска массового трафика. Подробный порядок такой интеграции описан в материале как автоматизировать SMS-статусы доставки интернет-магазина.
3 шага, которые можно сделать сегодня:
- Соберите для одной неудачной SMS полный submit_sm, submit_sm_resp, message_id и все связанные deliver_sm.
- Повторите тест с коротким текстом, кириллицей и длинным сообщением, меняя только один параметр за раз.
- Сопоставьте command_status и статус DLR с лимитом скорости, кодировкой и настройками registered_delivery, затем передайте поставщику точный набор логов.



