{"id":845,"date":"2022-08-21T13:50:15","date_gmt":"2022-08-21T13:50:15","guid":{"rendered":"http:\/\/oqtacore-blog-473533498.us-east-1.elb.amazonaws.com\/?p=845"},"modified":"2025-05-22T10:37:55","modified_gmt":"2025-05-22T10:37:55","slug":"aws-lambda-to-publish-message-to-a-telegram","status":"publish","type":"post","link":"https:\/\/oqtacore.com\/blog\/aws-lambda-to-publish-message-to-a-telegram\/","title":{"rendered":"Publishing messages to a telegram channel with AWS lambda"},"content":{"rendered":"<p><span data-preserver-spaces=\"true\">Telegram is a great thing with all its bots, groups, and channels. Let&#8217;s learn to post channel messages with an AWS Lambda<\/span><\/p>\n<p><!--more--><\/p>\n<p><span data-preserver-spaces=\"true\">For many of us developers, telegram became not only a single point of communication with real people but also with our infrastructure. For example, we at <a href=\"https:\/\/oqtacore.com\/services-for-resale\/\" target=\"_blank\" rel=\"noopener\">OQTACORE<\/a> often use telegram bots for alerts and simple configuration commands. In some cases, in the early stages of development, we even use telegram bots to monitor and reboot application servers on the weekends. A simple telegram bot is much easier to use than accessing SSH or an AWS console.<\/span><\/p>\n<p><span data-preserver-spaces=\"true\">But today we want to describe one of the most classical snippets we use &#8211; that is an AWS lambda that sends messages to a given channel. This can be used for the simplest alert mechanism.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Create_a_new_bot\"><\/span><span data-preserver-spaces=\"true\">Create a new bot<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">First, you would need a telegram bot. If you haven\u2019t already, open your Telegram client and message to @botfather<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-848 size-full\" src=\"http:\/\/blog.oqtacore.com\/wp-content\/uploads\/2022\/08\/Component-7.png\" alt=\"Creating a new telegram bot\" width=\"490\" height=\"553\" \/><\/p>\n<p>After a series of simple commands, you will be granted a token (pointed at by the red arrow).<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Add_the_bot_to_your_alerts_channel\"><\/span><span data-preserver-spaces=\"true\">Add the bot to your alerts channel<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">Create a new telegram channel and your bot there. Telegram will let you know that the bot can only be added with admin rights, and it should be fine.<\/span><\/p>\n<h2><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-849 size-full\" src=\"http:\/\/blog.oqtacore.com\/wp-content\/uploads\/2022\/08\/Component-8.png\" alt=\"Creating a new telegram channel\" width=\"394\" height=\"167\" \/><\/h2>\n<h2><\/h2>\n<h2><span class=\"ez-toc-section\" id=\"Get_the_channel_ID\"><\/span><span data-preserver-spaces=\"true\">Get the channel ID<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">\u00a0<\/span><span data-preserver-spaces=\"true\">Before writing the lambda, you will need to know the channel\u2019s ID. This is not hard. First, write some messages to the channel. Then you can use CURL:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">curl 'https:\/\/api.telegram.org\/bot{token}\/getUpdates'<\/pre>\n<p><span data-preserver-spaces=\"true\">Don\u2019t forget to replace {token} with your bot token that you obtained from @botfather!<\/span><\/p>\n<p><span data-preserver-spaces=\"true\">You will receive json with all messages from the channel, so let\u2019s say I wrote \u2018hey\u2019:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">{\r\n\r\n\u00a0\u00a0\"ok\": true,\r\n\r\n\u00a0\u00a0\"result\": [\r\n\r\n{\r\n\r\n\u00a0 \u00a0\"update_id\": 54351351,\r\n\r\n\u00a0 \u00a0\"channel_post\": {\r\n\r\n\u00a0 \u00a0 \u00a0\"message_id\": 8,\r\n\r\n\u00a0 \u00a0 \u00a0\"sender_chat\": {\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0\"id\": -351351351321,\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0\"title\": \"FsBet Alerts\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0\"type\": \"channel\"\r\n\r\n\u00a0 \u00a0 \u00a0},\r\n\r\n\u00a0 \u00a0 \u00a0\"chat\": {\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0\"id\": -351351354351,\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0\"title\": \"FsBet Alerts\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0\"type\": \"channel\"\r\n\r\n\u00a0 \u00a0 \u00a0},\r\n\r\n\u00a0 \u00a0 \u00a0\"date\": 1660047498,\r\n\r\n\u00a0 \u00a0 \u00a0\"text\": \"hey\"\r\n\r\n\u00a0 \u00a0}\r\n\r\n}\r\n\r\n\u00a0\u00a0]\r\n\r\n}<\/pre>\n<p><span data-preserver-spaces=\"true\">From this JSON, you need result.channel_post.chat.id. Just copy it manually, you don\u2019t need to write any code here \ud83d\ude42<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Finally_the_AWS_lambda\"><\/span><span data-preserver-spaces=\"true\">Finally, the AWS lambda<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span data-preserver-spaces=\"true\">This lambda is written in a such way that it can be immediately used with an API Gateway Proxy. It returns correct HTTP response codes. But you still can use it directly.<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">const https = require('https');\r\n\r\nconst chatId = %MY_CHAT_ID%;\r\n\r\nconst botToken = '%MY_BOT_TOKEN%';\r\n\r\nexports.handler = async (event) =&gt; {\r\n\r\nconst response = await sendMessage(JSON.parse(event.body).message);\r\n\r\nreturn response;\r\n\r\n};\r\n\r\nasync function sendMessage(message) {\r\n\r\nconst response = {\r\n\r\n\u00a0\u00a0\u00a0\u00a0 statusCode: 200,\r\n\r\n\u00a0\u00a0\u00a0\u00a0 headers: {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 'Content-Type': 'application\/json',\r\n\r\n\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n};\r\n\r\nreturn new Promise((resolve, reject) =&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0 const data = JSON.stringify({\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 chat_id: chatId,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 text: message,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 parse_mode: 'HTML'\r\n\r\n\u00a0\u00a0\u00a0\u00a0 });\r\n\r\n\u00a0\u00a0\u00a0\u00a0 const options = {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 hostname: 'api.telegram.org',\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 port: 443,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 path: `\/bot${botToken}\/sendMessage`,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 method: 'POST',\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 headers: {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 'Content-Type': 'application\/json',\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 'Content-Length': data.length,\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0 }\r\n\r\n\u00a0\u00a0\u00a0\u00a0 const req = https.request(options, res =&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 res.on('data', d =&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response.body = JSON.stringify(data);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response.statusCode = 200;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 resolve(response);\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\r\n\r\n\u00a0\u00a0\u00a0\u00a0 });\r\n\r\n\u00a0\u00a0\u00a0\u00a0 req.on('error', error =&gt; {\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response.body = JSON.stringify(error)\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 response.statusCode = 503;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 reject(error);\r\n\r\n\u00a0\u00a0\u00a0\u00a0 });\r\n\r\n\u00a0\u00a0\u00a0\u00a0 req.write(data);\r\n\r\n\u00a0\u00a0\u00a0\u00a0 req.end();\r\n\r\n})\r\n\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">To call this lambda, you can use such a test lambda event:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">{\r\n\r\n\u00a0\u00a0\"body\": \"{\\\"message\\\": \\\"test\\\"}\"\r\n\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Or, if you add this lambda to an API Gateway Proxy, this would be the way to call it:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">curl --request POST 'https:\/\/mysecretdomain.execute-api.eu-west-2.amazonaws.com\/qa\/telegram-bot\/send-alert' \\\r\n\r\n--header 'Content-Type: application\/json' \\\r\n\r\n--data-raw '{\r\n\r\n\u00a0\u00a0\"message\": \"test\"\r\n\r\n}'<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Conclusion\"><\/span><span style=\"font-weight: 400;\">Conclusion<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">That\u2019s it! Now you have a AWS lambda that you can call internally via AWS SDK or externally via API Gateway to send alerts to your telegram channel. We start most of our projects with this lambda, as setting up alerts is essential to ensure that everything works correctly\u2026 Especially on the weekends! \ud83d\ude42<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Telegram is a great thing with all its bots, groups, and channels. Let&#8217;s learn to post channel messages with an AWS Lambda<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_mo_disable_npp":"","yasr_overall_rating":0,"yasr_post_is_review":"","yasr_auto_insert_disabled":"","yasr_review_type":"","footnotes":""},"categories":[1],"tags":[18,17,16,26],"class_list":["post-845","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-it","tag-it-consulting","tag-system-integration","tag-tech-stuff"],"acf":{"image":855},"yasr_visitor_votes":{"number_of_votes":0,"sum_votes":0,"stars_attributes":{"read_only":false,"span_bottom":false}},"_links":{"self":[{"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/posts\/845","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/comments?post=845"}],"version-history":[{"count":19,"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/posts\/845\/revisions"}],"predecessor-version":[{"id":1914,"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/posts\/845\/revisions\/1914"}],"wp:attachment":[{"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/media?parent=845"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/categories?post=845"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oqtacore.com\/blog\/wp-json\/wp\/v2\/tags?post=845"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}