Skip to content

Instantly share code, notes, and snippets.

@tayyebi
Last active January 1, 2024 20:38
Show Gist options
  • Save tayyebi/669b0b5d0ccf407bb66d6a9325349a09 to your computer and use it in GitHub Desktop.
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 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