Skip to content

Instantly share code, notes, and snippets.

@SmartFinn
Last active February 24, 2025 16:33
Show Gist options
  • Save SmartFinn/150e732a555fac64d76782a2f3ad3ebb to your computer and use it in GitHub Desktop.
Save SmartFinn/150e732a555fac64d76782a2f3ad3ebb to your computer and use it in GitHub Desktop.
Forward email marked with custom label to Telegram #google-script #gas
/**
Forward email marked with custom label to Telegram.
Sergei Eremenko (https://github.com/SmartFinn) © 2020
**/
// Custom trigger to run script every 1 min
function startCustomTrigger() {
ScriptApp.newTrigger('checkInbox').timeBased().everyMinutes(1).create()
}
// Global Variables
const userProperties = PropertiesService.getUserProperties();
const scriptProperties = PropertiesService.getScriptProperties();
const telegramToken = scriptProperties.getProperty('telegramToken')
const telegramChatId = scriptProperties.getProperty('telegramChatId')
String.prototype.escapeSpecialChars = function() {
return this.replace(/&/g, '\&')
.replace(/</g, '\&lt;')
.replace(/>/g, '\&gt;');
};
Number.prototype.humanReadableFileSize = function() {
let size = this;
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'];
for (let i = 0; i < units.length; i++) {
if (size >= 1024) { size /= 1024; } else {
return `${size.toFixed(i > 2 ? 2 : i)} ${units[i]}`;
}
}
return this + ' B'; // in case the size is too big
};
String.prototype.truncateText = function(max = 2000, ending = ' …\n') {
return this.length > max ? this.substr(0, max - ending.length) + ending : this
}
// const escapeSpecialChars = text => text.replace(/&/g, '\&amp;')
// .replace(/</g, '\&lt;')
// .replace(/>/g, '\&gt;')
// const humanReadableFileSize = (size, divider = 1024, units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB']) => {
// for (let i = 0; i < units.length; i++) {
// if (size >= divider) { size /= divider; } else {
// return `${size.toFixed(i > 2 ? 2 : i)} ${units[i]}`;
// }
// }
//
// return `${size} ${units[0]}`; // in case the size is too big
// };
// const truncateText = (text, max = 2000, ending = ' …\n') => text.length > max ? text.substr(0, max - ending.length) + ending : text;
function telegramApiRequest(method, data) {
const options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
const response = UrlFetchApp.fetch(`https://api.telegram.org/bot${telegramToken}/${method}`, options);
if (response.getResponseCode() == 200) {
return JSON.parse(response.getContentText());
}
return false;
}
function telegramSendMessage(chat_id, text, opts = {}) {
return telegramApiRequest('sendMessage', {chat_id, text, ...opts});
}
function checkInbox() {
Logger.log("Script running ...");
// Grab gmail inbox
const labelNew = GmailApp.getUserLabelByName('Telegram/New');
const labelDone = GmailApp.getUserLabelByName('Telegram');
const seenMessages = userProperties.getProperty('SEEN_MESSAGES') != null
? userProperties.getProperty('SEEN_MESSAGES').split(',')
: []; // get ids of messages that already sent
for (let thread of labelNew.getThreads()) {
const threadLink = thread.getPermalink();
for (let msg of thread.getMessages()) {
const msgId = msg.getId();
if (seenMessages.includes(msgId)) {
Logger.log(`Skip message with ${msgId} id.`);
continue;
} else {
seenMessages.push(msgId);
}
const formattedDate = Utilities.formatDate(msg.getDate(), Session.getScriptTimeZone(), "dd MMM yyyy' at 'HH:mm:ss");
const msgAttachments = msg.getAttachments().map(att => `📎 ${att.getName()} (${att.getSize().humanReadableFileSize()})`)
// Message template
const msgHtml =
`📧 <b>${msg.getSubject().escapeSpecialChars()}</b>
<i>From: ${msg.getFrom().escapeSpecialChars()}</i>
<i>Date: ${formattedDate}</i>
${msg.getPlainBody().escapeSpecialChars().truncateText()}
${msgAttachments.join('\n')}
<a href="${threadLink}">Show original</a>`
// End of the message template
Logger.log(msgHtml);
telegramSendMessage(telegramChatId, msgHtml, {'parse_mode': 'HTML', 'disable_web_page_preview': true});
}
userProperties.setProperty('SEEN_MESSAGES', seenMessages.join(',')); // save ids of sent messages
labelNew.removeFromThread(thread); // Remove the label from the thread
labelDone.addToThread(thread); // Set label to thread
GmailApp.markThreadRead(thread);
}
Logger.log("Script finished.");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment