Я руковожу продуктовой командой, которая запускает гибридные онлайн-курсы.
Наш формат: часть обучения студенты проходят асинхронно (материалы всегда доступны на платформе), часть — в режиме вебинара с преподавателем.
Вебинары построены вокруг практики: студент должен прийти с выполненным домашним заданием или хотя бы попыткой решения. Преподавателю важно заранее увидеть работы группы, чтобы понять, где у студентов ошибки, разобрать разные пути решения, показать точно рабочее решение.
Для этого преподавателю нужно видеть домашки студентов за 2–3 дня до вебинара.
Роль куратора (и проблема)
В курсе есть куратор: он напоминает студентам о дедлайнах и вебинарах.
Но когда курсов стало несколько, у каждой группы — свои даты и дедлайны, куратор просто утонул в таблицах: часть напоминаний забывалась, часть дублировалась.
Очевидный вывод: рутинные напоминания нужно автоматизировать.
В статье покажу, как настроить систему уведомлений на примере одного курса:
студент получает напоминание в личку (а не в общий чат),
не получает лишних сообщений, если уже сдал ДЗ,
всё работает слаженно, на связке n8n + Google Sheets + Telegram и не требует денег (в отличии от куратора).
Что такое n8n
n8n — это no-code/low-code конструктор автоматизаций.
Представьте себе взрослую версию Scratch: вместо «котика, который прыгает» у вас «бот пишет студенту, что дедлайн завтра». Собирается тоже, как пазл. При сборке нашего решения, мы будем использовать две основные сущности:
Trigger (триггер) — событие. Например: «пришло сообщение», «шеф снова написал “срочно” в 23:59».
Action (действие) — то, что произойдет в ответ. Например: «отправить уведомление студенту» (или, если триггером было сообщение от шефа, то действие — «твой глаз дергается»).
Мы будем использовать:
триггеры Schedule и Telegram,
действия с Google Sheets и отправку сообщений в Telegram.
1. Готовим таблицу в Google Sheets
Создаём файл с несколькими листами:
students: student_id, name, email, telegram_id, tz, channel, course_id
homeworks: hw_id, student_id, course_id, due_at, status, link_to_submit
webinars: webinar_id, course_id, title, start_at, duration, meeting_url, ics_uid
course: course_id, title, start_at, duration, meeting_url, ics_uid
notifications_log: type, who, what_id, sent_at, channel, status
Советы:
tz — реальный часовой пояс студента (по умолчанию Europe/Moscow).
даты — в формате ISO 8601 с таймзоной (2025-09-20T18:00:00+02:00).
telegram_id пока пустое — соберём позже автоматически.
2. Создаём Telegram-бот
Чтобы студенты получали напоминания в личные сообщения, нужен отдельный бот-куратор.
Создать его просто:
В Telegram открываем @BotFather.
Вводим команду
/newbot
.Даем имя и ник (ник должен заканчиваться на
bot
). Пример:course_helper_bot
.BotFather выдаст Bot Token. Скопируем его — он понадобится в n8n.
Напиши своему боту
/start
, чтобы инициировать диалог.
Зачем нужен Bot Token
Bot Token — это ключ доступа к API Telegram.
Через него n8n сможет получать сообщения студентов (например, когда они пишут «/start») и отправлять студентам напоминания.
Позже мы добавим в n8n ноду Telegram Trigger, чтобы поймать chat_id
студента и записать его в поле telegram_id
на листе students
в Google Sheets.
3. Подключаем сервисы в n8n

Теперь подключим наши сервисы к n8n: Google Sheets и Telegram.
Подключаем Google Sheets
Открываем редактор n8n.
Переходим в раздел Credentials.
Создаем новую запись → Google Sheets (OAuth2).
Следом надо разрешить доступ к своему Google Drive. Это нужно, чтобы n8n мог читать и записывать данные в таблицу курса.
Подключаем Telegram
В том же разделе Credentials жмем Create Credential (красная кнопка справа сверху или плюсик рядом).
В поиске ищем
Telegram
.В появившейся форме Telegram API Token → вставляем токен, полученный у @BotFather. Остальные поля можно оставить пустыми.
Жмем Save.
После этого в списке появится новая запись Telegram account
.
В итоге будут два подключения в Credentials:
Google Sheets
Telegram
4. Получаем telegram_id студента

Чтобы бот мог писать студенту в личку, нужно узнать его chat_id
в Telegram.
Для этого создадим отдельный вспомогательный workflow.
Workflow: Get-Telegram-ChatId
В n8n создаем новый workflow с именем
Get-Telegram-ChatId
.Добавляем ноду Telegram Trigger → режим
On message
.Добавляем ноду Set.
Активируем workflow (Activate).
Пишем боту любое сообщение (например, «Привет!»).
Проверяем результат
В n8n надо открыть вкладку Executions.
Найти последнюю запись выполнения.
Кликнуть по ней и смотреть Output у ноды Telegram Trigger. Там будет JSON с объектом
message.chat.id
.
Пример:
"chat": {
"id": 123456789,
"first_name": "Имя",
...
}
Значение 123456789
— это и есть telegram_id
. Его надо вставить в таблицу в соответствующее поле. После этого можно деактивировать Get-Telegram-ChatId.
Сейчас мы сделали первый сценарий, всего у нас их будет два:
Get-Telegram-ChatId (с нодой Telegram Trigger) — разовый воркфлоу, чтобы поймать chat_id. У него свой триггер, поэтому он живёт в отдельном workflow.
HW-Reminders-3d — основной сценарий с Schedule/Cron, чтением из Google Sheets, IF и отправкой сообщений. У него другой триггер, поэтому это другой workflow.
В n8n у каждого воркфлоу свой «вход». Смешивать два разных триггера в одном нет смысла.
Идём дальше.
5. Создаём workflow для напоминания о ДЗ
Создаём новый workflow: HW-Reminders-3d. Для этого в n8n жмем кнопку Create Workflow. Даем имя HW-Reminders-3d.
Далее, будем добавлять ноды. Помним, чтобы добавить ноду, жмем плюсик справа (Add Node).
1. Schedule Trigger

запускается каждый день в 09:00 (таймзона Europe/Moscow).
2. Чтение данных

Добавляем ноду Google Sheets → настроить Credential (из раздела Credentials) → указать таблицу.
Resource:
Sheet
Operation:
Read
Mode:
All
Spreadsheet: выбираем свой файл
Sheet:
homeworks
Эта нода прочитает все строки листа homeworks
.
Сразу после неё — нода Code Normalize HW
(тип Code
):
return items.map(it => {
const j = it.json;
const sid = String(j.student_id || '').trim().toLowerCase();
const status = String(j.status || '').trim().toLowerCase(); // убираем пробелы
return { json: { ...j, sid, status } };
});
Читаем студентов из Google Sheets
Добавим вторую ноду Google Sheets (можно скопировать предыдущую), но указать лист students
:
Resource:
Sheet
Operation:
Read
Mode:
All
Sheet:
students
После неё — нода Code Normalize STU
:
return items.map(it => {
const j = it.json;
const sid = String(j.student_id || '').trim().toLowerCase();
return { json: { ...j, sid } };
});
Теперь нужно склеить домашки со студентами, для этого добавим ноду Merge

Mode:
Combine
Field to Match (Input 1):
sid
Field to Match (Input 2):
sid
Input 1 ←
Normalize HW
Input 2 ←
Normalize STU
Высчитываем «сколько осталось до дедлайна» с учётом часового пояса студента
Для этого добавим ноду Code Compute Deadline Diff
:
const j = $json;
const due = new Date(j.due_at);
const start_at = new Date(j.start_at);
const tz = j.tz || 'Europe/Moscow';
const nowTz = new Date(new Date().toLocaleString('en-US', { timeZone: tz }));
const diffDays = Math.floor((due - nowTz) / 86400000);
const diffHours = Math.round((due - nowTz) / 3.6e6);
return { ...j, diffDays, diffHours };
IF: выбираем только те элементы, где нужно напомнить

Добавим ноду IF:
Условие 1:
status
→equals
→pending
Условие 2:
diffDays
→equals
→3
Combine Conditions:
ALL (AND)
Подключим вход from Compute Deadline Diff
.
Ветка false можно никуда не вести. Если хочется следить, кто «не попал» под условия — можно отправлять их в «NoOp» или на отдельный лист логов.
Отправляем сообщение в Telegram (ветка true)
Добавляем ноду Telegram → Send Message:
Credentials: наш Telegram account
Chat ID:
{{$json.telegram_id}}
Text:
Привет, {{$json.name}}!
Через 3 дня дедлайн по ДЗ.
Сдать: {{$json.link_to_submit}}
Если уже сдал(а) — спасибо!
В n8n-хендлбарс-плейсхолдеры
{{$json.field}}
корректны для подстановки полей текущего элемента.
Пишем лог об отправке
Сразу после Telegram-ноды добавляем Google Sheets → Append row для листа notifications_log
:
Resource:
Sheet within document
Operation:
Append
(в некоторых версиях —Append row
)Document: наша таблица (всё время с одной и той же работаем)
Sheet:
notifications_log
-
Fields to send:
type
→hw
who
→{{$json.student_id}}
what_id
→{{$json.hw_id}}
sent_at
→{{$now}}
channel
→telegram
status
→ok
Этот лист — «бухгалтерия уведомлений»: тут видно, кому, когда и что отправили.
Обновляем статус домашки, чтобы не слать повторно
Нода Google Sheets → Update для листа homeworks
:
Resource:
Sheet
Operation:
Update
Key Column:
hw_id
Key Value:
{{$json.hw_id}}
Fields to send:
status
→notified
Это защищает от повторной отправки «за 3 дня» одному и тому же студенту по одному и тому же ДЗ.
Проверка: прогон и отладка
Сохраняем workflow и Activate.
Для быстрой проверки можно временно поменять время в
Schedule Trigger
или вместо него повесить Manual Trigger и выполнить запуск руками.Вкладка Executions покажет цепочку нод, вход/выход и возможные ошибки.
Расширение: несколько курсов и вебинары
Выше мы собрали минимальный вариант для одного курса и только для домашних заданий.
Но в реальной жизни курсов несколько, и у каждого свои вебинары. Чтобы не собирать отдельный workflow на каждый случай, лучше доработать существующий сценарий.
Блок Course
Добавляем лист course
и ноду Course
, которая подтягивает дополнительные данные по курсу:
связи между домашками и вебинарами,
даты ближайших вебинаров,
базовую информацию о курсе.
Это позволяет учитывать не только факт «сдать ДЗ», но и контекст курса в целом.
Loop Over Items → Get webinar for course
Этот блок нужен для циклической обработки вебинаров:
Loop Over Items
берёт спис��к курсов,для каждого курса запускает поиск связанных вебинаров в таблице,
на выходе получаем поток данных, где у студента есть и ДЗ, и вебинары.
Так reminders можно ставить не только для ДЗ, но и для событий (например, «через 2 дня вебинар»).
DateCompare + Code
Два блока, которые работают в паре:
DateCompare — упрощает сравнение дат (например, «меньше чем за 3 дня до события»).
Code — кастомные расчёты (
diffDays
,diffHours
), которые можно использовать в IF-условиях.
С их помощью можно точно решить, нужно ли отправить студенту уведомление о вебинаре.
Merge1: объединяем потоки
Если первый Merge
склеивал homeworks + students, то второй (Merge1
) нужен для объединения результата с вебинарами.
На выходе получаем единый поток данных: у каждого студента есть информация и о домашних заданиях, и о вебинарах.
Финальный штрих: Update row in sheet
После успешной отправки уведомления добавляем шаг Update row in sheet:
обновляем строку в
homeworks
,меняем поле
status
сpending
наnotified
Это защищает от повторной отправки одного и того же уведомления.
Лог в notifications_log
при этом остаётся, и можно отследить историю отправок.
Вот такой вышел итоговый вариант:

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