Отправка SMS из 1С через свою SIM-карту

Задача обычно звучит так: при событии в 1С — заказ оплачен, товар приехал, запись к врачу подтверждена — клиенту должна уйти SMS. Дальше начинается поиск «сервиса для отправки SMS из 1С», и он упирается в закрытый список провайдеров внутри самой 1С.

Почему нужного провайдера нет в списке

В типовых конфигурациях на базе библиотеки стандартных подсистем есть готовая подсистема «Отправка SMS». Список провайдеров в ней закрытый: он зашит в саму библиотеку, и добавить туда стороннего оператора, не меняя конфигурацию, нельзя. Если нужного провайдера в списке нет — через этот механизм подключиться не получится.

Поэтому интеграция делается иначе: 1С сама отправляет HTTP-запрос туда, куда нужно. Это работает в любой конфигурации, не требует изменения типовой (если положить код во внешнюю обработку) и не зависит от версии библиотеки.

Что понадобится

Белый IP, открытые порты и проброс наружу не нужны: 1С обращается к сервису сама, а телефон подключается к облаку сам.

Готовый код: отправка сообщения

Функцию можно положить в общий модуль конфигурации или во внешнюю обработку — тогда типовую менять не придётся вовсе. Код должен выполняться на сервере: в веб-клиенте HTTPСоединение на стороне браузера недоступно.

Функция ОтправитьSMS(Номер, Текст) Экспорт

    Токен = "ВАШ_API_КЛЮЧ";

    // Тело запроса
    Запись = Новый ЗаписьJSON;
    Запись.УстановитьСтроку();
    Запись.ЗаписатьНачалоОбъекта();
    Запись.ЗаписатьИмяСвойства("phoneNumber");
    Запись.ЗаписатьЗначение(Номер);
    Запись.ЗаписатьИмяСвойства("text");
    Запись.ЗаписатьЗначение(Текст);
    // requestId — свой идентификатор запроса. Если 1С повторит отправку
    // (обрыв связи, перезапуск задания), второе SMS с тем же requestId
    // создано не будет.
    Запись.ЗаписатьИмяСвойства("requestId");
    Запись.ЗаписатьЗначение(Строка(Новый УникальныйИдентификатор));
    Запись.ЗаписатьКонецОбъекта();
    ТелоЗапроса = Запись.Закрыть();

    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Authorization", "Bearer " + Токен);
    Заголовки.Вставить("Content-Type", "application/json");

    Соединение = Новый HTTPСоединение(
        "api.textbee.ru", 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL);

    HTTPЗапрос = Новый HTTPЗапрос("/v1/sms/send", Заголовки);
    HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса, КодировкаТекста.UTF8);

    Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);

    Результат = Новый Структура("Успех, Статус, Идентификатор, Ошибка",
        Ложь, "", "", "");

    ТелоОтвета = Ответ.ПолучитьТелоКакСтроку();
    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(ТелоОтвета);
    Данные = ПрочитатьJSON(Чтение, Истина);
    Чтение.Закрыть();

    Если Ответ.КодСостояния = 200 Или Ответ.КодСостояния = 201 Тогда
        Результат.Успех = Истина;
        Результат.Статус = Данные.Получить("status");
        Результат.Идентификатор = Данные.Получить("messageId");
    Иначе
        Результат.Ошибка = "" + Ответ.КодСостояния + ": "
            + Строка(Данные.Получить("message"));
    КонецЕсли;

    Возврат Результат;

КонецФункции

Вызов:

Итог = ОтправитьSMS("+79161234567", "Заказ №1245 оплачен. Спасибо!");

Если Итог.Успех Тогда
    Сообщить("Отправлено, статус: " + Итог.Статус);
Иначе
    Сообщить("Не отправлено. " + Итог.Ошибка);
КонецЕсли;

Что приходит в ответ

Поле status отвечает на главный вопрос — что произошло с сообщением прямо сейчас:

Коды ответа, которые стоит обработать отдельно: 402 — исчерпан лимит тарифа или нужен платный; 429 — слишком часто; 503 — ни одного телефона на связи.

Статус доставки позже

Доставка подтверждается не мгновенно. Если она важна, идентификатор из messageId нужно сохранить у себя и запросить статус позже — например, регламентным заданием раз в несколько минут:

Функция СтатусSMS(Идентификатор) Экспорт

    Токен = "ВАШ_API_КЛЮЧ";

    Заголовки = Новый Соответствие;
    Заголовки.Вставить("Authorization", "Bearer " + Токен);

    Соединение = Новый HTTPСоединение(
        "api.textbee.ru", 443, , , , 30, Новый ЗащищенноеСоединениеOpenSSL);

    HTTPЗапрос = Новый HTTPЗапрос("/v1/messages/" + Идентификатор, Заголовки);
    Ответ = Соединение.Получить(HTTPЗапрос);

    Чтение = Новый ЧтениеJSON;
    Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
    Данные = ПрочитатьJSON(Чтение, Истина);
    Чтение.Закрыть();

    Возврат Данные.Получить("status");

КонецФункции

Грабли, на которые наступают

Код выполняется на клиенте. В веб-клиенте HTTPСоединение недоступно. Отправку надо выполнять в серверной процедуре — директивой &НаСервере или из регламентного задания.

Прокси в организации. Если сервер 1С ходит в интернет через прокси, его нужно передать в соединение — иначе запрос просто не уйдёт:

Прокси = Новый ИнтернетПрокси;
Прокси.Установить("https", "proxy.company.local", 3128);
Соединение = Новый HTTPСоединение(
    "api.textbee.ru", 443, , , Прокси, 30, Новый ЗащищенноеСоединениеOpenSSL);

Отправка в цикле по документу. Не отправляйте SMS прямо в проведении документа: запрос в интернет внутри транзакции затягивает проведение и падает вместе с ним. Правильнее записать задание в регистр и отправлять регламентным заданием.

Повторы и дубли. Если задание перезапустится, клиент получит второе такое же SMS. От этого спасает requestId: сохраните его вместе с заданием и передавайте тот же самый при повторе — второе сообщение создано не будет.

Кодировка. Тело запроса передаётся строго в UTF-8 (УстановитьТелоИзСтроки(..., КодировкаТекста.UTF8)). Без этого русский текст уедет вопросительными знаками.

Честно про готовую обработку

Готовой внешней обработки .epf или расширения конфигурации у нас пока нет — есть код выше, и он рабочий. Если вам нужна именно обработка «поставил и работает», напишите: support (собака) textbee.ru. Мы собираем такие запросы, и по ним решаем, что делать следующим.

Своя SIM-карта вместо оператора рассылок

Сообщения уходят с вашего номера по вашему тарифу. Комиссию за SMS мы не берём — на бесплатном тарифе 50 отправок в месяц.

Попробовать бесплатно   Документация API →

Частые вопросы

Есть ли готовая обработка или расширение для 1С?

Готовой внешней обработки пока нет, и мы говорим об этом прямо. Отправка делается вызовом REST API из встроенного языка — код целиком приведён выше, он работает в любой конфигурации на платформе 8.3 и не требует изменения самой конфигурации, если положить его во внешнюю обработку.

Почему TextBee нет в списке провайдеров SMS в 1С?

Список провайдеров в подсистеме «Отправка SMS» библиотеки стандартных подсистем закрытый: он задан в самой библиотеке, и добавить туда стороннего провайдера без изменения конфигурации нельзя. Поэтому интеграция идёт не через этот список, а прямым HTTP-запросом.

Сколько стоит SMS, отправленная из 1С?

Сообщение уходит с вашей SIM-карты по вашему тарифу у оператора — мы комиссию за сообщение не берём. Оплачивается только тариф сервиса, на бесплатном доступно 50 отправок в месяц.

Нужен ли для этого белый IP или открытый порт?

Нет. 1С сама обращается наружу к api.textbee.ru по HTTPS, входящих подключений к серверу 1С не требуется. Телефон со шлюзом тоже подключается наружу сам.

Что будет, если телефон в этот момент выключен?

Сообщение встанет в очередь и уйдёт, когда телефон вернётся на связь. В ответе при этом придёт статус queued, а не sent — по нему видно, что сообщение принято, но ещё не отправлено.