Если ваша 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, кладёт в YMQ
2. Менеджер нажимает кнопку → webhook → функция обновляет YDB и Telegram
3. 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.editor
ymq.writer
ymq.reader
serverless.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:2135
YDB_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:2135
YDB_DATABASE=
ORDERS_TABLE=insales_order_alerts

YMQ_QUEUE_URL=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=ru-central1

REMINDER_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-67
E-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.

Комментарии (2)


  1. egranty
    28.05.2026 12:26

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

    Задача: автономная система, работающая внутри РФ, без постоянного сервера, с доставкой уведомлений в Telegram за секунды.

    У меня - разрыв шаблона. Или Телеграм в РФ больше не блокируют?


    1. Dimazzina Автор
      28.05.2026 12:26

      Си, корректо

      Только в посте про саму доставку. К сожалению, если выбирать инструмент для мгновенных уведомлений в карман менеджерам, альтернатив Телеграму с такой же простой интеграцией сейчас практически нет.

      Запрос в Telegram API улетает из бэкенда (облачной функции Yandex Cloud), так что на этапе отправки внутри РФ всё происходит быстро. А дальше - да, идеальных каналов связи сейчас нет, но ТГ из доступного остается самым отзывчивым.

      Для крупных команд, конечно, правильнее настраивать приём в корпоративных мини-приложениях или чатах, но для малого e-commerce это быстрый и простой выход.