(GAS-18) Bot Telegram dan GMail
Ingin membaca email (gmail) di Telegram? Yuk, kita bikin sendiri botnya!
Pendahuluan
Bacalah pendahuluan biar mengerti filosofi setiap tulisan dibuat :-D
Latar Belakang
Sudah ada @GmailBot buat apa membuat lagi?
Script cek email basicnya sudah aku buat jauh hari sebelum ada Gmail dilaunching. Namun, masih terbilang sederhana dan alakadarnya (saat itu fitur keyboard inline belum ada). Kemunculan Gmail bot, membuat pengecek emailku enggak “dipakai” lagi.
Dalam beberapa waktu ada dimana @GmailBot mengalami kemacetan alias engga bisa dipakai, script ini menjadi penting. Bahkan bisa berjalan bersamaan.
Selain itu, terkadang ada kebutuhan khusus yang tidak tersedia. Jadi dibutuhkan penanganan khusus atau fungsi yang custom. Misalnya handling notifikasi yang masuk ke email terkait notif atau warning ketika sistem monitoring masuk. Atau pembuatan push email bersama 1 devisi untuk dilihat rame-rame.
Maka, basic bot cek email (lihat, baca, operasi hapus, penanda, dll) masih sangat diperlukan. Dan tidak ada salahnya untuk mengshare versi “replika” atau mempelajari, bagaimana sebuah bot cek email bekerja, bukan?
Basic source code lama sudah banyak di modif, agar layak menjadi satu bot utuh dan berdiri sendiri. Serta ditambahkan fitur interkatif. Maka, materi kali ini sangat baik untuk dijadikan pengayaan dan menjadi percontohan terhadap banyak kasus dan proyek.
Ruang Lingkup
Tulisan ini akan membahas pembuatan bot untuk melakukan pengecekan email pada akun GMail. Operasi yang dapat dilakukan adalah:
- pengecekkan berkala email
- pengecekan manual
- operasi baca ringkas dan penuh
- operasi hapus email
Preview
ada email baru
cek manual
Bot juga per 10 menit melakukan pengecekkan otomatis.
Tingkat Kesulitan
Pada materi-materi sebelumnya, level kesulitan yang ada barangkali masih tergolong minimalis. Kali ini kita padukan sedikit banyak pengetahuan yang sudah-sudah ada. Kesulitan yang dihadapi relatif lebih sulit dibanding sebelumnya.
Penggabungan rangkaian fitur bot :
- Fungsi Trigger / Pemicu
- Keyboard Inline
- Edit Pesan
- Pengetahuan API Google Apps Scripts dan Telegram
- Pemahaman tentang istilah thread (1 bundel yang berisi rangkaian beberapa pesan)
- Peningkatan versi Library Telegram, tentang Utils dan Button
- Proteksi / limitasi pengakses
Sehingga, artikel yang ini akan menjadi lebih sulit dan kompleks.
Selain itu juga, tidak semua hal akan saya komentari lagi. Agar tidak berulang-ulang, dan hanya komentar untuk hal-hal penting saja ya.
Code
Tulisan ini diberi kode Materi 18
.
Ada beberapa step dan beberapa file script yang harus dibuat. Mari ikuti satu per satu.
I. Source Code
Struktur File
Kita akan membuat 4 buat file script.
Code.gs
ini file default, atau main file botgmail.gs
ini file fungsi-fungsi untuk gmailpemicu.gs
ini file untuk pemicu (pengecekan email terjadwal)sekaliJalan.js
untuk script yang dijalankan hanya 1x saja
Kira-kira seperti ini strukturnya:
Karena ini termasuk bot yang source nya agak panjang.
Semoga ada gambarnyan sebelum memulainya.
I.1. Library
Seperti biasa, masukkan Library Telegram nya. Gunakan versi paling besar angkanya. Saat ditulis, sudah versi 23
.
Menu: Sumber Daya
-> Pustaka
ID Lib: MHczUHrzvBLV1HsUn5XkOIfvg_do21SJR
Kalau belum tahu caranya menambah library, bisa lihat di dokumentasi atau materi sebelumnya.
I.2. Code
Pada halaman utama, atau sebagai engine utama bot. Yakni Kode.gs
atau Code.gs
tulis (copas) bot seperti biasanya. Tidak banyak perubahan, kecuali pada event cek /email
atau handle callback data
untuk keyboard inline.
Yang paling penting dalam pelajaran tulisan ini adalah, bagaimana mengedit sebuah pesan dan juga button inline.
// masukkan token bot mu
var token = 'TOKEN_BOT_KAMU';
// buat objek baru kita kasih nama tg
var tg = new telegram.daftar(token);
// buat variable untuk Button dan Utils
Utils = telegram.Utils;
Button = telegram.Button;
// target chat id, boleh ID user/group/channel
// karena isi email termasuk kredensial, maka perlu kita definisikan
var chat_id = 213567634; // ini ID saya, silakan diganti!
// label untuk penanda
var gLabel= 'tg'; // contoh disini pakai label tg untuk Telegram
// panjang Char per pesan default
var panjangChar = 500; // agar pertama dibaca tidak terlalu panjang
// --- codingan seperti biasa --
// fungsi buat handle hanya menerima pesan berupa POST, kalau GET keluarkan pesan error
function doGet(e) {
return HtmlService.createHtmlOutput("Hanya data POST yang kita proses yak!");
}
// fungsi buat handle pesan POST
function doPost(e) {
// Memastikan pesan yang diterima hanya dalam format JSON
if(e.postData.type == "application/json") {
// Kita parsing data yang masuk
var update = JSON.parse(e.postData.contents);
// Jika data pesan update valid, kita proses
if (update) {
prosesPesan(update);
}
}
}
// fungsi utama kita buat handle segala pesan
function prosesPesan(update) {
// detek klo ada pesan dari user
if (update.message) {
// penyederhanaan variable
var msg = update.message;
// jika ada pesan berupa text
if (msg.text) {
// jika user ketik /ping, bot akan jawab Pong!
if ( /\/ping/i.exec(msg.text) ){
return tg.kirimPesan(msg.chat.id, '<b>Pong!</b>', 'HTML');
}
// cek manual email
if ( /\/email/i.exec(msg.text) ){
// kita batasi yang boleh mengakses ini hanya user tertentu
// cuekin aja orangnya, ga usah dikasih pesan error apa-apa.
if (msg.chat.id !== chat_id) return;
// panggil fungsi pemicuEmail, cek nanti di bagian Pemicu
var adaEmail = pemiculEmail();
if (!adaEmail) {
return tg.kirimPesan(msg.chat.id, '✅ Email sudah terbaca semua.');
} else {
return;
}
}
// akhir deteksi pesan text
}
}
// proses buat handle callback
if (update.callback_query) {
// penyederhanaan variable
var cb = update.callback_query;
var msg = cb.message;
// deteksi jika ada cb (callback) data untuk menciutkan
var pola = /^ciutkan_(\w+)/i;
if ( pola.exec(cb.data) ){
var cocok = cb.data.match(pola);
var gID = cocok[1];
// ambil pesan Gmail berdasarkan ID nya
var pesan = gmail.getMessage(gID);
// susun format data buat dikirim
var data = {
chat_id: msg.chat.id,
message_id: msg.message_id,
text: pesan,
parse_mode: 'HTML',
reply_markup: msg.reply_markup
};
// ganti tombol dan isi callback data nya
data.reply_markup.inline_keyboard[1][0].text = "📖 Baca Lebih";
data.reply_markup.inline_keyboard[1][0].callback_data = 'readMore_'+gID;
// edit pesan
return tg.request('editMessageText',data);
}
// deteksi jika ada cb (callback) data untuk membaca lebih panjang
var pola = /^readMore_(\w+)/i;
if ( pola.exec(cb.data) ){
var cocok = cb.data.match(pola);
var gID = cocok[1];
// ambil pesan Gmail berdasarkan ID nya
var pesan = gmail.getMessage(gID, true);
// susun format data buat dikirim
var data = {
chat_id: msg.chat.id,
message_id: msg.message_id,
text: pesan,
parse_mode: 'HTML',
reply_markup: msg.reply_markup
};
// ganti tombol dan isi callback data nya
data.reply_markup.inline_keyboard[1][0].text = "🗞 Ciutkan";
data.reply_markup.inline_keyboard[1][0].callback_data = "ciutkan_"+gID;
return tg.request('editMessageText',data);
// tg.kirimPesan(msg.chat.id, pesan);
}
var pola = /^markRead_(\w+)/i;
if ( pola.exec(cb.data) ){
var cocok = cb.data.match(pola);
var gID = cocok[1];
// susun format data buat dikirim
var data = {
chat_id: msg.chat.id,
message_id: msg.message_id,
text: msg.text,
reply_markup: msg.reply_markup
};
// ganti tombol dan isi callback data nya
data.reply_markup.inline_keyboard[0][0].text = "✅ Terbaca";
data.reply_markup.inline_keyboard[0][0].callback_data = "markUnread_"+gID;
// tandai email Terbaca
gmail.markRead(gID);
// edit pesan dan tombolnya
tg.request('editMessageText',data);
// kasih notif sudah dikerjakan
return tg.request('answerCallbackQuery', { callback_query_id: cb.id, text: "✅ Pesan telah ditandai terbaca." });
}
var pola = /^markUnread_(\w+)/i;
if ( pola.exec(cb.data) ){
var cocok = cb.data.match(pola);
var gID = cocok[1];
// susun format data buat dikirim
var data = {
chat_id: msg.chat.id,
message_id: msg.message_id,
text: msg.text,
reply_markup: msg.reply_markup
};
// ganti tombol dan isi callback data nya
data.reply_markup.inline_keyboard[0][0].text = "☑️ Baca";
data.reply_markup.inline_keyboard[0][0].callback_data = "markRead_"+gID;
// tandai email BELUM dibaca
gmail.markUnread(gID);
// edit pesan dan tombolnya
tg.request('editMessageText',data);
// kasih notif sudah dikerjakan
return tg.request('answerCallbackQuery', { callback_query_id: cb.id, text: "☑️ Tandai BELUM dibaca." });
}
var pola = /^moveToTrash_(\w+)/i;
if ( pola.exec(cb.data) ){
var cocok = cb.data.match(pola);
var gID = cocok[1];
// tambahkan pesan dibawahnya, buat tanda kalau sudah dihapus di GMAIL
var pesan = gmail.getMessage(gID) + "\n\n<code>(DI GMAIL: PESAN INI TELAH DIHAPUS)</code>";
// susun format data buat dikirim
var data = {
chat_id: msg.chat.id,
message_id: msg.message_id,
text: pesan,
parse_mode: 'HTML'
}
// hapus emailnya
gmail.moveToTrash(gID);
// edit pesan dan tombolnya
tg.request('editMessageText',data);
// kasih notif sudah dikerjakan
return tg.request('answerCallbackQuery', { callback_query_id: cb.id, text:'🗑 Pesan Telah DIHAPUS.' });
}
}
}
I.3. Fungsi Gmail
Buat sebuah file script baru (File
-> Baru
-> File Skrip
) kemudian kita isikan sebuah variable yang menampung rangkaian fungsi gmail:
Beri nama: gmail
. Isikan source codenya seperti berikut:
// buat variable global dengan nama gmail
// untuk menampung fungsi-fungsi berkenaan dengan email
var gmail = {
getMessage: function(id, full) {
// atur panjang Pesan
// panjangChar = kita letakkan nanti di file script utama (bot/Code.gs)
var panjangPesan = panjangChar;
if (full) panjangPesan = 3500;
// ambil pesan berdasarkan ID nya
var message = GmailApp.getMessageById(id);
var gSubject = message.getSubject();
gSubject = Utils.clearHTML(gSubject);
// dapatkan pengirimnya
var gFrom = message.getFrom();
// trus kita bersihkan dari tags HTML
gFrom = Utils.clearHTML(gFrom);
// dapatkan waktunya
var gDate = message.getDate();
gDate = Utils.clearHTML( String(gDate));
// ambil isi email dalam mode text plain aja
var gMessage = message.getPlainBody();
// potong panjangnya sesuai parameter
gMessage = gMessage.substring(0, panjangPesan)
// bersihkan dari tag HTML
gMessage = Utils.clearHTML(gMessage);
// susun pesannya
var pesan = ' ✉ ' + gFrom + "\n📝 <b>" + gSubject + "</b>\n";
pesan += '⏱ <code>' + gDate + '</code>';
pesan += "\n\n"+gMessage;
// jika pesan kepotong, kasih informasi
if (gMessage.length > panjangPesan) pesan += "...\n(dipotong)";
// jika pesan ada attach nya, kasih informasi
var gAttach = message.getAttachments().length;
if (gAttach>0) pesan += "\n\n🗂 Lampiran: <code>"+gAttach+ "</code> buah.";
// kembalikan fungsi dengan pesan yang disusun
return pesan;
},
// fungsi untuk menandai Read
markRead : function (id) {
var message = GmailApp.getMessageById(id);
return message.markRead();
},
// fungsi untuk menandai unRead
markUnread : function (id) {
var message = GmailApp.getMessageById(id);
return message.markUnread();
},
// fungsi untuk mengambil isi email berupa text plain
getPlainBody : function (id) {
var message = GmailApp.getMessageById(id);
return message.getPlainBody();
},
// fungsi untuk membuang email ke tong sampah
moveToTrash : function (id) {
var message = GmailApp.getMessageById(id);
return message.moveToTrash();
},
// fungsi untuk membuat label
createLabel : function (label) {
return GmailApp.createLabel(label);
},
// fungsi untuk menghapus label
deleteLabel: function (label) {
var labelID = GmailApp.getUserLabelByName(label);
return GmailApp.deleteLabel(labelID);
}
}
I.4. Pemicu / Trigger
Sama seperti diatas, buat file script baru dengan nama pemicu
.
Kemudian masukkan script ini:
// fungsi buat pemicu email unread
function pemiculEmail() {
// ambil dulu label yang tersedia
var label = GmailApp.getUserLabelByName(gLabel);
// buat threads untuk mengambil pesan yang belum dibaca dan tidak ditandai label
// ambil satu batch 10 buah aja
var threads = GmailApp.search('label:unread NOT label:'+gLabel, 0, 10);
// jika tidak ada pesannya, udah pulang aja ga usah dilanjutkan
if (threads.length<1) return false;
// ambil semua pesannya
for (var i = 0; i < threads.length; i++) {
// dapatkan pesannya, ambil yang paling atas (terbaru) = index ke-0
var message = threads[i].getMessages()[0];
// dapatkan pengirimnya
var gFrom = message.getFrom();
// trus kita bersihkan dari tags HTML
gFrom = Utils.clearHTML(gFrom);
// dapatkan waktunya
var gDate = message.getDate();
gDate = Utils.clearHTML( String(gDate));
// dapatkan subject email
// karena bisa jadi ada perubahan saat reply, ambil yang paling atas aja lah ya
var gSubject = threads[i].getFirstMessageSubject();
gSubject = Utils.clearHTML(gSubject);
// dapatkan ID message nya
var gID = message.getId();
// dapatkan isi pesannya
// ambil yang text plain aja ya, bukan HTML. Biar ga ribet ngolahnya
// klo mau diolah silakan di modifikasi sendiri
var gMessage = message.getPlainBody();
gMessage = Utils.clearHTML(gMessage);
// untuk ISI nya attachment, ga dibahas dulu
// silakan modif sendiri hehe
// tampilkan ada gak nya duank aja ya
var gAttach = message.getAttachments().length;
// oke itu aja, yuk kita susun pesannya
var pesan = ' ✉ ' + gFrom + "\n📝 <b>" + gSubject + "</b>\n";
pesan += '⏱ <code>' + gDate + '</code>';
// isi email kita potong klo lebih dari panjangChar
pesan += "\n\n" + gMessage.substring(0, panjangChar)
// sesudah ditampakkin, tandai label nya
// biar ga kebaca ulang
threads[i].addLabel(label);
// kirim pesannya ke Telegram
// tg.kirimPesan(chat_id, pesan, 'HTML', true);
// kirim pesan dengan menu (keyboard inline)
var keyboard = [];
//buat barisan (row) keyboard
// 1 baris diisi 2 button
var kBaris = [
Button.inline('☑️ Baca','markRead_'+gID),
Button.inline('🗑 Hapus','moveToTrash_'+gID)
];
// masukkan baris ke keyboard
keyboard.push(kBaris);
// kalau pesan puanjang, tambahkan tombol baca lebih
if (gMessage.length > panjangChar) {
pesan += "... (dipotong)";
// 1 baris 1 button saja
kBaris = [
Button.inline('📖 Baca Lebih','readMore_'+gID)
];
keyboard.push(kBaris);
// dari sini ada pelajaran baru? membuat button di keyboard per baris ya
}
// informasi ada lampiran
if (gAttach>0) pesan += "\n\n🗂 Lampiran: <code>"+gAttach+ "</code> buah.";
// semua pesan sudah oke? baru dikirim
tg.sendMsgKeyboardInline(chat_id, pesan, keyboard);
// sebelum mengulang ke thread berikutnya, kasih sedikit jeda biar ga flooding
// 1 detik saja cukup
Utilities.sleep(1000);
}
// hasil kasih true (sukses)
return true;
}
Silakan di deploy 3 script + library di atas. Dan dapatkan web App URL nya untuk dipasangkan di webhook.
Kalau lupa cara deploy, silakan baca materi sebelumnya.
II. Sekali Jalan
Buat sekali lagi file script baru, misal namanya sekaliJalan
. Karena script ini memang hanya sekali saja dijalankan.
II.1 setWebhook
function setWebhook() {
// ubah web_app_URL yang di dapat saat Deploy
var url = 'web_app_URL';
return tg.setWebhook(url);
}
Simpan dan kemudian jalankan.
II.2 Buat Label
Fungsi ini buat bikin label penanda.
Ingat, jalankan sekali saja.
function buatLabel() {
return gmail.createLabel(gLabel);
}
Silakan di cek di akun gmailnya, seharusnya ada label baru bernama tg
seperti dibawah ini:
Test Run
Sampai di sini, bot sudah bisa berjalan dengan pemicu manual. Yakni di dalam bot ketik /email
maka akan menampilkan email yang belum terbaca.
III. Pemicu
Klik tombol pemicu yang berbentuk seperti icon jam.
Kemudian klik tombol Tambahkan Pemicu
untuk membuat pemicu (trigger) baru.
Keterangan gambar: perhatikan baik-baik yang dikotaki merah
Atur pada form pemicu menjadi seperti ini:
- Pilih fungsi yang dijalankan:
pemicuEmail
- Pilih penerapan mana yang harus dijalankan:
Head
(biarkan saja) - Pilih sumber acara:
Dipicu oleh waktu
- Pilih jenis pemicu berdasarkan waktu:
timer menit
(bisa diubah perjam, jika ingin mengecek lebih jarang) - Pilih interval meni:
Setiap 10 menit
(bisa diubah lebih cepat atau lebih lama. Saran tidak terlalu cepat)
Kemudian klik tombol Simpan.
Dengan demikian, email akan dicek otomatis per 10 menit oleh bot. Jika ada yang baru, akan dikirimkan ke kita.
FYI. Jangan menyeting timer (pemicu) nya per (1) menit sekali. Dikhawatirkan jatah quota API kita habis dan atau keburu timeout dan bisa juga bertumpuk.
SELESAI!
Youtube
Akan diupdate jika sudah ada video nya.
Penutup
Jika ada pertanyaan, saran atau masukkan silakan didiskusikan. Jika ingin live dan biasanya tanggapan juga lebih cepat, sangat disarankan bergabung pada group Telegram @botIndonesia.