InSales без пушей: как бесплатно перенести уведомления о заказах в Telegram на Yandex Cloud Serverless

от автора

Если ваша CMS или CRM умеет отправлять email-копию о новом заказе на произвольный адрес — этот гайд для вас. InSales, RetailCRM, МойСклад, WooCommerce, Битрикс, самописная система — без разницы. Инфраструктура одна и та же. Ссылка на гитхаб с полный мануалом по установке на русском в конце статьи.

Поводом написать стало то, что неделю назад приложение InSales было удалено из App Store и пуши о заказах пропали сразу. Таким образом мы пропустили несколько заказов, но благо они не сорвались полностью, хотя небольшой неприятный осадок остался.

Первая мысль при поиске решения — n8n или Make. Но зарубежные no‑code платформы сейчас работают в России нестабильно из‑за замедлений и блокировок трафика. Строить критическую бизнес‑инфраструктуру на том, что может лечь в любой момент — плохая идея.

Задача: автономная система, работающая внутри РФ, без постоянного сервера, с доставкой уведомлений в Telegram за секунды. Решение — Yandex Cloud Serverless: он не боится блокировок, имеет очень щедрые лимиты, благодаря чему функция работает полностью бесплатно. К тому же, сервис очень гибок в настройке и улучшении.

Расскажу, что получилось, и дам полный гайд по настройке.

Пример уведомлений в ТГ

Пример уведомлений в ТГ

Архитектура: как это работает

Ключевой инсайт: InSales (и большинство других CMS/CRM) умеет отправлять email-копию о каждом новом заказе на указанный адрес. Этот email и стал источником данных. Ищите в настройках своей платформы что‑то вроде «отправлять копию заказа на email».

У Yandex Cloud есть Email Trigger — сервис, который создаёт технический почтовый адрес вида xxxx@serverless.yandexcloud.net. Когда на него приходит письмо, автоматически запускается Cloud Function с телом письма в payload.

Дальше всё просто:

InSales  ↓ email-уведомление о заказеYandex Cloud Email Trigger  ↓Cloud Function (Node.js)  ↓Telegram Bot API

Уведомление приходит в Telegram через 5–10 секунд после оформления заказа.

Две версии: Lite и Pro

Я сделал два варианта под разные сценарии.

Lite — для тех, кто работает в одиночку или просто хочет видеть заказы без лишних усложнений:

InSales email → Email Trigger → Cloud Function → Telegram

Никаких баз данных, никаких очередей. Настраивается за 20–40 минут.

Pro — скорее для команды менеджеров, где важно контролировать, кто и когда взял заказ в работу. Если заказ никто не взял в течение 10 минут (можно настроить время), то придёт повторное напоминание.

InSales email  ↓Email Trigger  ↓Cloud Function  ├─ отправляет заказ в Telegram (с кнопкой «Принять заказ»)  ├─ сохраняет заказ в YDB (статус: pending)  └─ кладёт request_id в YMQ с задержкой 10 минут        ↓     если заказ не принят - отправляет напоминание в Telegram

Почему YDB + YMQ

Можно было обойтись простым setTimeout или внешним cron — но оба варианта ненадёжны в serverless‑среде, где функция живёт ровно столько, сколько нужно для выполнения запроса.

YDB Serverless хранит статус каждого заказа (pending / accepted). При нажатии кнопки статус меняется — и когда YMQ через 10 минут снова вызывает функцию, она проверяет базу и молчит, если заказ уже принят.

YMQ (Yandex Message Queue) — это совместимый с AWS SQS брокер очередей. Он позволяет положить сообщение с задержкой (DelaySeconds: 600) и гарантировать его доставку. Функция не висит в памяти, а просто просыпается, когда пришло время.

Это классическая Event‑Driven Architecture: одна Cloud Function обрабатывает три типа событий, определяя источник по структуре входящего event:

Что пришло в event

Что делает функция

event.messages[] (email от триггера)

Парсит заказ, пишет в YDB, отправляет в Telegram, кладёт в YMQ

event.body.callback_query (клик кнопки)

Меняет статус в YDB, редактирует кнопку в Telegram

event.messages[] с request_id (из YMQ)

Проверяет статус в YDB, при необходимости шлёт напоминание

Ни одного постоянно работающего сервера. Платим только за фактические вызовы.

Сравнительная таблица версий

Возможность

Lite

Pro

Уведомление о заказе в Telegram

Парсинг email-письма InSales

Кнопка «Принять заказ»

Статус заказа в YDB

Кто принял заказ

Напоминание, если заказ не принят

Время настройки

20-40 мин

60-120 мин

Экономика: почему это почти бесплатно

Проект работает полностью на serverless, отдельный сервер не нужен. Оплата идёт только за фактическое использование.

На момент написания статьи Yandex Cloud даёт каждый месяц бесплатно:

  • Cloud Functions: 1 000 000 вызовов + 10 GB×hour выполнения

  • Yandex Message Queue: 100 000 запросов

  • YDB Serverless: 1 000 000 Request Units + 1 ГБ хранения

Триггеры (Email Trigger, YMQ Trigger) тарифицируются отдельно по числу вызовов функции, то есть дополнительных расходов за сами триггеры нет.

Посчитаем реальную нагрузку для Pro-версии. Один заказ создаёт примерно 2–3 вызова функции:

1. Email Trigger → функция получает заказ, пишет в YDB, шлёт в Telegram, кладёт в YMQ2. Менеджер нажимает кнопку → webhook → функция обновляет YDB и Telegram3. YMQ Trigger → функция проверяет статус (и молчит, если уже принят)

Заказов в день

В месяц

Вызовов функции в месяц

Укладываемся в бесплатный лимит?

10

~300

~600–900

✅ с запасом

100

~3 000

~6 000–9 000

✅ всё ещё с запасом

500

~15 000

~30 000–45 000

1 000

~30 000

~60 000–90 000

Для магазина с тысячей заказов в день нагрузка — это примерно 9% от бесплатного лимита вызовов Cloud Functions. YDB и YMQ тоже остаются в пределах бесплатной квоты.

Расчёт приблизительный. Точную стоимость лучше проверять в калькуляторе Yandex Cloud — тарифы, регион и объём логов влияют на итоговую сумму.


Пошаговый гайд по развёртыванию

Шаг 0. Создаём Telegram-бота и чат

Создаём бота:

Открываем @BotFather в Telegram, отправляем /newbot, задаём имя и username (должен заканчиваться на bot). BotFather выдаст токен — сохраняем:

TELEGRAM_BOT_TOKEN=1234567890:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Создаём чат и добавляем бота:

Создаём отдельную группу или канал для уведомлений о заказах. Добавляем бота как участника (в группу) или администратора (в канал). Для Pro-версии бот должен уметь редактировать сообщения.

Получаем chat_id:

Проще всего через @UserInfoBot — запускаем, выбираем нужный чат, копируем ID. Сохраняем:

TELEGRAM_CHAT_ID=-1001234567890

Проверяем, что всё работает:

https://api.telegram.org/bot<TOKEN>/sendMessage?chat\_id=<CHAT\_ID>&text=Проверка

Шаг 1. Подготавливаем Yandex Cloud

Заходим на console.yandex.cloud, создаём аккаунт и привязываем платёжный аккаунт (нужен для активации сервисов, даже если будем укладываться в бесплатный лимит).

Создаём сервисный аккаунт:

IAM → Сервисные аккаунты → Создать

Имя: order-alerts-functions-sa

Для Lite достаточно роли serverless.functions.invoker. Для Pro добавляем ещё:

ydb.editorymq.writerymq.readerserverless.functions.invoker

Для Pro — создаём статический ключ доступа:

Сервисный аккаунт → Создать новый ключ → Статический ключ доступа

⚠️ Secret access key показывается только один раз. Сохраните сразу.

AWS_ACCESS_KEY_ID=AWS_SECRET_ACCESS_KEY=

Шаг 2. Создаём YDB и YMQ (только для Pro)

YDB:

YDB → Создать базу данных → Serverless

Из строки подключения формата grpcs://.../?database=/ru-central1/xxxx/yyyy выделяем два значения:

YDB_ENDPOINT=grpcs://ydb.serverless.yandexcloud.net:2135YDB_DATABASE=/ru-central1/xxxx/yyyy

Создаём таблицу в Query editor:

CREATE TABLE `insales_order_alerts` (  request_id Utf8 NOT NULL,  status Utf8,  order_number Utf8,  phone Utf8,  name Utf8,  customer_email Utf8,  products_text Utf8,  total_price Utf8,  comment Utf8,  delivery_text Utf8,  payment_text Utf8,  payment_status Utf8,  order_url Utf8,  message_id Utf8,  created_at Utf8,  accepted_by Utf8,  accepted_at Utf8,  raw_subject Utf8,  raw_email_text Utf8,  PRIMARY KEY (request_id));

YMQ:

Message Queue → Создать очередь → Standard

Название: insales-order-reminders. Задержку доставки оставляем 0 задержка будет задаваться в коде (DelaySeconds: 600). После создания копируем URL очереди:

YMQ_QUEUE_URL=https://message-queue.api.cloud.yandex.net/xxxx/yyyy/insales-order-reminders

Шаг 3. Создаём Cloud Function

Cloud Functions → Создать функцию

Имя: order-mail-to-telegram. Runtime: Node.js. Точка входа: index.handler. Сервисный аккаунт: order-alerts-functions-sa.

Загружаем код:

Берём lite/index.js или pro/index.js из репозитория. Добавляем package.json:

Для Lite:

{  "dependencies": {    "html-to-text": "^9.0.5"  }}

Для Pro:

{  "dependencies": {    "ydb-sdk": "^5.11.1",    "@yandex-cloud/nodejs-sdk": "latest",    "@aws-sdk/client-sqs": "^3.600.0",    "html-to-text": "^9.0.5"  }}

Переменные окружения для Pro:

TELEGRAM_BOT_TOKEN=TELEGRAM_CHAT_ID=YDB_ENDPOINT=grpcs://ydb.serverless.yandexcloud.net:2135YDB_DATABASE=ORDERS_TABLE=insales_order_alertsYMQ_QUEUE_URL=AWS_ACCESS_KEY_ID=AWS_SECRET_ACCESS_KEY=AWS_REGION=ru-central1REMINDER_DELAY_SECONDS=600

После деплоя у функции появится URL — сохраняем его, он понадобится для webhook.

Для Pro делаем функцию публичной (Telegram будет стучаться в неё при нажатии кнопки).


Шаг 4. Подключаем Email Trigger

Cloud Functions → Триггеры → Создать триггер → Почта

Привязываем к нашей функции, выбираем сервисный аккаунт, размер группы = 1, количество попыток = 1 на старте.

Если при сохранении триггера появляется ошибка прав — временно выдайте сервисному аккаунту роль editor, создайте триггер, затем отзовите обратно.

После создания триггер выдаст технический email-адрес:

xxxxxxxxxxxxxxxxxxxx@serverless.yandexcloud.net

Добавляем его в InSales:

Настройки → Карточка магазина → Email для уведомлений

Шаг 5. Настраиваем Telegram Webhook (только для Pro)

Устанавливаем webhook. Делается одним GET-запросом в браузере:

https://api.telegram.org/bot<TOKEN>/setWebhook?url=<FUNCTION\_URL>&allowed\_updates=%5B%22message%22%2C%22callback\_query%22%5D

Проверяем:

https://api.telegram.org/bot<TOKEN>/getWebhookInfo

В ответе должны быть:

  • url — URL нашей Cloud Function

  • allowed_updates — содержит callback_query

Без callback_query кнопка «Принять заказ» работать не будет.


Шаг 6. Создаём YMQ Trigger (только для Pro)

Cloud Functions → Триггеры → Создать триггер → Message Queue

Выбираем очередь insales-order-reminders, привязываем к той же функции. Размер группы = 1.

На этом настройка завершена. Создаём тестовый заказ и через 5–10 секунд в Telegram придёт уведомление.


Как это работает под капотом

Самое интересное — как один handler разбирается с тремя совершенно разными типами входящих событий.

module.exports.handler = async function (event) {  try {    console.log('Incoming event keys:', Object.keys(event || {}));    // 1. Telegram webhook: менеджер нажал кнопку «Принять заказ»    const callback = getTelegramCallback(event);    if (callback) {      console.log('Route: telegram callback');      return await handleTelegramCallback(callback);    }    // 2. YMQ Trigger: пришло отложенное напоминание из очереди    const requestIds = extractRequestIdsFromQueueEvent(event);    if (requestIds.length > 0) {      console.log('Route: reminder queue', requestIds);      return await handleReminderEvent(requestIds);    }    // 3. Email Trigger: новый заказ из InSales    if (event.httpMethod && event.httpMethod !== 'POST') {      return jsonResponse(405, { ok: false, error: 'Method not allowed' });    }    console.log('Route: email order');    return await handleEmailOrder(event);  } catch (error) {    console.error('insales-order-handler failed:', error);    return jsonResponse(500, { ok: false, error: 'Internal server error', message: error.message });  }};

Логика роутинга проста:

  • Если в event есть callback_query — это Telegram webhook. Достаём request_id из callback_data, находим заказ в YDB, меняем статус на accepted, редактируем кнопку и уведомляем чат.

  • Если в event.messages[] есть JSON с request_id — это сообщение из YMQ. Смотрим статус заказа в YDB: если pending — шлём напоминание, если accepted — молчим.

  • Всё остальное Email Trigger с письмом о заказе. Парсим, пишем в YDB, шлём в Telegram, кладём request_id в YMQ.

Парсер письма

Это самая хрупкая часть. Письма от разных магазинов приходят в разном формате, поэтому парсер построен на массиве регулярных выражений с приоритетом — matchFirst берёт первое совпадение:

const orderNumber = matchFirst(sourceText, [  /Поступил заказ\s*№\s*([^\s\n]+)/i,  /заказ\s*№\s*([^\s\n!]+)/i,  /Благодарим Вас за заказ\s*№\s*([^\s\n!]+)/i,  /Новый заказ\s*№\s*([^\s\n]+)/i,]);

Аналогично работает извлечение телефона, email, состава заказа, доставки и ссылки на админку. HTML из письма преобразуется в текст через html-to-text, после чего regex-ами вырезаются нужные блоки.

Ссылка на заказ в админке вытаскивается отдельно InSales часто оборачивает её в tracking URL. Функция extractRealUrlFromInsalesTracker декодирует base64url-параметр url, чтобы получить реальный адрес:

function extractRealUrlFromInsalesTracker(url) {  const parsed = new URL(rawUrl);  const encodedTarget = parsed.searchParams.get('url');  const decodedTarget = decodeBase64Url(encodedTarget);  return decodedTarget || rawUrl;}

Как выглядит уведомление

Обычное уведомление о заказе:

🛒 Новый заказ!Заказ: №6004Клиент: ИванТелефон: 8(999)123-45-67E-mail: client@example.comСостав заказа:Массажный пистолет Booster M2Комплектация: Набор для домаСумма: 9 990 ₽Оплата: Оплата при полученииОткрыть заказ в админке  [кнопка][✅ Принять заказ]

Напоминание через 10 минут (если заказ не взяли):

🚨 Заказ не принят 10 минутЗаказ: №6004Клиент: ИванТелефон: 8(999)123-45-67Открыть заказ в админке

Адаптация под другие системы

К InSales привязан только парсер письма, и то его легко переписать. Сама инфраструктура (Email Trigger → Cloud Function → YDB/YMQ → Telegram) работает с любой системой, которая умеет слать email-копию о заказе.

Единственное условие: в настройках вашей платформы должна быть возможность добавить дополнительный email-адрес для уведомлений о заказах. В большинстве CMS и CRM это есть.

Очевидно совместимо:

  • RetailCRM — есть настройка уведомлений на email

  • МойСклад — есть триггеры по событиям с email-уведомлением

  • Любая самописная CRM — если умеет слать письма

  • Другие CMS — Битрикс, OpenCart, WooCommerce

Для адаптации под другой формат письма достаточно поправить регулярки в parseOrderEmail, extractProductsText и extractDeliveryText. Подробный разбор каждой функции — в docs/code-overview.md в репозитории.


Итог

Система работает, менеджеры не пропускают заказы. Весь функционал обходится абсолютно бесплатно. В будущем можно расширяться — добавить полезные кнопки, разнообразить статусы заказа.

Что получилось:

  • Serverless — нет постоянного сервера, платить не за что

  • Работает внутри РФ — никаких зависимостей от зарубежных сервисов, максимальная скорость

  • Event‑Driven — одна функция обрабатывает email, webhook и очередь

  • Open source — можно форкнуть и адаптировать под свой стек

Сервис для отправки заказов из email-уведомлений интернет-магазина в Telegram через Yandex Cloud. Есть Lite-версия для простых уведомлений и Pro-версия с кнопкой принятия, статусом заказа и напоминанием, если заказ не принят в течение некоторого времени. Функционал бесплатный или совсем дешёвый при огромных объёмах, не боится блокировок.

Код в репозитории DmitriiDmallSick/order-mail-to-telegram: полная документация с пошаговыми скриншотами, два варианта кода (Lite и Pro), примеры .env файлов и разбор каждой функции в docs/code-overview.md.

ссылка на оригинал статьи https://habr.com/ru/articles/1040472/