Прямой ответ
SMS — самый дорогой канал уведомлений, поэтому используется только для сообщений, где требуется гарантированное получение вне зависимости от состояния приложения. Типичные случаи: код подтверждения, уведомление о критичном событии, оповещение при недоступности других каналов.
Стоимость определяется числом сегментов, на которое делится сообщение.
| Кодировка | Символов в сегменте | Сегментов при 200 символах |
|---|---|---|
| GSM-7 (латиница) | 160 | 2 |
| UCS-2 (кириллица) | 70 | 3 |
Кириллический текст кодируется UCS-2, поэтому помещает 70 символов в сегмент вместо 160. Сообщение из 140 кириллических символов занимает два сегмента и тарифицируется как два сообщения.
def sms_segments(text: str) -> int:
limit = 70 if any(ord(c) > 127 for c in text) else 160
return max(1, -(-len(text) // limit))
Отправка через API провайдера с фиксацией идентификатора:
r = httpx.post(f"{SMS_API}/messages", auth=AUTH, json={
"to": phone, "from": SENDER_ID, "text": text,
"reference": f"notif-{notification_id}",
}, timeout=15.0)
provider_id = r.json()["id"]
Статус доставки приходит асинхронно через уведомление провайдера, поэтому факт отправки не означает доставку. О разделении записи и отправки — в статье про архитектуру уведомлений.
Что влияет на доставку и стоимость
Четыре фактора определяют фактическую доставку и расходы.
Альфанумерический отправитель. Имя отправителя вместо номера повышает узнаваемость, но требует регистрации у оператора и не поддерживает ответы пользователя. Незарегистрированное имя отклоняется частью операторов.
Длина сообщения. Каждый сегмент тарифицируется отдельно, поэтому сокращение текста до одного сегмента снижает стоимость в два-три раза.
Частота отправки. Ограничение числа сообщений на пользователя в единицу времени предотвращает накопление расходов при сбое логики отправки; об ограничении запросов — в статье про rate limiting.
Повторные отправки. Повтор при отсутствии статуса доставки создаёт второе сообщение, поэтому повтор выполняется только после истечения интервала ожидания статуса.
Практическое следствие: расчёт стоимости выполняется до внедрения, поскольку кириллический текст в два с лишним раза дороже латинского при той же длине.
SELECT date_trunc('day', created_at) AS day,
COUNT(*) AS messages,
SUM(segments) AS segments_total
FROM sms_messages
GROUP BY 1 ORDER BY 1 DESC LIMIT 14;
Отдельный вопрос — статусы доставки. Провайдер возвращает статусы «доставлено», «не доставлено» и «в процессе». Статус «не доставлено» сопровождается причиной: номер не существует, телефон выключен, оператор отклонил сообщение. Причина определяет, выполняется ли повтор.
Выбор канала определяется типом события; о сравнении каналов — в статье про выбор канала уведомлений.
Практика: использование SMS в сервисе
1. Применяйте SMS только для критичных сообщений. Стоимость канала не оправдана для уведомлений, которые пользователь может получить в приложении либо по почте.
2. Сокращайте текст до одного сегмента. Сообщение в пределах 70 кириллических символов стоит в два-три раза меньше длинного.
3. Зарегистрируйте альфанумерический отправитель. Незарегистрированное имя отклоняется частью операторов, а сообщение не доходит.
4. Фиксируйте число сегментов при отправке. Учёт сегментов позволяет сопоставить расходы с тарифом провайдера.
5. Ограничивайте частоту отправки на пользователя. Сбой логики отправки без ограничения приводит к массовой рассылке и накоплению расходов.
6. Не повторяйте отправку до истечения интервала. Повтор при отсутствии статуса создаёт второе сообщение и двойные расходы.
7. Ведите учёт по дням и типам событий. Рост расходов определяется типом события, поэтому учёт ведётся в разрезе причин отправки.
Рекомендации:
- Не отправляйте длинные тексты через SMS. Подробное содержание передаётся ссылкой, а сообщение содержит краткую информацию.
- Учитывайте часовые пояса при отправке. Сообщение в ночное время воспринимается как навязчивое, поэтому учитывается местное время получателя.
- Различайте отказ номера и временную недоступность. Повтор выполняется при временной причине, постоянный отказ прекращает попытки.
- Мониторьте долю недоставленных сообщений. Рост доли указывает на проблему с отправителем либо с базой номеров.
- Документируйте перечень событий для SMS. Расширение перечня увеличивает расходы, поэтому решение фиксируется.
Практический сценарий: рост расходов на SMS в несколько раз
Контекст: месячные расходы на SMS выросли втрое при неизменном числе пользователей.
- Диагностика. Учёт по дням показал рост числа сообщений, а по типам событий — преобладание уведомлений о статусе заказа. Среднее число сегментов на сообщение выросло с одного до трёх.
- Причина. Текст уведомления о статусе заказа расширили подробным описанием, и сообщение перестало помещаться в один сегмент. Одновременно добавили отправку при каждом изменении статуса, поэтому число сообщений на заказ увеличилось.
- Действия. (а) Сократили текст уведомления до одного сегмента, перенеся подробности на страницу заказа по ссылке; (б) ограничили отправку SMS только критичными изменениями статуса, остальные перевели на push и почту; (в) добавили ограничение числа сообщений на пользователя в сутки; (г) включили учёт сегментов и метрику расходов по типам событий; (д) добавили проверку длины текста в тестах шаблонов.
- Результат. Число сегментов на сообщение вернулось к единице, а расходы снизились до прежнего уровня при сохранении информирования пользователей.
Вывод: стоимость SMS определяется числом сегментов и частотой отправки, поэтому расширение текста и добавление поводов для отправки кратно увеличивают расходы. Ограничение длины сообщения и перечня событий возвращает расходы к расчётному уровню.
FAQ
Сколько символов помещается в одно SMS? 160 в кодировке GSM-7 для латиницы и 70 в UCS-2 для кириллицы. Превышение делит сообщение на сегменты.
Нужно ли регистрировать альфанумерический отправитель? Да, у операторов. Незарегистрированное имя отклоняется частью операторов, и сообщение не доходит.
Когда приходит статус доставки? Асинхронно через уведомление провайдера. Факт принятия сообщения не означает доставку на телефон.
Можно ли получать ответы пользователя на SMS? Только при использовании номера, а не альфанумерического отправителя. Имя отправителя не поддерживает ответы.
Источники: Twilio SMS docs, GSM 03.38, PostgreSQL aggregate functions — ссылки в шапке.