Back to blog
Next.jsTelegramNode.jsBackend

Why I Route Contact Messages to Telegram (With Email as a Fallback)

June 6, 20262 min readby Niloy Mahmud Apu

A contact form that emails you is fine — until the email lands in spam, or you just don't check that inbox for a day. For something as time-sensitive as a potential client reaching out, I wanted the message on my phone the moment it's sent.

So I route contact-form submissions to a Telegram bot, and fall back to email only if that fails.

Setting up the bot

  1. Message @BotFather and create a bot to get a token.
  2. Get your numeric chat id from @userinfobot.
  3. Store both as server-side env vars (never NEXT_PUBLIC_):
TELEGRAM_BOT_TOKEN=123456:ABC...
TELEGRAM_CHAT_ID=987654321

Sending a message

The Bot API is a single HTTP call — no SDK required:

await fetch(`https://api.telegram.org/bot${TOKEN}/sendMessage`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    chat_id: CHAT_ID,
    text: message,
    parse_mode: "HTML",
  }),
});

The fallback that matters

Telegram is reliable, but "reliable" isn't "guaranteed." My API route tries Telegram first; if the call fails for any reason, it sends the same message over SMTP instead. The visitor always sees success, and I never lose a lead:

const telegramOk = await sendTelegram(name, email, message);
if (!telegramOk) {
  await sendEmail(name, email, message);
}

Don't forget spam

A public endpoint will get hit by bots. Two cheap defenses stop almost all of it:

  • A honeypot field hidden from real users — if it's filled, drop the request.
  • A simple rate limit per IP.

Result

Messages now buzz my phone within a second, formatted and readable, while email quietly backs everything up. It's the kind of small touch that makes a portfolio feel responsive and alive.