Last active
January 1, 2024 20:38
-
-
Save tayyebi/669b0b5d0ccf407bb66d6a9325349a09 to your computer and use it in GitHub Desktop.
Google Apps Script bot, to forward fetched messages from Telegram to E-Mail.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This code includes contributions made by Bing AI. | |
* | |
* Copyright (c) [2024] [Mohammad Reza Tayyebi] | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in all | |
* copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
* SOFTWARE. | |
*/ | |
// Import UrlFetchApp to make requests to Telegram API | |
var UrlFetchApp = UrlFetchApp; | |
// Telegram Bot Token | |
var TELEGRAM_TOKEN = '6285:nozW_xLENQM'; | |
// Your email | |
var YOUR_EMAIL = 'mailify@tyyi.net'; | |
// This function converts a telegram message object to an html string | |
function messageToHtml(message) { | |
// Get the message text, sender name, date and time | |
var jsonString = JSON.stringify(message, null, 2); | |
var text = message.text || message.caption || ""; | |
var name = message.from ? message.from.first_name + " " + message.from.last_name : message.chat.title; | |
var date = new Date(message.date * 1000); // Telegram uses unix timestamp in seconds | |
var time = Utilities.formatDate(date, Session.getScriptTimeZone(), "HH:mm:ss"); | |
var userId = message.from ? message.from.id : "Unknown"; | |
var isBot = message.from ? message.from.is_bot : "Unknown"; | |
var chatId = message.chat ? message.chat.id : "Unknown"; | |
var chatType = message.chat ? message.chat.type : "Unknown"; | |
var authorSignature = message.author_signature || "Unknown"; | |
var forwardedFrom = message.forward_from ? message.forward_from.first_name + " " + message.forward_from.last_name : "Unknown"; | |
var userHandle = (chatType === "private" && message.from && message.from.username) ? "<a href='https://t.me/" + message.from.username + "'>@" + message.from.username + "</a>" : "Unknown"; | |
var chatLink = (chatType === "channel" && message.chat.username) ? "<a href='https://t.me/" + message.chat.username + "'>Channel Link</a>" : ((chatType === "group" || chatType === "supergroup") ? "<a href='https://t.me/c/" + chatId + "/" + message.message_id + "'>Group Message Link</a>" : "Unknown"); | |
// Create an html element for the message | |
var html = "<div class='message'>"; | |
html += "<dl class='metadata'>"; | |
html += "<dt>Name</dt><dd class='name'><b>" + name + "</b></dd>"; | |
html += "<dt>User ID</dt><dd class='userId'>" + userId + "</dd>"; | |
html += "<dt>Is Bot</dt><dd class='isBot'>" + (isBot ? 'bot' : '') + "</dd>"; | |
html += "<dt>Time</dt><dd class='time'>" + time + "</dd>"; | |
html += "<dt>Chat ID</dt><dd class='chatId'>" + chatId + "</dd>"; | |
html += "<dt>Chat Type</dt><dd class='chatType'>" + chatType + chatLink + "</dd>"; | |
html += "<dt>Author Signature</dt><dd class='authorSignature'>" + authorSignature + "</dd>"; | |
html += "<dt>Forwarded From</dt><dd class='forwardedFrom'>" + forwardedFrom + "</dd>"; | |
html += "<dt>User Handle</dt><dd class='userHandle'>" + userHandle + "</dd>"; | |
html += "</dl>"; | |
html += "<div class='text'>" + text + "</div>"; | |
html += "<!--<div class='preformatted'><details><summary>More detailes</summary><pre>" + jsonString + "</pre></details></div>-->"; // Add the JSON string as preformatted text | |
html += "</div>"; | |
Logger.log(removeHtmlTags(html)); | |
return html; | |
} | |
// This function gets the file path for a given file id from the telegram API | |
function getFilePath(fileId) { | |
var token = TELEGRAM_TOKEN; // Replace with your bot token | |
var url = "https://api.telegram.org/bot" + token + "/getFile?file_id=" + fileId; | |
var response = UrlFetchApp.fetch(url); | |
var data = JSON.parse(response.getContentText()); | |
return data.result.file_path; | |
} | |
function removeHtmlTags(htmlString) { | |
return htmlString.replace(/<[^>]*>?/g, '\r\n'); | |
} | |
// This function gets the file data as a blob for a given file path from the telegram API | |
function getFileData(filePath) { | |
var token = TELEGRAM_TOKEN; // Replace with your bot token | |
var url = "https://api.telegram.org/file/bot" + token + "/" + filePath; | |
var response = UrlFetchApp.fetch(url); | |
return response.getBlob(); | |
} | |
// This function converts an array of telegram messages to an html string and sends it as an email | |
function messagesToHtmlEmail(messages, date) { | |
var html = ""; | |
// Create an html document with some style | |
html += "<!DOCTYPE html>"; | |
html += "<html>"; | |
html += "<head>"; | |
html += "<style>"; | |
html += ".message { border: 1px solid black; margin: 10px; padding: 10px; }"; | |
html += ".name { font-weight: bold; }"; | |
html += ".time { font-style: italic; }"; | |
html += ".{ font-style: italic; color: gray; font-size:smaller; }"; | |
html += ".photo { text-align: center; margin-bottom: 20px; }"; | |
html += ".photo img { max-width: 500px; max-height: 500px; }"; | |
html += ".preformatted details { font-size: xx-small; font-family: monospace; display:none; }"; | |
html += "</style>"; | |
html += "</head>"; | |
html += "<body>"; | |
// Create a set to store unique chat IDs, user IDs, channel usernames, and group titles | |
var chats = new Set(); | |
var users = new Set(); | |
var channels = new Set(); | |
var groups = new Set(); | |
// Loop through the messages to populate the sets | |
for (var i = 0; i < messages.length; i++) { | |
var message = messages[i]; | |
if (message.chat) { | |
chats.add(message.chat.id); | |
if (message.chat.type === "channel") { | |
channels.add(message.chat.username); | |
} else if (message.chat.type === "group" || message.chat.type === "supergroup") { | |
groups.add(message.chat.title); | |
} | |
} | |
if (message.from) { | |
users.add(message.from.id); | |
} | |
} | |
// Add the list of included chats, users, channels, and groups to the message intro | |
html += "<div class='intro'>"; | |
html += "<p>Number of messages: " + messages.length + "</p>"; | |
html += "<p>Included chats: " + Array.from(chats).join(", ") + "</p>"; | |
html += "<p>Included users: " + Array.from(users).join(", ") + "</p>"; | |
html += "<p>Included channels: " + Array.from(channels).join(", ") + "</p>"; | |
html += "<p>Included groups: " + Array.from(groups).join(", ") + "</p>"; | |
html += "</div>"; | |
// Specify the email options | |
var options = { | |
to: YOUR_EMAIL, // Replace with the email address of the recipient | |
subject: "Telegram messages [" + date + "]", // Replace with the email subject | |
htmlBody: "", | |
attachments: [], | |
inlineImages: {} | |
}; | |
// Loop through the messages and convert them to html | |
for (var i = 0; i < messages.length; i++) { | |
var message = messages[i]; | |
var messageHtml = messageToHtml(message); | |
html += "<!--MESSAGE-->"; | |
html += messageHtml; | |
// If the message has any media, add them as attachments | |
if (message.photo) { | |
// Get the largest photo size available | |
var photo = message.photo.pop(); | |
// Get the file id and the file path from the telegram API | |
var fileId = photo.file_id; | |
var filePath = getFilePath(fileId); | |
// Get the file data as a blob | |
var fileData = getFileData(filePath); | |
// Add the blob to the attachments array | |
options.attachments.push(fileData); | |
// Embed images to the messages inline | |
var inlineImage = { | |
fileName: photo.file_id, | |
content: fileData, | |
mimeType: fileData.getContentType(), // Get the actual mime type of your image | |
contentId: photo.file_id // This will be used to reference the image in the html body | |
}; | |
options.inlineImages[photo.file_id] = fileData; | |
html += "<div class='photo'><img src='cid:" + photo.file_id + "' /></div>"; | |
Logger.log('Attached image: ' + photo.file_id); | |
} | |
// If the message has audio, add it as an attachment | |
if (message.audio) { | |
var fileData = getFileData(getFilePath(message.audio.file_id)); | |
options.attachments.push(fileData); | |
} | |
// If the message has a document, add it as an attachment | |
if (message.document) { | |
var fileData = getFileData(getFilePath(message.document.file_id)); | |
options.attachments.push(fileData); | |
} | |
// If the message has a video, add it as an attachment | |
if (message.video) { | |
var fileData = getFileData(getFilePath(message.video.file_id)); | |
options.attachments.push(fileData); | |
} | |
// If the message has a sticker, add it as an attachment | |
if (message.sticker) { | |
var fileData = getFileData(getFilePath(message.sticker.file_id)); | |
options.attachments.push(fileData); | |
} | |
// If the message has contact information, add it as a text attachment | |
if (message.contact) { | |
var contactInfo = "Name: " + message.contact.first_name + "\n"; | |
contactInfo += "Phone number: " + message.contact.phone_number + "\n"; | |
if (message.contact.last_name) contactInfo += "Last name: " + message.contact.last_name + "\n"; | |
if (message.contact.vcard) contactInfo += "vCard: " + message.contact.vcard + "\n"; | |
options.attachments.push(Utilities.newBlob(contactInfo, "text/plain", "contact.txt")); | |
} | |
} | |
// Close the html document | |
html += "</body>"; | |
html += "</html>"; | |
// Create the message | |
options.htmlBody = html; | |
// Search for the sent email | |
var threads = GmailApp.search('subject:("' + options.subject + '")'); | |
Logger.log('Sending email...'); | |
// Create the message chain | |
if (threads.length > 0) { | |
// Send the next email | |
threads[0].reply(removeHtmlTags(options.htmlBody), options); | |
} | |
else { | |
// Send the first email | |
GmailApp.sendEmail(options.to, options.subject, removeHtmlTags(options.htmlBody), options); | |
// Wait for a while to ensure the email has been sent | |
Utilities.sleep(5000); | |
} | |
} | |
// This function gets the updates from the telegram API and converts them to an html email | |
function getUpdates() { | |
var token = TELEGRAM_TOKEN; // Replace with your bot token | |
var lastUpdateId = PropertiesService.getScriptProperties().getProperty('LAST_UPDATE_ID'); | |
var url = "https://api.telegram.org/bot" + token + "/getUpdates?offset=" + (parseInt(lastUpdateId) + 1); | |
var response = UrlFetchApp.fetch(url); | |
var data = JSON.parse(response.getContentText()); | |
// Check if there are any new updates | |
if (data.result.length > 0) { | |
var messages = data.result.map(function (update) { | |
// Check if the update contains a message object | |
if (update.message) { | |
// Send a reply | |
var replyUrl = "https://api.telegram.org/bot" + token + "/sendMessage?chat_id=" + update.message.chat.id + "&text=" + encodeURIComponent("✅") + "&reply_to_message_id=" + update.message.message_id; | |
UrlFetchApp.fetch(replyUrl); | |
return update.message; | |
} | |
else if (update.channel_post) { | |
return update.channel_post; | |
} | |
}).filter(Boolean); // Filter out undefined values | |
if (messages.length > 0) { | |
// Get the current date and time | |
var date = new Date(); | |
// Get the year, month, and day | |
var year = date.getFullYear(); | |
var month = date.getMonth() + 1; // getMonth returns a zero-based value (where 0 indicates the first month) | |
var day = date.getDate(); | |
// Format the date as YYYY-MM-DD | |
var formattedDate = year + '-' + String(month).padStart(2, '0') + '-' + String(day).padStart(2, '0'); | |
messagesToHtmlEmail(messages, formattedDate); | |
} | |
// Save the update_id of the last processed update | |
var newLastUpdateId = data.result[data.result.length - 1].update_id; | |
PropertiesService.getScriptProperties().setProperty('LAST_UPDATE_ID', '' + newLastUpdateId); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment