From dc85ce8e1cff4229c540f05fb988946eeeda1945 Mon Sep 17 00:00:00 2001 From: Aleksei Chistiakov Date: Mon, 31 Aug 2026 11:17:13 +0500 Subject: [PATCH 1/3] fix(telegram): exclude link targets from message length Signed-off-by: Aleksei Chistiakov --- notify/telegram/telegram.go | 22 ++++++++++++++++++++-- notify/telegram/telegram_test.go | 11 +++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/notify/telegram/telegram.go b/notify/telegram/telegram.go index 645f12dcb5..bdd93d6bda 100644 --- a/notify/telegram/telegram.go +++ b/notify/telegram/telegram.go @@ -22,8 +22,10 @@ import ( "os" "strconv" "strings" + "unicode/utf8" commoncfg "github.com/prometheus/common/config" + "golang.org/x/net/html" "gopkg.in/telebot.v3" "github.com/prometheus/alertmanager/notify" @@ -31,7 +33,8 @@ import ( "github.com/prometheus/alertmanager/types" ) -// Telegram supports 4096 chars max - from https://limits.tginfo.me/en. +// Telegram supports up to 4096 characters after entity parsing. +// See https://core.telegram.org/bots/api#sendmessage. const maxMessageLenRunes = 4096 // Notifier implements a Notifier for telegram notifications. @@ -92,7 +95,7 @@ func (n *Notifier) Notify(ctx context.Context, alert ...*types.Alert) (bool, err if err != nil { return false, err } - if len([]rune(messageText)) > maxMessageLenRunes { + if htmlTextRuneCount(messageText) > maxMessageLenRunes { messageText = `Alertmanager notification could not be sent: message length exceeds Telegram limits. Please check the template used for producing the message content.` } @@ -147,6 +150,21 @@ func wrapWithFailureReason(err error) error { return err } +// htmlTextRuneCount excludes HTML markup and attribute values such as link targets. +func htmlTextRuneCount(message string) int { + tokenizer := html.NewTokenizer(strings.NewReader(message)) + count := 0 + + for { + switch tokenizer.Next() { + case html.ErrorToken: + return count + case html.TextToken: + count += utf8.RuneCount(tokenizer.Text()) + } + } +} + func createTelegramClient(apiURL, parseMode string, httpClient *http.Client) (*telebot.Bot, error) { bot, err := telebot.NewBot(telebot.Settings{ URL: apiURL, diff --git a/notify/telegram/telegram_test.go b/notify/telegram/telegram_test.go index 316d8ddab5..07d8fe765d 100644 --- a/notify/telegram/telegram_test.go +++ b/notify/telegram/telegram_test.go @@ -83,6 +83,7 @@ func TestTelegramRetry(t *testing.T) { func TestTelegramNotify(t *testing.T) { token := "secret" + longHTMLLink := `Open` fileWithToken, err := os.CreateTemp(t.TempDir(), "telegram-bot-token") require.NoError(t, err, "creating temp file failed") @@ -133,6 +134,16 @@ func TestTelegramNotify(t *testing.T) { expText: `Alertmanager notification could not be sent: message length exceeds Telegram limits. Please check the template used for producing the message content.`, }, + { + name: "HTML mode ignores link targets when enforcing length limit", + cfg: TelegramConfig{ + ParseMode: "HTML", + Message: longHTMLLink, + HTTPConfig: &commoncfg.HTTPClientConfig{}, + BotToken: commoncfg.Secret(token), + }, + expText: longHTMLLink, + }, { name: "Default mode with too-large message", cfg: TelegramConfig{ From fc7887d4787978bfb094cdd0a4cb24f102562461 Mon Sep 17 00:00:00 2001 From: Aleksei Chistiakov Date: Mon, 31 Aug 2026 15:46:37 +0500 Subject: [PATCH 2/3] fix(telegram): handle malformed HTML length checks Signed-off-by: Aleksei Chistiakov --- notify/telegram/telegram.go | 3 +++ notify/telegram/telegram_test.go | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/notify/telegram/telegram.go b/notify/telegram/telegram.go index bdd93d6bda..468530d768 100644 --- a/notify/telegram/telegram.go +++ b/notify/telegram/telegram.go @@ -158,6 +158,9 @@ func htmlTextRuneCount(message string) int { for { switch tokenizer.Next() { case html.ErrorToken: + if len(tokenizer.Raw()) > 0 { + return utf8.RuneCountInString(message) + } return count case html.TextToken: count += utf8.RuneCount(tokenizer.Text()) diff --git a/notify/telegram/telegram_test.go b/notify/telegram/telegram_test.go index 07d8fe765d..88c54e091d 100644 --- a/notify/telegram/telegram_test.go +++ b/notify/telegram/telegram_test.go @@ -84,6 +84,8 @@ func TestTelegramRetry(t *testing.T) { func TestTelegramNotify(t *testing.T) { token := "secret" longHTMLLink := `Open` + longMalformedHTML := ` Date: Mon, 31 Aug 2026 15:59:53 +0500 Subject: [PATCH 3/3] fix(telegram): handle malformed declaration tokens Signed-off-by: Aleksei Chistiakov --- notify/telegram/telegram.go | 2 ++ notify/telegram/telegram_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/notify/telegram/telegram.go b/notify/telegram/telegram.go index 468530d768..b8335e4564 100644 --- a/notify/telegram/telegram.go +++ b/notify/telegram/telegram.go @@ -162,6 +162,8 @@ func htmlTextRuneCount(message string) int { return utf8.RuneCountInString(message) } return count + case html.CommentToken, html.DoctypeToken: + return utf8.RuneCountInString(message) case html.TextToken: count += utf8.RuneCount(tokenizer.Text()) } diff --git a/notify/telegram/telegram_test.go b/notify/telegram/telegram_test.go index 88c54e091d..a95c3bd8ba 100644 --- a/notify/telegram/telegram_test.go +++ b/notify/telegram/telegram_test.go @@ -86,6 +86,10 @@ func TestTelegramNotify(t *testing.T) { longHTMLLink := `Open` longMalformedHTML := `