MAX
14 мин··

Массовая отправка через MAX: как не сломать канал первой же рассылкой

Практический разбор массовой отправки через MAX: очереди, безопасный темп, приоритеты и что считать нормальной инженерной защитой от 429.

Фактические детали в этой статье сверены по официальной документации MAX. Практики очередей, fallback-каналов и продуктовые советы здесь даны как инженерные рекомендации, а не как обещание платформы. Создание ботов, обзор Bot API, отправка сообщений, webhook, загрузка файлов.

Почему рассылка быстро становится сложной

На бумаге массовая отправка через MAX выглядит просто: берёте список получателей и крутите цикл поPOST /messages. В реальности такой подход ломается почти сразу, потому что канал защищает себя от перегрузки, а ваша бизнес-логика редко умеет держать ровный темп сама по себе.

Первая проблема обычно не “слишком мало возможностей MAX”, а отсутствие своей инфраструктуры: очереди, приоритетов, ретраев, дедупликации и нормальной наблюдаемости.

Рабочая архитектура

Для MAX-рассылки не нужен космический стек, но нужен скучный и предсказуемый pipeline:

Рендер схемы...

  1. Producer формирует сообщение и кладёт его в очередь, а не шлёт сразу в канал.
  2. Workers держат понятный темп отправки и не превышают безопасный RPS.
  3. DLQ хранит сообщения, которые не удалось доставить даже после повторов.
  4. Метрики отвечают на вопрос не “API хороший или плохой”, а “что именно сейчас мешает отправке”.

Приоритеты и очередь

Главная ошибка молодых продуктов это одна очередь на всё подряд. Тогда код подтверждения и маркетинговая рассылка дерутся за один и тот же канал.

Тип сообщенияПриоритетЧто делать
OTP и безопасностьP0Пускать первыми и не смешивать с маркетингом
Транзакционные статусыP1Держать в отдельной очереди или как минимум выше промо
Продуктовые напоминанияP2Можно терпеть умеренную задержку
Промо и массовые кампанииP3Давить последними и только после контроля темпа
const queueMessage = {
  chatId: "1234567890",
  message: "Ваш заказ отправлен",
  priority: "P1",
  clientId: "order_1001_sent",
};

Даже если у вас всего один worker, такое разделение уже спасает от самых неприятных продуктовых эффектов.

Retry и DLQ

В рассылке нельзя опираться на “один запрос = одна доставка”. У вас будут 429, 5xx, сетевые сбои и отдельные невалидные адресаты. Поэтому контур без retry и DLQ это не архитектура, а временная удача.

async function processJob(job) {
  try {
    return await maxClient.send(job.payload);
  } catch (error) {
    if ([429, 500, 502, 503, 504].includes(error.status)) {
      return queue.retry(job, computeBackoff(job.attempt));
    }

    return dlq.push({
      ...job,
      reason: error.status ?? "unknown_error",
    });
  }
}

DLQ нужен не только чтобы “не потерять” сообщения. Он нужен, чтобы команда видела, где у рассылки системная проблема: токены, формат, канал, конкретный тип пользователей или бизнес-логика.

Когда лучше не писать всё самому

Если вы запускаете одну внутреннюю кампанию, свой sender может быть оправдан. Но как только появляется несколько сценариев, приоритеты, CRM, операторы и соседние каналы, стоимость собственной инфраструктуры начинает расти быстрее, чем кажется в начале.

  • Нужно быстро соединить MAX с Telegram, VK или резервным SMS.
  • Нужны шаблоны, история отправки и статусы без отдельного internal tooling.
  • Команда не хочет поддерживать очереди и лимиты как отдельный мини-продукт.

В таком случае проще использовать готовую платформу вроде Relaya и оставить за собой только продуктовую логику. Если же вы строите всё сами, следующая статья по цепочке это разбор лимитов и работа с 429.

Массовая отправка ломается не потому, что “канал плохой”, а потому, что сообщение становится уже не просто сообщением, а задачей доставки. А задачи доставки любят очереди, приоритеты и дисциплину.

Создайте бесплатный MAX-профиль

Если хочется не просто читать, а сразу проверить сценарий руками: подключите MAX, отправьте себе тестовое сообщение и уже потом решайте, нужны ли другие каналы.