<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Статьи о SMS-маркетинге и рассылках | QUICKTEL</title>
	<atom:link href="https://quicktel.ru/category/articles/feed/" rel="self" type="application/rss+xml" />
	<link>https://quicktel.ru/category/articles/</link>
	<description></description>
	<lastBuildDate>Fri, 09 Oct 2026 07:00:00 +0000</lastBuildDate>
	<language>ru-RU</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://quicktel.ru/wp-content/uploads/2023/05/cropped-qt-32x32.png</url>
	<title>Статьи о SMS-маркетинге и рассылках | QUICKTEL</title>
	<link>https://quicktel.ru/category/articles/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Пропускная способность SMS API: как рассчитать MPS и размер очереди</title>
		<link>https://quicktel.ru/propusknaya-sposobnost-sms-api-mps/</link>
					<comments>https://quicktel.ru/propusknaya-sposobnost-sms-api-mps/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Fri, 09 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Надёжность SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7335</guid>

					<description><![CDATA[<p>Средний объём почти ничего не говорит о требуемой мощности SMS-интеграции. Компания может отправлять 100 тысяч сообщений в день, но 40 тысяч из них должны уйти за первые десять минут после события. Если SMS API и workers рассчитаны только на суточное среднее, очередь будет разгружаться часами. Пропускную способность удобно выражать в MPS — messages per second. [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/propusknaya-sposobnost-sms-api-mps/">Пропускная способность SMS API: как рассчитать MPS и размер очереди</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Средний объём почти ничего не говорит о требуемой мощности SMS-интеграции. Компания может отправлять 100 тысяч сообщений в день, но 40 тысяч из них должны уйти за первые десять минут после события. Если SMS API и workers рассчитаны только на суточное среднее, очередь будет разгружаться часами.</p>
<p>Пропускную способность удобно выражать в MPS — messages per second. Но расчёт должен учитывать запросы, получателей, сегменты, приоритеты и ограничение конкретного маршрута.</p>
<h2 id='nachat-so-stsenariev'>Начать со сценариев</h2>
<p>Соберите по каждому типу сообщения:</p>
<ul>
<li>обычный и пиковый объём;</li>
<li>длительность пика;</li>
<li>допустимую задержку;</li>
<li>TTL;</li>
<li>среднее и максимальное число сегментов;</li>
<li>приоритет;</li>
<li>операторов и маршруты;</li>
<li>ожидаемый рост;</li>
<li>поведение при сбое.</li>
</ul>
<p>OTP и массовая сервисная кампания могут иметь одинаковый объём, но совершенно разные требования. Первый сценарий чувствителен к секундам, второй иногда допускает растягивание на часы.</p>
<h2 id='bazovyj-raschyot'>Базовый расчёт</h2>
<p>Если нужно обработать <code>N</code> сообщений за <code>T</code> секунд, минимальная средняя скорость равна <code>N / T</code>. Для 60 000 сообщений за 20 минут: <code>60 000 / 1 200 = 50 MPS</code>.</p>
<p>Это нижняя граница без запаса и без другого трафика. Если параллельно идут 10 MPS критичных уведомлений, требуется уже 60 MPS. Добавьте резерв на неравномерность, повторы и рост, но не завышайте его без измерений.</p>
<h2 id='soobshheniya-zaprosy-i-segmenty'>Сообщения, запросы и сегменты</h2>
<p>Один HTTP-запрос может содержать пакет получателей, а одно длинное SMS — несколько тарифицируемых сегментов. Уточните, в каких единицах провайдер задаёт квоту. Возможны три разные величины:</p>
<ul>
<li>RPS — запросы в секунду;</li>
<li>MPS — сообщения или получатели в секунду;</li>
<li>SPS — SMS-сегменты в секунду.</li>
</ul>
<p>Если среднее сообщение содержит 1,3 сегмента, поток 100 получателей в секунду создаёт около 130 сегментов в секунду. Для бюджета и некоторых маршрутов это принципиально. Причины сегментации разобраны в статье про <a href="/dlina-sms-i-kolichestvo-segmentov/" rel="noopener" target="_blank">длину SMS</a>.</p>
<h2 id='zakon-littla-dlya-ocheredi'>Закон Литтла для очереди</h2>
<p>При устойчивом потоке примерный размер системы связан с интенсивностью и временем: <code>L = λ × W</code>. Если приходит 80 задач в секунду, а среднее время внутри конвейера 5 секунд, одновременно там находится около 400 задач.</p>
<p>Для аварийного backlog полезнее прямой расчёт. Если накопилось 120 000 сообщений, входящий поток остаётся 20 MPS, а система обрабатывает 100 MPS, чистая скорость разгрузки — 80 MPS. Очередь уйдёт примерно за 1 500 секунд, то есть 25 минут. Если processing rate равен входящему, backlog не уменьшится вообще.</p>
<h2 id='ogranichenie-samogo-medlennogo-zvena'>Ограничение самого медленного звена</h2>
<p>Итоговая скорость не выше минимума из:</p>
<ul>
<li>создания задач бизнес-системой;</li>
<li>записи и чтения очереди;</li>
<li>числа и скорости workers;</li>
<li>клиентского <a href="/rate-limit-sms-api/" rel="noopener" target="_blank">rate limit</a>;</li>
<li>квоты SMS API;</li>
<li>пропускной способности маршрута и оператора;</li>
<li>скорости обработки DLR, если она влияет на downstream.</li>
</ul>
<p>Ускорение workers не помогает, если провайдер разрешает 50 MPS. Повышение API-квоты бесполезно, если один worker синхронно ждёт каждый ответ.</p>
<h2 id='konkurentnost'>Конкурентность</h2>
<p>При среднем времени API-вызова 200 мс один последовательный worker теоретически выполняет около 5 запросов в секунду. Для 50 RPS потребуется примерно 10 параллельных операций плюс запас. Но пакетные запросы и асинхронный клиент меняют модель.</p>
<p>Не увеличивайте конкурентность бесконечно. Она повышает число открытых соединений, нагрузку на базу и риск резкого всплеска после восстановления. Общий лимитер должен контролировать суммарный поток всех экземпляров.</p>
<h2 id='rezerv-dlya-kritichnogo-trafika'>Резерв для критичного трафика</h2>
<p>Если кампания занимает всю квоту, OTP попадёт в конец очереди. Зарезервируйте MPS для приоритетного класса и ограничьте скорость bulk-трафика. Схема <a href="/prioritety-sms-trafika/" rel="noopener" target="_blank">приоритетов SMS</a> должна быть частью расчёта мощности.</p>
<p>Резерв не обязан простаивать: weighted scheduler может временно отдавать свободную квоту другим классам, но быстро возвращать её при появлении критичных задач.</p>
<h2 id='sboj-i-vosstanovlenie'>Сбой и восстановление</h2>
<p>После получасовой недоступности накопится backlog. План мощности должен отвечать, за сколько он исчезнет после восстановления и какие сообщения уже просрочены. Сначала удаляются или закрываются задачи с истёкшим TTL, затем трафик разгружается с ограничением, чтобы не вызвать второй сбой.</p>
<p>Если резервный провайдер имеет меньшую квоту, RTO нужно считать по ней. Сам факт переключения маршрута ещё не означает сохранение времени доставки.</p>
<h2 id='nagruzochnyj-test'>Нагрузочный тест</h2>
<p>Формулы проверяются измерениями. <a href="/nagruzochnoe-testirovanie-sms/" rel="noopener" target="_blank">Нагрузочное тестирование SMS</a> должно отделять генерацию нагрузки от реальной отправки и использовать sandbox, mock или согласованный ограниченный контур.</p>
<p>Измеряйте throughput, p95/p99 latency, возраст очереди, CPU, соединения, ошибки, 429 и время восстановления после паузы. Тест ровным потоком не заменяет резкий пик и restart workers.</p>
<h2 id='planirovanie-rosta'>Планирование роста</h2>
<p>Стройте несколько сценариев: обычный день, маркетинговый пик, аварийное оповещение и сбой провайдера. Указывайте допущения и дату данных. Пересматривайте расчёт после изменения шаблонов, потому что число сегментов влияет на стоимость и иногда на пропускную способность.</p>
<p>Алерт нужен до исчерпания мощности: прогноз времени разгрузки очереди полезнее сообщения «очередь уже переполнена».</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>пиковый объём известен по каждому сценарию;</li>
<li>MPS не перепутан с RPS и сегментами;</li>
<li>учтён параллельный критичный трафик;</li>
<li>определено самое медленное звено;</li>
<li>рассчитано время разгрузки backlog;</li>
<li>просроченные задачи не отправляются после восстановления;</li>
<li>квота общая для всех workers;</li>
<li>формулы подтверждены нагрузочным тестом;</li>
<li>есть запас и регулярный пересмотр прогноза.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Пропускная способность SMS API — это способность доставить нужный объём в допустимое время, а не максимальное число workers. Расчёт начинается с пиков и TTL, различает запросы, сообщения и сегменты, учитывает самое медленное звено и скорость восстановления. Тогда очередь становится управляемым буфером, а не местом, где уведомления незаметно стареют.</p>
<p>Сообщение <a href="https://quicktel.ru/propusknaya-sposobnost-sms-api-mps/">Пропускная способность SMS API: как рассчитать MPS и размер очереди</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/propusknaya-sposobnost-sms-api-mps/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Роли и права в SMS-платформе: RBAC для безопасного запуска</title>
		<link>https://quicktel.ru/roli-prava-rbac-sms-platforma/</link>
					<comments>https://quicktel.ru/roli-prava-rbac-sms-platforma/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Thu, 08 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Безопасность SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7333</guid>

					<description><![CDATA[<p>Общая учётная запись администратора удобна до первой ошибки: невозможно понять, кто изменил шаблон, выгрузил базу или запустил кампанию. RBAC — управление доступом по ролям — разделяет возможности пользователей и сервисов по их реальным обязанностям. Для SMS-платформы это особенно важно: один интерфейс может содержать персональные данные, бюджет, API-ключи и кнопку массовой отправки. Принцип минимальных прав Пользователь [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/roli-prava-rbac-sms-platforma/">Роли и права в SMS-платформе: RBAC для безопасного запуска</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Общая учётная запись администратора удобна до первой ошибки: невозможно понять, кто изменил шаблон, выгрузил базу или запустил кампанию. RBAC — управление доступом по ролям — разделяет возможности пользователей и сервисов по их реальным обязанностям.</p>
<p>Для SMS-платформы это особенно важно: один интерфейс может содержать персональные данные, бюджет, API-ключи и кнопку массовой отправки.</p>
<h2 id='printsip-minimalnyh-prav'>Принцип минимальных прав</h2>
<p>Пользователь получает только те действия и данные, которые нужны для работы. Маркетологу не обязательно видеть API-секреты, разработчику — выгружать всю аудиторию, сотруднику поддержки — менять бюджет и Sender ID.</p>
<p>Права назначают ролям, а не каждому человеку отдельным набором. Исключения имеют срок, основание и владельца. Иначе модель постепенно превращается в набор бессрочных ручных разрешений.</p>
<h2 id='bazovye-roli'>Базовые роли</h2>
<p>Конкретный набор зависит от компании, но полезно разделить:</p>
<ul>
<li>автор контента — создаёт черновик шаблона и кампании;</li>
<li>владелец аудитории — готовит сегмент и исключения;</li>
<li>согласующий — проверяет правовое основание, текст и параметры;</li>
<li>оператор — запускает уже утверждённую версию;</li>
<li>аналитик — видит агрегированные результаты без лишних контактов;</li>
<li>поддержка — ищет отдельное сообщение по безопасному ID;</li>
<li>разработчик интеграции — управляет тестовым контуром и техническими настройками;</li>
<li>администратор — назначает роли, но не обязан запускать кампании;</li>
<li>аудитор — читает неизменяемый журнал действий.</li>
</ul>
<p>В малой команде один человек может совмещать роли, но система всё равно фиксирует, какое действие выполнялось и требовало ли отдельного подтверждения.</p>
<h2 id='razdelenie-kritichnyh-dejstvij'>Разделение критичных действий</h2>
<p>Для большого объёма полезен принцип four eyes: автор не может единолично утвердить и запустить собственную кампанию. Повторное согласование требуется после изменения текста, аудитории, времени, Sender ID или бюджета.</p>
<p>Это не должно превращаться в формальную кнопку. Согласующий видит diff относительно проверенной версии и контрольные показатели: размер сегмента, число исключений, сегменты SMS и ожидаемую стоимость.</p>
<h2 id='dostup-k-dannym'>Доступ к данным</h2>
<p>Право видеть отчёт не означает право скачать номера. В интерфейсе используйте маскирование и поиск по внутреннему contact ID. Экспорт — отдельное разрешение с причиной, сроком жизни файла и записью в аудит.</p>
<p>Доступ можно ограничить проектом, подразделением, брендом или набором Sender ID. Пользователь филиала не должен видеть кампании всей компании только потому, что у него роль «оператор».</p>
<h2 id='servisnye-akkaunty'>Сервисные аккаунты</h2>
<p>API-интеграция работает от отдельного сервисного аккаунта, а не от ключа сотрудника. У него нет интерактивного входа и лишних административных прав. Ключи разделяются по приложениям и средам, регулярно пересматриваются и <a href="/rotaciya-api-klyuchej-sms/" rel="noopener" target="_blank">ротируются</a>.</p>
<p>Действия сервиса связываются с приложением и исходным бизнес-событием. Формулировка «запустил API» недостаточна для расследования.</p>
<h2 id='audit'>Аудит</h2>
<p>Журнал фиксирует:</p>
<ul>
<li>входы и неудачные попытки;</li>
<li>выдачу и отзыв ролей;</li>
<li>создание и изменение шаблона;</li>
<li>импорт, просмотр и экспорт аудитории;</li>
<li>согласование и отклонение;</li>
<li>изменение лимита и бюджета;</li>
<li>запуск, паузу и отмену;</li>
<li>выпуск и отзыв API-ключа;</li>
<li>emergency-доступ.</li>
</ul>
<p>Запись содержит пользователя или сервис, время, объект, действие, результат и correlation ID. Сам журнал защищают от изменения и ограничивают доступ к нему.</p>
<h2 id='vremennye-prava'>Временные права</h2>
<p>Повышение роли на период проекта безопаснее постоянного admin. Срок истекает автоматически, а владелец получает уведомление. Периодическая ревизия удаляет доступы у уволенных сотрудников, завершённых подрядчиков и неиспользуемых сервисов.</p>
<p>Проверяйте не только роли внутри платформы, но и доступ к хостингу, секретам, CRM и файлам выгрузки. Самая строгая кнопка запуска не помогает, если общий API-ключ лежит в чате.</p>
<h2 id='emergency-dostup'>Emergency-доступ</h2>
<p>Во время инцидента может понадобиться срочно остановить отправку или сменить маршрут. Break-glass роль хранится отдельно, выдаётся на короткое время и вызывает немедленный аудит. Её использование требует последующего разбора.</p>
<p>Аварийный доступ проверяют заранее. Нельзя обнаруживать во время массовой ошибки, что единственный администратор недоступен или второй фактор привязан к старому телефону.</p>
<h2 id='udobstvo'>Удобство</h2>
<p>Слишком сложная модель провоцирует обходы: общие аккаунты, пересылку выгрузок и бессрочные исключения. Роль должна соответствовать понятной рабочей задаче, а запрос временного доступа — занимать минуты, не дни.</p>
<p>Интерфейс объясняет, почему действие недоступно и кто может его согласовать. Это лучше, чем скрытая кнопка, ради которой сотрудник просит пароль коллеги.</p>
<h2 id='proverki'>Проверки</h2>
<p>Автоматические тесты подтверждают, что роль не может вызвать запрещённый API напрямую. Проверять только видимость элементов интерфейса недостаточно: backend авторизует каждое действие независимо.</p>
<p>Раз в квартал или другой согласованный период владельцы подтверждают состав ролей. Список «пользователь — роль — область — последнее использование» делает review предметным.</p>
<h2 id='svyaz-s-protsessom-zapuska'>Связь с процессом запуска</h2>
<p>RBAC технически закрепляет <a href="/reglament-sms-rassylok/" rel="noopener" target="_blank">регламент SMS-рассылок</a>: кто создаёт, кто согласует, кто запускает и кто может остановить. Регламент без прав остаётся просьбой, а права без владельцев быстро устаревают.</p>
<h2 id='itog'>Итог</h2>
<p>RBAC снижает риск случайной рассылки, утечки базы и непрозрачного изменения настроек. Хорошая модель разделяет контент, аудиторию, согласование, запуск и администрирование, использует сервисные аккаунты и журналирует критичные действия. При этом она должна быть достаточно удобной, чтобы сотрудники не искали обходной путь.</p>
<p>Сообщение <a href="https://quicktel.ru/roli-prava-rbac-sms-platforma/">Роли и права в SMS-платформе: RBAC для безопасного запуска</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/roli-prava-rbac-sms-platforma/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Контрактное тестирование SMS API: как пережить изменения провайдера</title>
		<link>https://quicktel.ru/kontraktnoe-testirovanie-sms-api/</link>
					<comments>https://quicktel.ru/kontraktnoe-testirovanie-sms-api/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Wed, 07 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[SMS API]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7331</guid>

					<description><![CDATA[<p>Интеграция может месяцами работать, а затем сломаться из-за нового обязательного поля, другого типа кода ошибки или изменения webhook. Обычный unit-тест проверяет ваш код на подготовленном объекте, но не подтверждает, что этот объект соответствует реальному контракту SMS-провайдера. Контрактные тесты фиксируют форму запросов и ответов на границе систем. Они обнаруживают несовместимость до массовой отправки и упрощают переезд [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/kontraktnoe-testirovanie-sms-api/">Контрактное тестирование SMS API: как пережить изменения провайдера</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Интеграция может месяцами работать, а затем сломаться из-за нового обязательного поля, другого типа кода ошибки или изменения webhook. Обычный unit-тест проверяет ваш код на подготовленном объекте, но не подтверждает, что этот объект соответствует реальному контракту SMS-провайдера.</p>
<p>Контрактные тесты фиксируют форму запросов и ответов на границе систем. Они обнаруживают несовместимость до массовой отправки и упрощают <a href="/pereezd-na-novyj-sms-shlyuz/" rel="noopener" target="_blank">переезд на новый SMS-шлюз</a>.</p>
<h2 id='chto-vhodit-v-kontrakt'>Что входит в контракт</h2>
<p>Контракт — это не только URL и список полей. Он включает:</p>
<ul>
<li>метод, путь, заголовки и авторизацию;</li>
<li>обязательные и необязательные параметры;</li>
<li>типы, форматы и ограничения;</li>
<li>семантику HTTP-кодов;</li>
<li>структуру успеха и ошибок;</li>
<li>правила idempotency и client message ID;</li>
<li>rate limit и заголовки повторов;</li>
<li>схему webhook и подпись;</li>
<li>словарь DLR;</li>
<li>версию API и правила устаревания.</li>
</ul>
<p>Каждая проверка должна отвечать на конкретный риск. Snapshot всего JSON без смысловых assertions часто создаёт шум при безвредном добавлении поля.</p>
<h2 id='consumer-driven-podhod'>Consumer-driven подход</h2>
<p>Клиент формулирует, какие свойства реально использует. Например: при успехе нужен непустой строковый message ID; при 429 — понятный код и необязательный <code>Retry-After</code>; webhook обязан содержать provider message ID и статус.</p>
<p>Добавление нового необязательного поля не ломает такой тест. Изменение типа <code>message_id</code> или исчезновение обязательного значения — ломает. Это отделяет совместимое расширение от опасного изменения.</p>
<h2 id='fixtures'>Fixtures</h2>
<p>Сохраните обезличенные примеры:</p>
<ul>
<li>успешная одиночная отправка;</li>
<li>пакет с частичным результатом;</li>
<li>ошибка валидации номера;</li>
<li>ошибка авторизации;</li>
<li>rate limit;</li>
<li>5xx;</li>
<li>таймаут или разрыв соединения;</li>
<li>промежуточный и финальный DLR;</li>
<li>неизвестный статус;</li>
<li>дублированный webhook.</li>
</ul>
<p>Fixture имеет источник и дату. Реальный production-payload очищается от номера, текста, ключей и других персональных данных до попадания в репозиторий.</p>
<h2 id='mock-i-realnyj-sandbox'>Mock и реальный sandbox</h2>
<p>Локальный mock делает тесты быстрыми и воспроизводимыми. Он проверяет поведение клиента при известных ответах, но не доказывает соответствие текущему API. Поэтому периодически тот же набор запускают против <a href="/testovaya-sreda-sms-api/" rel="noopener" target="_blank">тестовой среды SMS API</a> или выделенного аккаунта провайдера.</p>
<p>Если официальный sandbox беден, полезна проверка схемы документации и ограниченный production smoke-test. У каждого уровня своя задача; ни один не заменяет остальные.</p>
<h2 id='strogost-parsera'>Строгость парсера</h2>
<p>Клиент должен принимать дополнительные неизвестные поля, если контракт допускает расширение. Слишком строгая десериализация ломается от безвредного обновления. Но неизвестный enum статуса нельзя тихо превращать в delivered или permanent failure.</p>
<p>Для критичных enum используйте явное состояние <code>unknown</code>, метрику и сохранение исходного значения. Такой подход применяется в <a href="/mapping-statusov-sms-provajderov/" rel="noopener" target="_blank">маппинге DLR</a>.</p>
<h2 id='versiya-api'>Версия API</h2>
<p>Версию указывают явно в URL, заголовке или конфигурации согласно документации провайдера. Автоматический переход на latest делает релиз внешней стороны вашим незапланированным релизом.</p>
<p>Следите за уведомлениями об устаревании и датой отключения. До миграции новая версия проходит тот же контрактный набор, а результаты сравниваются по семантике, а не только по JSON.</p>
<h2 id='webhook-kak-obratnyj-kontrakt'>Webhook как обратный контракт</h2>
<p>Для исходящего API ваша система — consumer, а для webhook она становится provider endpoint. Тестируйте сырое тело, заголовки, <a href="/podpis-webhook-sms/" rel="noopener" target="_blank">подпись webhook</a>, повтор события и порядок DLR.</p>
<p>Endpoint должен быстро принимать совместимое новое поле, но отклонять отсутствие обязательного идентификатора. Ошибка одного события не должна блокировать весь поток.</p>
<h2 id='gde-zapuskat-testy'>Где запускать тесты</h2>
<p>Быстрый набор выполняется на каждый merge. Расширенный sandbox-набор — по расписанию и перед релизом адаптера. Production smoke-test запускается редко, на allowlist номеров и с жёстким бюджетом.</p>
<p>Отдельный монитор следит за сертификатом, DNS и доступностью endpoint, но это уже эксплуатационная проверка, а не контрактный тест.</p>
<h2 id='izmeneniya-vashego-adaptera'>Изменения вашего адаптера</h2>
<p>Контракт защищает не только от провайдера. Рефакторинг может перестать передавать TTL, изменить Sender ID или неверно трактовать частичный ответ. Тест проверяет сформированный HTTP-запрос целиком по значимым полям.</p>
<p>Перед обновлением SDK изучите release notes и сравните фактические запросы. Новый SDK иногда меняет значения по умолчанию, повторы или таймауты без изменения бизнес-кода.</p>
<h2 id='reaktsiya-na-proval'>Реакция на провал</h2>
<p>Падение теста блокирует релиз адаптера и создаёт задачу владельцу интеграции. Не обновляйте fixture автоматически, иначе несовместимость будет просто принята как новая норма.</p>
<p>Сначала определите: изменение совместимо, требует новой версии клиента или является ошибкой теста. Решение и новая семантика фиксируются вместе с fixture.</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>перечислены свойства API, которые реально использует клиент;</li>
<li>fixtures обезличены и имеют дату;</li>
<li>дополнительные поля допускаются, обязательные контролируются;</li>
<li>неизвестные enum не маскируются;</li>
<li>webhook тестируется как отдельный входящий контракт;</li>
<li>mock дополняется периодической проверкой sandbox;</li>
<li>версия API закреплена явно;</li>
<li>обновление SDK проходит сравнение запросов;</li>
<li>fixture нельзя обновить без осмысленного review.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Контрактные тесты превращают внешнюю интеграцию из набора предположений в проверяемое соглашение. Они не гарантируют доставку SMS, зато заранее показывают, что клиент и провайдер одинаково понимают запрос, ответ, ошибку и webhook. Это особенно важно при обновлении API, SDK и маршрута.</p>
<p>Сообщение <a href="https://quicktel.ru/kontraktnoe-testirovanie-sms-api/">Контрактное тестирование SMS API: как пережить изменения провайдера</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/kontraktnoe-testirovanie-sms-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Подпись webhook SMS: как проверять подлинность DLR</title>
		<link>https://quicktel.ru/podpis-webhook-sms/</link>
					<comments>https://quicktel.ru/podpis-webhook-sms/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Tue, 06 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Безопасность SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7329</guid>

					<description><![CDATA[<p>Webhook со статусом доставки меняет данные и может запускать бизнес-логику. Если endpoint принимает любой POST без проверки, посторонний отправитель способен подделать delivered, создать поток ошибок или перегрузить систему. HTTPS защищает канал передачи, но не доказывает, что запрос сформировал именно SMS-провайдер. Подпись webhook связывает тело запроса с секретом, известным двум сторонам. Система вычисляет контрольное значение и [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/podpis-webhook-sms/">Подпись webhook SMS: как проверять подлинность DLR</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Webhook со статусом доставки меняет данные и может запускать бизнес-логику. Если endpoint принимает любой POST без проверки, посторонний отправитель способен подделать <code>delivered</code>, создать поток ошибок или перегрузить систему. HTTPS защищает канал передачи, но не доказывает, что запрос сформировал именно SMS-провайдер.</p>
<p>Подпись webhook связывает тело запроса с секретом, известным двум сторонам. Система вычисляет контрольное значение и сравнивает его с заголовком провайдера до разбора и изменения статуса.</p>
<h2 id='sledovat-kontraktu-provajdera'>Следовать контракту провайдера</h2>
<p>Не существует единого формата подписи. Провайдер определяет алгоритм, набор подписываемых полей, порядок, кодировку, заголовки и формат результата. Нельзя заменить документированный алгоритм собственной похожей схемой.</p>
<p>Часто используется HMAC-SHA256 по сырому телу и timestamp, но возможны другие варианты. Сохраните официальный пример запроса как тестовый fixture и проверяйте его при обновлении SDK или фреймворка.</p>
<h2 id='syroe-telo-zaprosa'>Сырое тело запроса</h2>
<p>Подпись обычно вычисляется до JSON-парсинга. Повторная сериализация меняет пробелы, порядок полей или Unicode и приводит к другому хешу. Поэтому middleware должен сохранить точные байты входящего тела.</p>
<p>Сначала проверяются лимит размера, обязательные заголовки и подпись. Только после успешной аутентификации JSON разбирается и проходит валидацию схемы.</p>
<h2 id='constant-time-comparison'>Constant-time comparison</h2>
<p>Сравнивать подписи следует функцией постоянного времени, доступной в языке или библиотеке. Обычное <code>==</code> может завершаться на первом несовпадающем символе и теоретически раскрывать информацию по времени ответа.</p>
<p>Перед сравнением убедитесь, что обе строки декодированы в ожидаемый формат: hex или Base64. Ошибка декодирования означает отказ, а не попытку угадать формат.</p>
<h2 id='timestamp-i-replay'>Timestamp и replay</h2>
<p>Корректно подписанный запрос можно перехватить и повторить позднее. Добавление timestamp в подписываемую строку и проверка допустимого окна ограничивают replay. Часы серверов должны быть синхронизированы, а допустимое отклонение — документировано.</p>
<p>Одного времени недостаточно: внутри окна событие может прийти повторно законно. Обработчик остаётся <a href="/idempotentnost-sms-api/" rel="noopener" target="_blank">идемпотентным</a> и дедуплицирует webhook по event ID либо устойчивой комбинации message ID, статуса и времени события.</p>
<h2 id='rotatsiya-sekreta'>Ротация секрета</h2>
<p>Во время ротации endpoint может короткое время принимать подписи от текущего и следующего секрета. Каждый имеет внутренний key ID и срок действия. После перехода старый секрет удаляется, а попытки его использования становятся сигналом.</p>
<p>Не храните webhook secret рядом с публичным URL или в исходном коде. Процесс управления такой же, как для <a href="/rotaciya-api-klyuchej-sms/" rel="noopener" target="_blank">ротации API-ключей SMS</a>, но права входящего и исходящего канала разделяются.</p>
<h2 id='ip-allowlist'>IP allowlist</h2>
<p>Список IP может быть дополнительным слоем, если провайдер публикует стабильные диапазоны. Он не заменяет подпись: адреса меняются, запрос может идти через прокси, а доверенная сеть тоже не гарантирует целостность тела.</p>
<p>Обновление allowlist автоматизируют и тестируют. В противном случае легитимные DLR внезапно перестанут приходить после изменения инфраструктуры провайдера.</p>
<h2 id='obrabotka-oshibok'>Обработка ошибок</h2>
<p>При неверной подписи endpoint возвращает отказ без подробного объяснения. В лог попадают время, источник, безопасный request ID и причина категории, но не секрет, полная подпись или чувствительный payload.</p>
<p>Алерт на каждую единичную ошибку создаёт шум: сканеры интернета регулярно находят публичные URL. Сигнал строят по устойчивому росту, совпадению с известным IP провайдера или появлению после ротации.</p>
<h2 id='bystryj-otvet'>Быстрый ответ</h2>
<p>После проверки подписи и минимальной схемы webhook лучше надёжно поставить во внутреннюю очередь и быстро вернуть ожидаемый 2xx. Долгая бизнес-обработка увеличивает число повторов со стороны провайдера.</p>
<p>Сам быстрый ответ не означает, что событие потеряно. Сначала оно сохраняется атомарно, затем обрабатывается асинхронно. Общий pipeline описан в статье про <a href="/webhook-dlya-statusov-sms/" rel="noopener" target="_blank">webhook статусов SMS</a>.</p>
<h2 id='testy'>Тесты</h2>
<p>Обязательные сценарии:</p>
<ul>
<li>корректное тело и подпись;</li>
<li>изменение одного байта payload;</li>
<li>неверный секрет;</li>
<li>отсутствующий заголовок;</li>
<li>старый и будущий timestamp;</li>
<li>повтор корректного события;</li>
<li>два активных секрета во время ротации;</li>
<li>JSON с другим порядком полей;</li>
<li>слишком большое тело;</li>
<li>запрос после отзыва старого секрета.</li>
</ul>
<p>Тест должен использовать сырые байты официального примера, а не объект, который framework сериализует заново.</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>алгоритм реализован точно по документации провайдера;</li>
<li>подпись считается по сырым байтам;</li>
<li>сравнение выполняется constant-time функцией;</li>
<li>timestamp входит в проверку, если это предусмотрено контрактом;</li>
<li>повторы дедуплицируются;</li>
<li>секрет хранится и ротируется отдельно от API-ключа;</li>
<li>IP allowlist остаётся дополнительным слоем;</li>
<li>до аутентификации не меняются бизнес-данные;</li>
<li>ошибки не раскрывают детали проверки.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Подпись webhook защищает доверие к DLR. Правильная реализация начинается с точного контракта провайдера, сырых байтов и безопасного сравнения, а заканчивается replay-защитой, идемпотентностью и ротацией секрета. Только после этих проверок входящий статус может влиять на сообщение и бизнес-процесс.</p>
<p>Сообщение <a href="https://quicktel.ru/podpis-webhook-sms/">Подпись webhook SMS: как проверять подлинность DLR</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/podpis-webhook-sms/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Ротация API-ключей SMS без остановки отправок</title>
		<link>https://quicktel.ru/rotaciya-api-klyuchej-sms/</link>
					<comments>https://quicktel.ru/rotaciya-api-klyuchej-sms/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Mon, 05 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Безопасность SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7327</guid>

					<description><![CDATA[<p>API-ключ SMS даёт право отправлять сообщения и расходовать бюджет. Если он годами живёт в исходном коде, общей таблице или старом сервере, компрометацию трудно заметить, а срочный отзыв может остановить все уведомления. Ротация ограничивает срок действия секрета и одновременно проверяет, умеет ли система безопасно его заменить. Общая модель защиты канала описана в материале про безопасность SMS [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/rotaciya-api-klyuchej-sms/">Ротация API-ключей SMS без остановки отправок</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>API-ключ SMS даёт право отправлять сообщения и расходовать бюджет. Если он годами живёт в исходном коде, общей таблице или старом сервере, компрометацию трудно заметить, а срочный отзыв может остановить все уведомления. Ротация ограничивает срок действия секрета и одновременно проверяет, умеет ли система безопасно его заменить. Общая модель защиты канала описана в материале про <a href="/bezopasnost-pri-ispolzovanii-api-dlya-otpravki-sms-chto-vazhno-znat/" rel="noopener" target="_blank">безопасность SMS API</a>.</p>
<p>Рабочий процесс строится так, чтобы новый и старый ключ короткое время существовали параллельно, а откат не требовал возвращать отозванный секрет.</p>
<h2 id='inventarizatsiya'>Инвентаризация</h2>
<p>До ротации найдите всех потребителей: production и staging, фоновые workers, CRM, 1С, резервные скрипты, CI/CD, панели мониторинга. Для каждого зафиксируйте владельца, среду, разрешения и способ доставки секрета.</p>
<p>Один общий ключ для нескольких систем мешает понять источник трафика и увеличивает blast radius. Где возможно, создайте отдельные сервисные учётные данные по приложениям и средам.</p>
<h2 id='gde-hranit-klyuch'>Где хранить ключ</h2>
<p>Секрет не должен находиться в git, Markdown-инструкции, образе контейнера или клиентском JavaScript. Приложение получает его из менеджера секретов или защищённой конфигурации среды с минимальными правами.</p>
<p><a href="https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html" rel="noopener" target="_blank">OWASP Secrets Management Cheat Sheet</a> рекомендует управлять жизненным циклом секретов централизованно: выдачей, аудитом, ротацией и отзывом. Логи должны фиксировать использование и изменения, но не само значение ключа.</p>
<h2 id='shema-bez-prostoya'>Схема без простоя</h2>
<p>Если провайдер поддерживает несколько активных ключей:</p>
<ol>
<li>Создать новый ключ с теми же минимально необходимыми правами.</li>
<li>Сохранить его как новую версию секрета.</li>
<li>Переключить один экземпляр или малую долю workers.</li>
<li>Проверить приём API, message ID, DLR и метрики ошибок.</li>
<li>Обновить остальные экземпляры.</li>
<li>Убедиться, что старый ключ больше не используется.</li>
<li>Отозвать старый ключ.</li>
<li>Проверить алерт на попытку его повторного использования.</li>
</ol>
<p>Если одновременно разрешён только один ключ, нужен согласованный maintenance-процесс или временная отдельная учётная запись. Такой риск следует выяснить при выборе провайдера, а не в день инцидента.</p>
<h2 id='kak-prilozhenie-vybiraet-klyuch'>Как приложение выбирает ключ</h2>
<p>Сервис читает активную версию при старте либо динамически обновляет секрет с кешированием. При динамической схеме нельзя запрашивать secret manager перед каждым SMS: его временная недоступность остановит канал и создаст лишнюю нагрузку.</p>
<p>Кеш должен иметь понятное время жизни и безопасное поведение. Уже работающий экземпляр может некоторое время использовать старый активный ключ, но после отзыва обязан получить новый. Метрика версии ключа не должна раскрывать секрет; достаточно внутреннего идентификатора.</p>
<h2 id='proverka-otsutstviya-starogo-klyucha'>Проверка отсутствия старого ключа</h2>
<p>Поиск по репозиторию важен, но недостаточен. Проверьте переменные CI/CD, конфигурацию хостинга, архивные задачи, контейнеры, локальные файлы и аварийные runbook. На стороне провайдера полезна статистика вызовов по ключам.</p>
<p>После переключения выдержите окно, превышающее максимальное время жизни старых процессов и заданий. Только затем отзывайте прежний секрет, если нет признаков использования.</p>
<h2 id='avarijnaya-rotatsiya'>Аварийная ротация</h2>
<p>При подозрении на утечку приоритет меняется: старый ключ отзывают как можно быстрее, даже если возможна краткая деградация. Runbook должен содержать контакты, способ выпуска нового ключа, перечень потребителей и план проверки.</p>
<p>Одновременно ограничивают бюджет и скорость, анализируют необычные получатели и объёмы, сохраняют аудит. Резкий рост отправок может быть признаком <a href="/sms-pumping/" rel="noopener" target="_blank">SMS pumping</a>. Простая замена ключа без выяснения места утечки оставляет новый секрет под тем же риском.</p>
<h2 id='prava-i-limity'>Права и лимиты</h2>
<p>Если API позволяет, ключ отправки не должен управлять пользователями, тарифами и другими ключами. Staging получает собственную малую квоту и не видит production. IP allowlist и отдельные роли уменьшают последствия утечки, но не заменяют ротацию.</p>
<p>Для редких административных операций используйте отдельные учётные данные с усиленным контролем. Чем меньше повседневный ключ умеет, тем безопаснее автоматическая интеграция.</p>
<h2 id='logi-bez-sekreta'>Логи без секрета</h2>
<p>Никогда не записывайте Authorization header, URL с ключом или дамп всей конфигурации. В журнале достаточно key ID, имени сервиса, результата аутентификации и correlation ID.</p>
<p>Маскирование должно происходить до передачи в централизованный лог. Фильтр только в интерфейсе не защищает исходное хранилище.</p>
<h2 id='regulyarnaya-proverka'>Регулярная проверка</h2>
<p>Ротация по расписанию — это упражнение восстановления. Если процесс каждый раз требует ручного редактирования десятка серверов, архитектурная проблема обнаружится до настоящей утечки. Проводите тест в контролируемое окно и измеряйте время полного переключения.</p>
<p>После завершения обновляйте инвентарь, дату следующей ротации и владельца. Не оставляйте бессрочный запасной ключ «на всякий случай».</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>каждый ключ имеет владельца, среду и назначение;</li>
<li>секреты разделены по приложениям;</li>
<li>значение не хранится в коде и логах;</li>
<li>новый ключ проверяется на малой доле трафика;</li>
<li>видна версия ключа, но не сам секрет;</li>
<li>старый ключ отзывается после подтверждения переключения;</li>
<li>попытка использовать отозванный ключ вызывает алерт;</li>
<li>аварийный runbook проверен заранее;</li>
<li>бюджеты и права минимальны.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Ротация API-ключей SMS — часть эксплуатации, а не разовая мера после утечки. Параллельный выпуск, поэтапное переключение, наблюдение и обязательный отзыв позволяют менять секрет без простоя. Регулярный процесс одновременно уменьшает риск и показывает скрытые зависимости интеграции.</p>
<p>Сообщение <a href="https://quicktel.ru/rotaciya-api-klyuchej-sms/">Ротация API-ключей SMS без остановки отправок</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/rotaciya-api-klyuchej-sms/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Тестовая среда SMS API: как отделить sandbox от production</title>
		<link>https://quicktel.ru/testovaya-sreda-sms-api/</link>
					<comments>https://quicktel.ru/testovaya-sreda-sms-api/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Fri, 02 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[SMS API]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7325</guid>

					<description><![CDATA[<p>Тестовая среда SMS API нужна, чтобы проверять интеграцию без случайной рассылки клиентам и лишних расходов. Но sandbox полезен только тогда, когда его ограничения понятны. Успешный виртуальный ответ не доказывает, что оператор примет Sender ID, реальное сообщение уложится в сегменты, а DLR придёт с тем же временем и порядком. Безопасная схема сочетает три уровня: локальные тесты [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/testovaya-sreda-sms-api/">Тестовая среда SMS API: как отделить sandbox от production</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Тестовая среда SMS API нужна, чтобы проверять интеграцию без случайной рассылки клиентам и лишних расходов. Но sandbox полезен только тогда, когда его ограничения понятны. Успешный виртуальный ответ не доказывает, что оператор примет Sender ID, реальное сообщение уложится в сегменты, а DLR придёт с тем же временем и порядком.</p>
<p>Безопасная схема сочетает три уровня: локальные тесты без сети, sandbox или эмулятор контракта и небольшой production-тест на разрешённые номера.</p>
<h2 id='zhyostkoe-razdelenie-sred'>Жёсткое разделение сред</h2>
<p>У sandbox и production должны различаться:</p>
<ul>
<li>API endpoint;</li>
<li>ключи и секреты;</li>
<li>аккаунты или проекты;</li>
<li>очереди и базы данных;</li>
<li>webhook URL;</li>
<li>Sender ID;</li>
<li>бюджеты и лимиты;</li>
<li>панели мониторинга.</li>
</ul>
<p>Переключатель не должен зависеть от строки, которую разработчик меняет вручную перед запуском. Среда задаётся конфигурацией развёртывания, а production-ключ физически недоступен тестовому контуру.</p>
<h2 id='allowlist-kak-vtoroj-predohranitel'>Allowlist как второй предохранитель</h2>
<p>Даже в staging полезно разрешить отправку только на заранее утверждённые номера команды. Если тестовая конфигурация случайно указывает на production API, allowlist остановит выгрузку клиентской базы.</p>
<p>Проверку ставят в собственном сервисе до SMS API. Она действует независимо от интерфейса кампании и блокирует любой путь отправки. Для тестовых адресатов сохраняют согласованный лимит частоты, чтобы автоматические тесты не создавали сотни реальных сообщений.</p>
<h2 id='chto-dolzhen-umet-sandbox'>Что должен уметь sandbox</h2>
<p>Хорошая тестовая среда возвращает стабильный message ID, позволяет выбирать сценарий ответа и отправляет webhook с документированной схемой. Нужны случаи:</p>
<ul>
<li>успешный приём;</li>
<li>синхронная валидационная ошибка;</li>
<li>401 или 403;</li>
<li>rate limit;</li>
<li>5xx и таймаут;</li>
<li>delivered, expired и permanent failure;</li>
<li>дублированный webhook;</li>
<li>webhook до или после ожидаемого времени;</li>
<li>неизвестный статус для проверки fallback.</li>
</ul>
<p>Если официальный sandbox не поддерживает нужные ветки, добавьте собственный mock-сервер, построенный по контракту. Он не заменяет провайдера, но делает ошибки воспроизводимыми.</p>
<h2 id='lokalnye-testy'>Локальные тесты</h2>
<p>Большая часть логики не требует реальной SMS: парсинг номера, рендер шаблона, подсчёт сегментов, ключ идемпотентности, маппинг кодов и переходы статусов. Эти тесты должны быть быстрыми и запускаться при каждом изменении.</p>
<p>Записывайте примеры ответов как fixtures с версией контракта. Не копируйте в репозиторий реальные номера, тексты и секреты из production.</p>
<h2 id='testovye-dlr'>Тестовые DLR</h2>
<p>Webhook sandbox должен проходить тот же код проверки, что и production: аутентификацию, дедупликацию, поиск message ID и <a href="/mapping-statusov-sms-provajderov/" rel="noopener" target="_blank">маппинг статуса</a>. Отдельная «упрощённая тестовая ветка» часто скрывает реальные ошибки.</p>
<p>Для проверки подписи используйте тестовый секрет, а не отключайте защиту. Проверьте повтор события, старую метку времени и изменение тела запроса.</p>
<h2 id='chto-sandbox-ne-dokazyvaet'>Что sandbox не доказывает</h2>
<p>Виртуальная среда обычно не воспроизводит:</p>
<ul>
<li>реальную скорость маршрута и операторов;</li>
<li>регистрацию Sender ID;</li>
<li>фильтры содержания;</li>
<li>MNP и роуминг;</li>
<li>фактическое число сегментов в биллинге;</li>
<li>время появления DLR;</li>
<li>поведение устройства абонента;</li>
<li>производственную квоту и стоимость.</li>
</ul>
<p>Поэтому перед релизом нужен ограниченный реальный запуск. Это не массовая <a href="/testovaya-sms-rassylka/" rel="noopener" target="_blank">тестовая SMS-рассылка</a>, а техническая проверка интеграции на контролируемых номерах основных операторов.</p>
<h2 id='perehod-v-production'>Переход в production</h2>
<p>Production включают по чек-листу:</p>
<ol>
<li>Контрактные тесты проходят на текущей версии API.</li>
<li>Webhook доступен снаружи и проверяет подлинность.</li>
<li>Ключи находятся в хранилище секретов.</li>
<li>Настроены rate limit, очередь и TTL.</li>
<li>Allowlist staging не затрагивает production-сценарий ошибочно.</li>
<li>Бюджет и дневной лимит минимальны для первого запуска.</li>
<li>Мониторинг и кнопка остановки проверены.</li>
<li>Первая отправка идёт на небольшой canary-набор.</li>
</ol>
<p>Не переносите базу тестовых message ID и DLR в производственную аналитику. Среда должна быть обязательным измерением каждой записи и метрики.</p>
<h2 id='testovye-dannye'>Тестовые данные</h2>
<p>Используйте синтетические контакты и события. Если без копии production не обойтись, данные обезличивают и минимизируют. Замена только имени недостаточна, когда остаются телефон, заказ и текст.</p>
<p>Для проверок граничной длины создавайте искусственные строки. Они лучше реальных персональных данных и позволяют точно воспроизводить сценарий.</p>
<h2 id='kontrol-sluchajnoj-otpravki'>Контроль случайной отправки</h2>
<p>Помимо allowlist полезны нулевой или очень низкий бюджет тестового аккаунта, отдельный Sender ID и алерт на любое production-сообщение из нерабочей среды. Сервис должен записывать имя среды рядом с correlation ID.</p>
<p>Команда периодически выполняет упражнение: неправильный endpoint, production-похожий ключ и большая тестовая аудитория. Ожидаемый результат — блокировка до первого реального SMS.</p>
<h2 id='itog'>Итог</h2>
<p>Sandbox снижает риск, но не является копией мобильной сети. Надёжный процесс разделяет ключи и данные, использует allowlist, воспроизводимые ответы и тестовые DLR, а затем подтверждает ограниченный реальный путь. Ценность тестовой среды — не в зелёном ответе, а в безопасной проверке всех веток интеграции.</p>
<p>Сообщение <a href="https://quicktel.ru/testovaya-sreda-sms-api/">Тестовая среда SMS API: как отделить sandbox от production</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/testovaya-sreda-sms-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Валидация переменных SMS-шаблона до отправки</title>
		<link>https://quicktel.ru/validaciya-peremennyh-sms-shablona/</link>
					<comments>https://quicktel.ru/validaciya-peremennyh-sms-shablona/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Thu, 01 Oct 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Управление SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7323</guid>

					<description><![CDATA[<p>Шаблон Заказ {{order_number}} готов выглядит безопасно, пока в данных не окажется пустой номер, слишком длинное имя или строка с переносом. Тогда клиент получает SMS с фигурными скобками, обрезанным смыслом или неожиданным количеством сегментов. Такие ошибки возникают до SMS API, поэтому провайдер не может исправить их за приложение. Валидация переменных — отдельный этап между бизнес-событием и [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/validaciya-peremennyh-sms-shablona/">Валидация переменных SMS-шаблона до отправки</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Шаблон <code>Заказ {{order_number}} готов</code> выглядит безопасно, пока в данных не окажется пустой номер, слишком длинное имя или строка с переносом. Тогда клиент получает SMS с фигурными скобками, обрезанным смыслом или неожиданным количеством сегментов. Такие ошибки возникают до SMS API, поэтому провайдер не может исправить их за приложение.</p>
<p>Валидация переменных — отдельный этап между бизнес-событием и постановкой готового сообщения в очередь. Он проверяет схему данных, формирует текст и только затем разрешает отправку.</p>
<h2 id='kontrakt-shablona'>Контракт шаблона</h2>
<p>У каждого шаблона должен быть машиночитаемый контракт:</p>
<ul>
<li>список переменных;</li>
<li>обязательность;</li>
<li>тип и допустимый формат;</li>
<li>минимальная и максимальная длина;</li>
<li>поведение при пустом значении;</li>
<li>допустимый набор символов;</li>
<li>источник данных;</li>
<li>пример корректного значения;</li>
<li>версия шаблона.</li>
</ul>
<p>Хранить этот контракт только в комментарии недостаточно. Валидатор должен использовать ту же схему, по которой команда согласовала шаблон.</p>
<h2 id='obyazatelnye-i-neobyazatelnye-znacheniya'>Обязательные и необязательные значения</h2>
<p>Если обязательного поля нет, сообщение не отправляют. Подстановка пустой строки может изменить смысл: <code>Встреча назначена на </code> выглядит как ошибка и вызывает обращение в поддержку.</p>
<p>Для необязательного блока лучше условная конструкция на уровне шаблонизатора, а не пробел вместо значения. Например, фраза про зал или подъезд должна исчезать целиком вместе с пунктуацией. Иначе остаются двойные пробелы, запятые и незавершённые предложения.</p>
<h2 id='tipy-i-format'>Типы и формат</h2>
<p>Дата форматируется в понятном часовом поясе, сумма — с валютой, номер заказа — без научной нотации, ссылка — только из разрешённого домена. Значение <code>2026-09-21T07:00:00Z</code> технически корректно, но не готово для клиента.</p>
<p>Не полагайтесь на неявное преобразование типов. <code>null</code>, <code>false</code>, ноль и пустая строка означают разные состояния. Особенно важен ноль: скидка 0% может быть корректным значением, а не отсутствием данных.</p>
<h2 id='ogranichenie-dliny'>Ограничение длины</h2>
<p>Длину проверяют после всех подстановок. Короткий шаблон может стать длинным из-за имени организации или ссылки. Изменение алфавита одной переменной способно переключить кодировку и увеличить число сегментов.</p>
<p>Расчёт должен использовать ту же логику, что и отправка. Основы GSM-7, Unicode и сегментации разобраны в статье про <a href="/dlina-sms-i-kolichestvo-segmentov/" rel="noopener" target="_blank">длину SMS</a>. Если итог превышает лимит сценария или бюджета, задача блокируется либо использует заранее согласованную короткую версию.</p>
<p>Автоматически обрезать имя или адрес опасно: можно удалить важную часть. Правило сокращения проектируют для конкретного поля и проверяют на примерах.</p>
<h2 id='nebezopasnye-simvoly-i-kontent'>Небезопасные символы и контент</h2>
<p>SMS не исполняет HTML, но данные всё равно могут ломать структуру: переносы строк, управляющие символы, невидимые пробелы, фигурные скобки шаблонизатора. Нормализуйте Unicode и разрешайте только ожидаемые символы для каждого поля.</p>
<p>Пользовательский ввод нельзя вставлять в рекламный текст без модерации. Он может содержать чужую ссылку, нежелательную лексику или персональные данные. Даже сервисное сообщение должно следовать принципу минимизации: передавайте клиенту только необходимое.</p>
<h2 id='ssylki'>Ссылки</h2>
<p>Ссылку собирают отдельно и проверяют до шаблона. Разрешите HTTPS и известные домены, запретите управляющие символы и неподтверждённые редиректы. Если используется <a href="/korotkie-ssylki-v-sms/" rel="noopener" target="_blank">короткая ссылка в SMS</a>, её жизненный цикл должен покрывать время чтения сообщения.</p>
<p>Не позволяйте переменной заменять весь домен по произвольному значению из CRM. Лучше хранить базовый адрес в конфигурации, а из события принимать безопасный идентификатор.</p>
<h2 id='neizmenyaemye-versii'>Неизменяемые версии</h2>
<p>После согласования шаблон получает версию. Изменение текста, набора переменных или ограничений создаёт новую версию, как описано в материале про <a href="/versii-sms-shablonov/" rel="noopener" target="_blank">версионирование SMS-шаблонов</a>.</p>
<p>Задача в очереди должна ссылаться на конкретную версию. Иначе повтор после релиза сформирует другой текст из тех же данных, что усложнит аудит и идемпотентность.</p>
<h2 id='testovye-nabory'>Тестовые наборы</h2>
<p>Для каждого шаблона подготовьте fixtures:</p>
<ul>
<li>обычный пример;</li>
<li>минимальные и максимальные значения;</li>
<li>пустое необязательное поле;</li>
<li>отсутствие обязательного поля;</li>
<li>кириллица, латиница, цифры и разрешённая пунктуация;</li>
<li>длинная ссылка;</li>
<li>значение с переносом и невидимым символом;</li>
<li>дата на границе суток и часового пояса;</li>
<li>текст, который меняет число SMS-сегментов.</li>
</ul>
<p>Snapshot-тест полезен для итоговой строки, но не заменяет отдельные проверки схемы. Ошибка должна говорить, какая переменная нарушила правило, а не просто «рендер не удался».</p>
<h2 id='povedenie-pri-oshibke'>Поведение при ошибке</h2>
<p>Некорректная задача не должна бесконечно повторяться. Её переводят в карантин или <a href="/dead-letter-queue-sms/" rel="noopener" target="_blank">DLQ</a> с кодом шаблона, версией, причиной и безопасными ID. Ответственный получает агрегированный сигнал, если ошибок много.</p>
<p>Нельзя подставлять заглушку вроде <code>не указано</code> без согласования: для даты визита или суммы это может создать вредное сообщение. Fallback допустим только там, где он является частью контракта шаблона.</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>все переменные перечислены в схеме;</li>
<li>обязательные поля не заменяются пустой строкой;</li>
<li>типы и часовые пояса преобразуются явно;</li>
<li>итоговая длина и сегменты считаются после рендера;</li>
<li>ссылки ограничены доверенными доменами;</li>
<li>управляющие и невидимые символы обрабатываются;</li>
<li>версия шаблона неизменяема;</li>
<li>есть тесты граничных значений;</li>
<li>ошибка блокирует отправку и попадает в наблюдаемый карантин.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Валидация переменных превращает SMS-шаблон из строки с маркерами в проверяемый контракт. Она останавливает пустые подстановки, неожиданные сегменты и небезопасные ссылки до внешнего API. Чем раньше система обнаруживает ошибку данных, тем меньше риск отправить её клиенту и тем проще найти источник.</p>
<p>Сообщение <a href="https://quicktel.ru/validaciya-peremennyh-sms-shablona/">Валидация переменных SMS-шаблона до отправки</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/validaciya-peremennyh-sms-shablona/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Мониторинг SMS-интеграции: метрики API, очереди и доставки</title>
		<link>https://quicktel.ru/monitoring-sms-integracii/</link>
					<comments>https://quicktel.ru/monitoring-sms-integracii/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Wed, 30 Sep 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Аналитика SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7321</guid>

					<description><![CDATA[<p>SMS-интеграция может отвечать HTTP 200 и при этом работать плохо: очередь растёт, DLR задерживаются, один оператор показывает аномальную недоставку, а важные уведомления уступают место массовой кампании. Поэтому мониторинг строят по всей цепочке, а не только по доступности API. Цель наблюдения — быстро ответить на три вопроса: создаются ли нужные сообщения, принимает ли их провайдер и [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/monitoring-sms-integracii/">Мониторинг SMS-интеграции: метрики API, очереди и доставки</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>SMS-интеграция может отвечать HTTP 200 и при этом работать плохо: очередь растёт, DLR задерживаются, один оператор показывает аномальную недоставку, а важные уведомления уступают место массовой кампании. Поэтому мониторинг строят по всей цепочке, а не только по доступности API.</p>
<p>Цель наблюдения — быстро ответить на три вопроса: создаются ли нужные сообщения, принимает ли их провайдер и достигают ли они ожидаемого результата вовремя.</p>
<h2 id='chetyre-sloya-metrik'>Четыре слоя метрик</h2>
<p>Первый слой — бизнес-события. Сколько оплат, заказов или запросов OTP должно было породить SMS и сколько задач реально создано. Без этого незаметен сбой до очереди.</p>
<p>Второй — внутренний конвейер: размер и возраст очереди, скорость workers, повторы, просроченные задачи, DLQ. Здесь видно, успевает ли приложение обрабатывать входящий поток.</p>
<p>Третий — SMS API: latency, ошибки по классам, 429, таймауты, доля принятых запросов и скорость отправки.</p>
<p>Четвёртый — доставка: финальные DLR, время до статуса, доля постоянных ошибок и разрез по оператору, маршруту, Sender ID и сценарию.</p>
<h2 id='glavnaya-metrika-vozrast-a-ne-tolko-razmer'>Главная метрика — возраст, а не только размер</h2>
<p>Очередь из тысячи задач может быть нормальной при высокой скорости, а десять задач с возрастом двадцать минут — критичными для OTP. Поэтому алерт строят по возрасту старейшей задачи и процентилям ожидания, отдельно для классов трафика.</p>
<p>Сравнивайте возраст с TTL. Если сообщение уже не успеет принести пользу, система должна остановить отправку и зафиксировать причину. Настройка срока жизни разобрана в статье про <a href="/srok-zhizni-sms-ttl/" rel="noopener" target="_blank">TTL SMS</a>.</p>
<h2 id='api-metriki'>API-метрики</h2>
<p>Отслеживайте p50, p95 и p99 времени ответа, а не только среднее. Ошибки группируйте на временные, постоянные, лимит и внутренние. Отдельная метрика нужна для неоднозначных таймаутов, когда неизвестно, принял ли провайдер сообщение.</p>
<p>Доля HTTP 200 без сопоставимого message ID тоже является ошибкой контракта. Успех означает, что система получила идентификатор и сохранила связь с <a href="/correlation-id-sms-integraciya/" rel="noopener" target="_blank">correlation ID</a>.</p>
<h2 id='metriki-dlr'>Метрики DLR</h2>
<p>Показатель доставки нельзя считать сразу после отправки. Установите окно созревания, например достаточное для большинства финальных статусов выбранного сценария. Свежие сообщения остаются в когорте <code>pending</code>, а не записываются в недоставленные.</p>
<p>Полезные показатели:</p>
<ul>
<li>доля финальной доставки;</li>
<li>доля pending старше ожидаемого окна;</li>
<li>время от события до принятия API;</li>
<li>время от принятия до delivered;</li>
<li>доля expired и permanent failure;</li>
<li>неизвестные коды DLR;</li>
<li>дубликаты и нарушения порядка webhook.</li>
</ul>
<p>Единый <a href="/mapping-statusov-sms-provajderov/" rel="noopener" target="_blank">маппинг статусов провайдеров</a> делает эти метрики сопоставимыми.</p>
<h2 id='razrezy-i-kardinalnost'>Разрезы и кардинальность</h2>
<p>Начните со сценария, провайдера, оператора, маршрута, Sender ID, типа трафика и среды. Не добавляйте номер телефона, message ID или correlation ID в labels метрик — уникальные значения перегрузят систему наблюдения.</p>
<p>Конкретный идентификатор хранится в логах и трассировках. Из графика оператор переходит к выборке логов по времени и стабильным измерениям, а затем исследует отдельные сообщения.</p>
<h2 id='alerty'>Алерты</h2>
<p>Алерт должен означать действие. Примеры:</p>
<ul>
<li>старейший OTP в очереди превысил допустимый возраст;</li>
<li>доля 429 растёт несколько минут;</li>
<li>permanent failure у одного оператора существенно выше базовой линии;</li>
<li>нет DLR для сообщений, принятых определённое время назад;</li>
<li>расход или сегменты растут быстрее объёма бизнес-событий;</li>
<li>появились неизвестные provider status;</li>
<li>конкретный критичный сценарий перестал создавать задачи.</li>
</ul>
<p>Фиксированный порог полезен для жёсткого SLO, а сравнение с обычной линией — для сезонных показателей. Алерт по одному событию часто шумит; используйте устойчивое окно и минимальный объём выборки.</p>
<h2 id='synthetic-proverka'>Synthetic-проверка</h2>
<p>Периодическая тестовая SMS на контролируемые номера помогает проверить путь до устройства, но сама создаёт расходы и не покрывает всех абонентов. Маркируйте такие сообщения отдельным сценарием, ограничьте частоту и исключите их из бизнес-аналитики.</p>
<p>Synthetic не заменяет реальные DLR. Он подтверждает, что выбранный маршрут в данный момент способен доставить несколько тестов, но не доказывает качество всего трафика.</p>
<h2 id='dashboard-dlya-raznyh-rolej'>Dashboard для разных ролей</h2>
<p>Дежурному нужны возраст очереди, ошибки, DLR и активные инциденты. Владельцу продукта — выполнение сценариев и влияние на клиента. Финансам — сегменты, стоимость и аномалии расходов. Одна перегруженная панель редко подходит всем.</p>
<p>Для каждого графика укажите источник, единицу, часовой пояс и окно данных. Смена версии маппинга или маршрута должна быть отмечена, иначе изменение показателя выглядит необъяснимым.</p>
<h2 id='runbook-ryadom-s-alertom'>Runbook рядом с алертом</h2>
<p>Алерт содержит ссылку на короткие действия: проверить очередь, статус провайдера, последние релизы, конкретные коды и возможность безопасно остановить сценарий. При внешнем сбое используется отдельный <a href="/sboj-sms-provajdera/" rel="noopener" target="_blank">план действий при отказе SMS-провайдера</a>.</p>
<p>После инцидента корректируют не только порог. Добавляют недостающую метрику, автоматический предохранитель или диагностическое поле, которое сократит следующий разбор.</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>есть метрика ожидаемых и созданных SMS-задач;</li>
<li>очередь контролируется по возрасту и классу трафика;</li>
<li>API latency измеряется процентилями;</li>
<li>429, таймауты и постоянные ошибки разделены;</li>
<li>DLR считаются после окна созревания;</li>
<li>доступны разрезы по оператору и сценарию;</li>
<li>уникальные ID не попадают в labels;</li>
<li>каждый алерт имеет владельца и runbook;</li>
<li>synthetic-трафик ограничен и отделён от бизнеса.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Хороший мониторинг SMS связывает бизнес-событие, внутреннюю очередь, вызов API и финальный DLR. Он показывает не только факт ошибки, но и место задержки, масштаб и затронутый сценарий. Это позволяет остановить проблему до того, как её первым заметит клиент.</p>
<p>Сообщение <a href="https://quicktel.ru/monitoring-sms-integracii/">Мониторинг SMS-интеграции: метрики API, очереди и доставки</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/monitoring-sms-integracii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Маппинг статусов SMS-провайдеров: единая модель DLR</title>
		<link>https://quicktel.ru/mapping-statusov-sms-provajderov/</link>
					<comments>https://quicktel.ru/mapping-statusov-sms-provajderov/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Tue, 29 Sep 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[SMS API]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7319</guid>

					<description><![CDATA[<p>У SMS-провайдеров отличаются названия и детализация статусов. Один возвращает DELIVRD, другой delivered, третий числовой код. Временная ошибка у одного означает повтор маршрута, а похожее слово у другого — финальный отказ. Если бизнес-система напрямую использует внешний словарь, смена шлюза затрагивает отчёты, автоматические действия и поддержку. Маппинг статусов создаёт внутреннюю модель DLR. Каждый внешний код переводится в [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/mapping-statusov-sms-provajderov/">Маппинг статусов SMS-провайдеров: единая модель DLR</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>У SMS-провайдеров отличаются названия и детализация статусов. Один возвращает <code>DELIVRD</code>, другой <code>delivered</code>, третий числовой код. Временная ошибка у одного означает повтор маршрута, а похожее слово у другого — финальный отказ. Если бизнес-система напрямую использует внешний словарь, смена шлюза затрагивает отчёты, автоматические действия и поддержку.</p>
<p>Маппинг статусов создаёт внутреннюю модель DLR. Каждый внешний код переводится в ограниченный набор состояний, но оригинальное значение сохраняется для диагностики.</p>
<h2 id='zachem-dva-urovnya-statusov'>Зачем два уровня статусов</h2>
<p>Внутренний статус отвечает на общий вопрос: сообщение принято, обрабатывается, доставлено или завершилось ошибкой. Внешний код объясняет детали конкретного маршрута. Если оставить только общий статус, поддержка потеряет причину. Если оставить только внешний, бизнес-логика станет зависеть от провайдера.</p>
<p>Практичная запись содержит:</p>
<ul>
<li>внутренний <code>delivery_status</code>;</li>
<li>исходные <code>provider_status</code> и <code>provider_error_code</code>;</li>
<li>признак финальности;</li>
<li>время события у провайдера и время получения;</li>
<li>provider message ID;</li>
<li>версию таблицы маппинга;</li>
<li>безопасное описание причины.</li>
</ul>
<h2 id='bazovaya-vnutrennyaya-model'>Базовая внутренняя модель</h2>
<p>Набор зависит от продукта, но обычно достаточно состояний:</p>
<ul>
<li><code>queued</code> — задача создана внутри системы;</li>
<li><code>accepted</code> — SMS API принял сообщение;</li>
<li><code>processing</code> — провайдер или оператор продолжает обработку;</li>
<li><code>delivered</code> — получен финальный положительный DLR;</li>
<li><code>failed_temporary</code> — известна временная проблема, возможны дальнейшие действия;</li>
<li><code>failed_permanent</code> — финальная недоставка;</li>
<li><code>expired</code> — истёк срок жизни;</li>
<li><code>rejected</code> — сообщение отклонено до доставки;</li>
<li><code>unknown</code> — код пока не распознан.</li>
</ul>
<p>Не объединяйте <code>accepted</code> и <code>delivered</code>. Успешный HTTP-ответ означает приём запроса, а не доставку на устройство. Общий жизненный цикл DLR описан в статье про <a href="/statusy-dostavki-sms/" rel="noopener" target="_blank">статусы доставки SMS</a>.</p>
<h2 id='finalnost-i-perehody'>Финальность и переходы</h2>
<p>Для каждого внешнего кода укажите, финальный ли он и какие переходы допустимы. События могут приходить повторно или не по порядку. Поздний промежуточный статус не должен откатывать уже зафиксированную доставку.</p>
<p>Вместо правила «последний webhook всегда прав» используйте таблицу переходов. Например, <code>processing → delivered</code> допустим, а <code>delivered → processing</code> игнорируется как запоздавшее событие. Спорный финальный переход сохраняется в журнале и поднимает сигнал, но не переписывает историю молча.</p>
<h2 id='neizvestnye-kody'>Неизвестные коды</h2>
<p>Новый код провайдера нельзя автоматически считать постоянной ошибкой. Сохраните его как <code>unknown</code>, добавьте метрику и уведомление владельцу интеграции. Затем документация сверяется, таблица маппинга обновляется и получает новую версию.</p>
<p>Fallback по строкам вроде «содержит fail» ненадёжен. Код и его смысл должны быть перечислены явно. Для числовых значений учитывайте тип: строка <code>001</code> не равна числу <code>1</code>, если ведущие нули значимы в контракте.</p>
<h2 id='webhook-i-pervichnyj-otvet'>Webhook и первичный ответ</h2>
<p>Синхронный ответ SMS API и последующий <a href="/webhook-dlya-statusov-sms/" rel="noopener" target="_blank">webhook DLR</a> проходят через один нормализатор, но имеют разные роли. Первый фиксирует приём или немедленный отказ. Webhook обновляет состояние позже.</p>
<p>Сохраняйте необработанный payload в защищённом ограниченном журнале только при необходимости и на заданный срок. Основная таблица должна содержать нормализованные поля, достаточные для работы продукта.</p>
<h2 id='prichiny-dlya-biznesa-i-podderzhki'>Причины для бизнеса и поддержки</h2>
<p>Пользователю не нужен десяток технических кодов оператора. Создайте отдельную классификацию причин: неверный номер, недоступный абонент, истёк TTL, запрещённый Sender ID, контент отклонён, недостаточно средств, лимит, неизвестная ошибка.</p>
<p>Текст для клиента и внутреннее описание разделяются. Нельзя показывать пользователю непроверенный сырой комментарий внешней системы. Для поддержки сохраняют provider code и ссылку на актуальную документацию.</p>
<h2 id='analitika-bez-iskazhenij'>Аналитика без искажений</h2>
<p>Метрики строятся по внутренним статусам, версии маппинга, провайдеру, оператору и сценарию. Если смысл внешнего кода изменился, старая история не должна тихо пересчитаться. Версия позволяет объяснить разрыв в отчёте.</p>
<p>Долю доставки считают только по сообщениям, для которых прошло достаточное окно получения финального DLR. Иначе свежие <code>processing</code> временно ухудшат показатель. Скорость и SLA анализируют отдельно, как описано в материале про <a href="/skorost-dostavki-sms-sla/" rel="noopener" target="_blank">скорость доставки SMS</a>.</p>
<h2 id='testirovanie-mappinga'>Тестирование маппинга</h2>
<p>Создайте набор fixtures из документированных и реально встреченных payload. Для каждого проверьте внутренний статус, финальность, причину и допустимый переход. Отдельные тесты нужны для дубликата события, неизвестного кода, нарушения порядка и webhook без message ID.</p>
<p>При подключении нового провайдера контракт считается готовым не после первой успешной SMS, а после прохождения всех значимых веток статусов. Недоступные в тесте случаи согласуются с поддержкой и помечаются как неподтверждённые.</p>
<h2 id='chek-list'>Чек-лист</h2>
<ul>
<li>внутренний словарь мал и не зависит от названий провайдера;</li>
<li>исходный код и ошибка сохраняются рядом;</li>
<li>у каждого кода задана финальность;</li>
<li>переходы защищены от запоздавших событий;</li>
<li>неизвестный код заметен и не маскируется;</li>
<li>маппинг имеет версию и тестовые fixtures;</li>
<li>синхронный ответ не считается доставкой;</li>
<li>аналитика учитывает окно ожидания финального DLR;</li>
<li>бизнес-причины отделены от сырого текста провайдера.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Единая DLR-модель изолирует продукт от словаря конкретного SMS-шлюза. Она упрощает миграцию, отчёты и автоматические реакции, не уничтожая диагностические детали. Ключевые свойства — сохранение исходного кода, явная финальность, контролируемые переходы и заметное состояние <code>unknown</code>.</p>
<p>Сообщение <a href="https://quicktel.ru/mapping-statusov-sms-provajderov/">Маппинг статусов SMS-провайдеров: единая модель DLR</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/mapping-statusov-sms-provajderov/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Dead Letter Queue для SMS: как разбирать сообщения после неудачных попыток</title>
		<link>https://quicktel.ru/dead-letter-queue-sms/</link>
					<comments>https://quicktel.ru/dead-letter-queue-sms/#respond</comments>
		
		<dc:creator><![CDATA[web_dev]]></dc:creator>
		<pubDate>Mon, 28 Sep 2026 07:00:00 +0000</pubDate>
				<category><![CDATA[Статьи]]></category>
		<category><![CDATA[#База Знаний]]></category>
		<category><![CDATA[Надёжность SMS]]></category>
		<guid isPermaLink="false">https://quicktel.ru/?p=7317</guid>

					<description><![CDATA[<p>Не каждую SMS-задачу удаётся обработать автоматически. Временный сетевой сбой можно повторить, но неверная схема события, отсутствующий шаблон или неизвестный код провайдера не исправятся от десятой попытки. Если такие задачи бесконечно возвращать в основную очередь, они расходуют ресурсы и скрывают системную проблему. Dead Letter Queue, или DLQ, — отдельное хранилище для задач, которые не удалось обработать [&#8230;]</p>
<p>Сообщение <a href="https://quicktel.ru/dead-letter-queue-sms/">Dead Letter Queue для SMS: как разбирать сообщения после неудачных попыток</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Не каждую SMS-задачу удаётся обработать автоматически. Временный сетевой сбой можно повторить, но неверная схема события, отсутствующий шаблон или неизвестный код провайдера не исправятся от десятой попытки. Если такие задачи бесконечно возвращать в основную очередь, они расходуют ресурсы и скрывают системную проблему.</p>
<p>Dead Letter Queue, или DLQ, — отдельное хранилище для задач, которые не удалось обработать по заданной политике. Она не является мусорной корзиной. У каждой записи остаются причина, история попыток и понятный путь: исправить и переиграть, закрыть как неактуальную или эскалировать владельцу.</p>
<h2 id='kogda-perevodit-zadachu-v-dlq'>Когда переводить задачу в DLQ</h2>
<p>Критерии задаются заранее:</p>
<ul>
<li>исчерпан лимит временных повторов;</li>
<li>событие не соответствует поддерживаемой версии схемы;</li>
<li>обязательные данные отсутствуют или невалидны;</li>
<li>шаблон или Sender ID не найден;</li>
<li>получен постоянный код ошибки провайдера;</li>
<li>задача просрочена по TTL;</li>
<li>обработчик обнаружил состояние, которое требует решения человека.</li>
</ul>
<p>Не все случаи означают повторную отправку. Просроченный OTP следует закрыть, а ошибку новой версии события — исправить и переобработать без потери бизнес-смысла.</p>
<h2 id='otlichie-dlq-ot-obychnoj-ocheredi'>Отличие DLQ от обычной очереди</h2>
<p><a href="/ochered-sms-soobshchenij/" rel="noopener" target="_blank">Основная SMS-очередь</a> оптимизирована для автоматического потока. DLQ оптимизирована для расследования. В ней важнее контекст ошибки, фильтры, владелец и контролируемый replay.</p>
<p>Запись должна содержать event ID, correlation ID, тип события, версию, время первой и последней попытки, число попыток, классификацию ошибки и безопасную ссылку на исходные данные. Полный текст, номер телефона и секреты не следует копировать без необходимости.</p>
<h2 id='klassifikatsiya-oshibok'>Классификация ошибок</h2>
<p>Единая строка <code>failed</code> мало помогает. Разделите причины хотя бы на категории:</p>
<ul>
<li>transient — временная внешняя проблема;</li>
<li>validation — некорректные входные данные;</li>
<li>configuration — отсутствует шаблон, маршрут или настройка;</li>
<li>contract — неизвестный ответ или несовместимая схема;</li>
<li>security — ошибка подписи, доступа или политики;</li>
<li>expired — сообщение потеряло смысл;</li>
<li>manual — требуется бизнес-решение.</li>
</ul>
<p>Категория определяет владельца и допустимость replay. Она также показывает тенденции: рост <code>contract</code> после релиза отличается от единичных невалидных номеров.</p>
<h2 id='povtornyj-zapusk'>Повторный запуск</h2>
<p>Кнопка «переотправить всё» опасна. Перед replay нужно устранить причину, выбрать ограниченную группу, проверить TTL и убедиться, что задача ещё актуальна. Новая попытка сохраняет исходный event ID и <a href="/idempotentnost-sms-api/" rel="noopener" target="_blank">idempotency key</a>, если речь о той же логической отправке.</p>
<p>Replay лучше выполнять в новую очередь с отметкой источника и пользователем, который его инициировал. Тогда основная обработка остаётся наблюдаемой, а аудит показывает, почему старое событие вернулось в поток.</p>
<p>Если сообщение могло быть принято провайдером до сбоя, сначала выясните его статус по client message ID. Слепой повтор неоднозначного запроса создаёт дубли.</p>
<h2 id='massovaya-problema'>Массовая проблема</h2>
<p>Тысячи одинаковых записей в DLQ обычно означают одну причину, а не тысячи отдельных инцидентов. Группируйте по коду ошибки, версии обработчика, шаблону, сценарию и времени начала. Интерфейс должен позволять увидеть representative sample без просмотра каждой строки.</p>
<p>При резком росте включается автоматический предохранитель: пауза проблемного сценария, отключение релиза или переключение маршрута. DLQ фиксирует последствия, но не должна быть единственным алертом.</p>
<h2 id='srok-hraneniya-i-dostup'>Срок хранения и доступ</h2>
<p>Храните запись достаточно долго для расследования и безопасного replay, но не бесконечно. Политика зависит от бизнес-сценария и требований к персональным данным. После завершения можно оставить агрегированную причину и технические ID, удалив payload.</p>
<p>Доступ к DLQ часто позволяет повторно запустить сообщения, поэтому это привилегированная операция. Нужны персональные учётные записи, журнал действий и разделение прав на просмотр и replay.</p>
<h2 id='metriki'>Метрики</h2>
<p>Следите за:</p>
<ul>
<li>числом новых DLQ-записей по категориям;</li>
<li>долей относительно общего потока;</li>
<li>возрастом самой старой открытой записи;</li>
<li>временем до назначения владельца и решения;</li>
<li>количеством replay и их результатом;</li>
<li>сценариями, шаблонами и версиями с наибольшим вкладом;</li>
<li>повторным попаданием одной задачи в DLQ.</li>
</ul>
<p>Нулевой размер DLQ не всегда хорош: если система удаляет неудачные задачи или бесконечно повторяет их в основной очереди, проблемы просто не видны.</p>
<h2 id='runbook-razbora'>Runbook разбора</h2>
<p>Для дежурной команды полезна короткая инструкция:</p>
<ol>
<li>Подтвердить масштаб и начало проблемы.</li>
<li>Сгруппировать записи по причине.</li>
<li>Проверить последние релизы и конфигурацию.</li>
<li>Остановить источник новых ошибок, если поток растёт.</li>
<li>Определить, какие сообщения ещё актуальны.</li>
<li>Исправить причину и протестировать одну запись.</li>
<li>Переиграть ограниченный пакет с мониторингом.</li>
<li>Зафиксировать решение и добавить автоматическую защиту.</li>
</ol>
<h2 id='tipichnye-oshibki'>Типичные ошибки</h2>
<ul>
<li>использовать DLQ как постоянный архив;</li>
<li>хранить там секреты и полный персональный payload;</li>
<li>не назначать владельца;</li>
<li>повторять просроченные сообщения;</li>
<li>генерировать новый ID при каждом replay;</li>
<li>смешивать ошибки отправки и финальную недоставку оператором;</li>
<li>не ограничивать массовый повтор;</li>
<li>удалять запись сразу после первого успешного replay без аудита.</li>
</ul>
<h2 id='itog'>Итог</h2>
<p>Dead Letter Queue делает необрабатываемые SMS-задачи видимыми и управляемыми. Хорошая DLQ хранит минимум безопасного контекста, классифицирует причины и поддерживает контролируемый replay. Её ценность не в количестве накопленных ошибок, а в коротком пути от сигнала до исправления и предотвращения повторения.</p>
<p>Сообщение <a href="https://quicktel.ru/dead-letter-queue-sms/">Dead Letter Queue для SMS: как разбирать сообщения после неудачных попыток</a> появились сначала на <a href="https://quicktel.ru">Quicktel</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://quicktel.ru/dead-letter-queue-sms/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
