A zero-infrastructure Gmail → Telegram notification engine. Filters, deduplicates, and formats your inbox into structured Telegram alerts — running entirely inside Google Apps Script. No servers, no databases.
BOT_TOKEN and CHAT_ID held the actual
bot token and numeric chat ID as their values. Since
CONFIG_KEYS is a map of
property store key names, every set() and
get() call used the raw token string as the key —
so nothing was ever stored or retrieved correctly. This caused
the "BOT_TOKEN and CHAT_ID are required" crash on every
setup() call and the silent "Inbox Radar is
disabled" skip on every trigger run.
_parseMessage(message) accepted a
GmailMessage but internally aliased it as
thread and called
thread.getPlainBody() — a method that doesn't exist
on GmailThread. Also used
thread.getId() which returns a thread ID, not a
message ID. The function was never called (fetch() inlined its
own version) but left a correctness trap. Rewritten to accept
(msg, thread) and now used in fetch().
get("ENABLED") returns null before
setup() is called. null === "true" is
false, so every trigger run before initialization
would silently log "Inbox Radar is disabled" — masking
the real problem (setup not yet run). Added an explicit null
check with a clear log message.
buildDigest numbered list items with
${i + 1}\\. (MarkdownV2 escaped dot), but
telegramSender.send() defaults to legacy
Markdown mode. In that mode the backslash renders
literally, so every digest item appeared as
"1\. 🔐 Subject" instead of "1. 🔐 Subject".
dedupeStore.has(id) called
_load() internally, which hit
PropertiesService every call. With 20 messages
that's 20 separate API calls. Added
dedupeStore.snapshot() to load the Set once and
pass the reference through the entire loop.