Ошибки SMPP показывают, на каком этапе остановилась отправка SMS: шлюз отклонил запрос, сеть временно ограничила скорость или абонент не получил сообщение. В статье разберём коды ESME_RTHROTTLED, ESME_RINVSRCADR и другие ответы, свяжем их с DLR и разделим ошибки на временные и окончательные. После этого разработчик сможет настроить повторы, журналирование и уведомления так, чтобы система не отправляла один и тот же SMS бесконечно.
Что именно сообщает SMPP-ответ?
При передаче submit_sm приложение получает от SMPP-шлюза командный статус. Он отвечает на вопрос, принял ли шлюз запрос в обработку. Успешный ответ ещё не означает, что SMS дошло до телефона: окончательный результат обычно приходит позже в delivery receipt, или DLR.
Удобно разделять два события. SMPP-ответ описывает приём команды шлюзом, а DLR сообщает результат дальнейшей доставки. Если приложение проверяет только submit_sm, оно видит лишь начало цепочки и может ошибочно считать сообщение доставленным.
| Этап | Что проверять | Какой вывод сделать |
|---|---|---|
| Подключение | bind_resp и состояние сессии | Можно ли передавать команды через текущую SMPP-сессию |
| Приём сообщения | command_status в submit_sm_resp | Принял ли шлюз запрос и выдал ли message_id |
| Доставка | DLR и его delivery status | Дошло ли SMS до абонента или оператор вернул отказ |
| Контроль канала | enquire_link, тайм-ауты, disconnect | Жива ли сессия и можно ли продолжать отправку |
При разборе DLR полезно сохранять исходный текст receipt, message_id, время отправки и внутренний идентификатор операции. Без этой связи трудно понять, какой именно запрос завершился ошибкой, особенно когда система отправляет большой поток SMS.
Почему возникает ESME_RTHROTTLED?
ESME_RTHROTTLED означает, что шлюз ограничил скорость запросов. Приложение передаёт команды быстрее, чем разрешает текущая настройка соединения или маршрута. Повторить такой запрос сразу в том же темпе значит получить следующий отказ.
Обработчик должен поставить сообщение в очередь и повторить попытку после паузы. Размер паузы лучше вынести в настройки, чтобы менять его без новой сборки приложения. При повторных отказах интервал увеличивают, а число попыток ограничивают.
- Получить ответ ESME_RTHROTTLED.
- Вернуть сообщение в очередь с новым временем попытки.
- Увеличить задержку по выбранной схеме.
- После установленного числа неудач передать событие в журнал или мониторинг.
Один worker не должен бесконтрольно создавать новые потоки при ограничении скорости. Надёжнее использовать общий планировщик очереди: он видит число активных запросов и равномерно распределяет отправку между доступными SMPP-сессиями.
Параметры TON и NPI тоже влияют на принятие сообщения. Если проблема связана с адресацией отправителя или получателя в белорусском направлении, проверьте настройку TON/NPI в SMPP для SMS в Беларуси, а не увеличивайте количество повторов.
Как исправить ESME_RINVSRCADR?
ESME_RINVSRCADR сообщает, что адрес источника некорректен или не разрешён для этого подключения. Причина часто связана с полем source_addr: приложение передало значение в неподходящем формате, использовало неверный TON/NPI или выбрало отправителя, которого шлюз не принимает.
Такой отказ обычно относится к окончательным для конкретного запроса. Повтор с теми же параметрами результата не изменит. Сначала нужно исправить данные отправителя, проверить разрешённый формат и только потом создать новую попытку.
В конфигурации полезно хранить отправителя отдельно от текста SMS. Перед отправкой приложение проверяет, что значение заполнено, соответствует выбранному типу адреса и доступно этому SMPP-аккаунту. Ошибка должна попадать в журнал вместе с source_addr, TON, NPI и идентификатором маршрута.
| Ситуация | Действие приложения | Нужен повтор? |
|---|---|---|
| ESME_RTHROTTLED | Пауза, возврат в очередь, ограничение скорости | Да, с задержкой |
| ESME_RINVSRCADR | Остановить запрос, проверить source_addr и TON/NPI | Нет, пока параметры не исправлены |
| Недействительная сессия | Закрыть соединение и выполнить повторный bind | Да, после восстановления канала |
| Отказ доставки в DLR | Сохранить финальный статус и причину | Только по отдельному правилу для временных причин |
Как строить обработчик SMPP-ошибок?
Система обработки должна работать по таблице правил, а не по набору разрозненных условий в коде. Для каждого статуса задайте тип ошибки, допустимость повтора, максимальное число попыток и действие после окончательного отказа.
Минимальная запись в очереди может содержать message_id, номер получателя, текст или его ссылку, время следующей попытки, число повторов и последний код ошибки. Текст SMS не стоит менять при каждом повторе: иначе DLR и внутренний журнал будет сложнее сопоставить.
Для временных ошибок используйте отложенную очередь. Для окончательных отказов сразу фиксируйте результат и не возвращайте сообщение в обычный поток. Отдельный статус «требует проверки» пригодится для неизвестных кодов: приложение не потеряет событие и не начнёт бесконечный цикл.
При большом объёме трафика проверьте обработчик в тестовой среде. SMPP-песочница для проверки SMS, DLR и конкатенации помогает отделить ошибку бизнес-логики от особенностей реального маршрута. Для OTP отдельно проверьте повторы и связь результата с кодом подтверждения: полезен материал о передаче OTP-кода через SMPP с DLR и повторами.
Какие данные записывать в журнал?
- время отправки и время получения ответа;
- тип SMPP-команды и command_status;
- message_id, если шлюз его вернул;
- source_addr, TON и NPI;
- номер получателя в нормализованном формате;
- текст или безопасный идентификатор шаблона;
- DLR и финальный статус доставки;
- номер попытки и причина следующего повтора.
Логи должны позволять найти одну операцию по message_id и внутреннему идентификатору заказа. Если в журнале есть только общий текст «SMS не отправлено», разработчик не отличит ограничение скорости от неверного адреса отправителя.
Какие ошибки чаще всего ломают автоматическую отправку?
- Приложение считает успешный submit_sm_resp доказательством доставки.
- ESME_RTHROTTLED повторяется без паузы и перегружает очередь.
- ESME_RINVSRCADR отправляется повторно с тем же source_addr.
- Программа теряет message_id и не может связать DLR с исходным SMS.
- Неизвестный код автоматически трактуется как временный, поэтому очередь растёт бесконечно.
- После разрыва соединения приложение повторяет запрос, не проверив состояние сессии и риск дубликата.
Перед запуском проверьте несколько сценариев: успешную передачу, отказ из-за ограничения скорости, неверный адрес источника, разрыв SMPP-сессии и финальный отрицательный DLR. Для каждого сценария заранее задайте ожидаемый статус, число повторов и запись в журнале. Если трафик уже проходит через SMPP, настройку такого обработчика можно вынести в отдельный технический проект и проверить на тестовом подключении.
3 шага, которые можно сделать на этой неделе:
- Составьте таблицу кодов с колонками «временная ошибка», «повтор», «максимум попыток» и «действие после отказа».
- Свяжите submit_sm_resp, message_id и DLR в одном журнале операций.
- Прогоните тесты для ESME_RTHROTTLED и ESME_RINVSRCADR, чтобы система ставила паузу в первом случае и исправляла параметры во втором.


