Skip to content

Instantly share code, notes, and snippets.

@NickCis
Last active August 7, 2025 15:56
Show Gist options
  • Save NickCis/57f809b9c7f0bee35237b63798edbe6b to your computer and use it in GitHub Desktop.
Save NickCis/57f809b9c7f0bee35237b63798edbe6b to your computer and use it in GitHub Desktop.
Calendar Events: creating calendar events from gmail notifications e-mails.

Calendar Google APP script

La idea de este script es crear eventos del calendario como recordatorios para pagar servicios.

Necesita crear reglas en GMail para que le agregue la etiqueta calendar-event a los mails de notificaciones. El script le removerá dicha etiqueta a los mails que ya procesó.

const LabelPending = 'calendar-event';
const emailRe = /(^|<)(([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5}))(>|$)/;
function osde(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getPlainBody();
const match = body.match(/Vencimiento.*?(\d{2})\/(\d{2})\/(\d{4})/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year] = match;
return CalendarApp.createAllDayEvent(
`OSDE: vencimiento`,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
function mastercard(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getPlainBody();
const match = body.match(/Vence\s*el.*?(\d{2}).(\d{2}).(\d{4})/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year] = match;
return CalendarApp.createAllDayEvent(
`Mastercard: vencimiento`,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
function reba(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getBody();
const match = body.match(/Fecha\s*de\s*vencimiento:.*?(\d{2}).(\d{2}).(\d{2})/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year] = match;
return CalendarApp.createAllDayEvent(
`Reba: vencimiento`,
new Date(parseInt(year, 10) + 2000, parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
function wilo(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getBody();
// y vence el 12/09.
let match = body.match(/y vence el (\d{2})\/(\d{2})/i);
// Fecha de vencimiento: 12-12-22
if (!match)
match = body.match(/Fecha de vencimiento: (\d{2})-(\d{2})/i);
if (match) {
const permalink = thread.getPermalink();
let [, day, month] = match;
day = parseInt(day, 10);
month = parseInt(month, 10);
return CalendarApp.createAllDayEvent(
`Wilobank: vencimiento`,
new Date((new Date()).getFullYear() + (month === 1 ? 1 : 0), month - 1, day),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
function galicia(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getBody();
// Vencimiento: 09 Sep 22
const match = body.match(/Vencimiento: (\d{2}) (\S+) (\d{2})/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, txtMonth, year] = match;
let month = -1;
const months = [
'e',
'f',
'mar',
'ab',
'may',
'jun',
'jul',
'ag',
's',
'o',
'n',
'd',
];
for (let i = 0; i < months.length; i++) {
if (txtMonth.toLowerCase().startsWith(months[i]))
month = i;
}
let title = `Galicia: vencimiento`;
const titleMatch = email.getSubject().match(/Resumen de cuenta (\S+)/i);
if (titleMatch)
title = `Galicia ${titleMatch[1]}: vencimiento`;
return CalendarApp.createAllDayEvent(
title,
new Date(parseInt(year, 10) + 2000, month, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
function santander(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getPlainBody();
// El 11/10/2022 vence tu Tarjeta Santander VISA terminada en XXXX.
// El 17/02/2022 vence tu servicio.
let match = body.match(/El \*(\d{2})\/(\d{2})\/(\d{4})\* vence tu (servicio|Tarjeta Santander \*(.*?)\* terminada en)/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year, , card] = match;
let title = 'Santander: vencimiento';
if (card) {
title = `Santander ${card.trim()}: vencimiento`;
} else {
const serviceMatch = body.match(/Empresa\s*([^\n]+)/i);
if (serviceMatch)
title = `${serviceMatch[1].trim()}: vencimiento (Santander)`;
}
return CalendarApp.createAllDayEvent(
title,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
// Débitos automáticos (AFIP)
match = body.match(/El siguiente servicio está por vencer\..*?Fecha\s+(\d{2})\/(\d{2})\/(\d{2}\d{2}?).*?Servicio\s+(.*?)\n/s);
if (match) {
const permalink = thread.getPermalink();
let [, day, month, year, service] = match;
year = parseInt(year, 10);
if (year < 2000) year = year + 2000;
const title = `Santander ${service.trim()}: vencimiento`;
return CalendarApp.createAllDayEvent(
title,
new Date(year, parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
// Vencimiento de tarjetas
match = body.match(/Tarjeta\s+\*?\s*VISA.*?Fecha de vencimiento\s+\*?\s*(\d{2})\/(\d{2})\/(\d{2}\d{2}?).*?Tarjeta\s+\*?\s*AMEX.*?Fecha de vencimiento\s+\*?\s*(\d{2})\/(\d{2})\/(\d{2}\d{2}?)/is);
if (match) {
const permalink = thread.getPermalink();
let [, visaDay, visaMonth, visaYear, amexDay, amexMonth, amexYear] = match;
visaYear = parseInt(visaYear, 10);
if (visaYear < 2000) visaYear = visaYear + 2000;
amexYear = parseInt(amexYear, 10);
if (amexYear < 2000) amexYear = amexYear + 2000;
return [
CalendarApp.createAllDayEvent(
'Santander VISA: vencimiento',
new Date(visaYear, parseInt(visaMonth, 10) - 1, parseInt(visaDay, 10)),
{ description: `Ver: ${permalink}` },
),
CalendarApp.createAllDayEvent(
'Santander AMEX: vencimiento',
new Date(amexYear, parseInt(amexMonth, 10) - 1, parseInt(amexDay, 10)),
{ description: `Ver: ${permalink}` },
)
];
}
return true;
}
function aysa(from, email, thread) {
if (from === '[email protected]') {
const body = email.getPlainBody();
// Te informamos que el día * 2024-06-26T00:00:00
const match = body.match(/Te\s+informamos\s+que\s+el\s+d.a[^0-9]+(\d{4})-(\d{2})-(\d{2})/i);
if (match) {
const permalink = thread.getPermalink();
const [, year, month, day] = match;
return CalendarApp.createAllDayEvent(
`AYSA: vencimiento`,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
} else if (from === '[email protected]') {
const body = email.getPlainBody();
// Fecha de vencimiento: 31/07/2024
const match = body.match(/Fecha\s+de\s+vencimiento:[^0-9]*(\d{2})\/(\d{2})\/(\d{4})/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year] = match;
return CalendarApp.createAllDayEvent(
`AYSA: vencimiento`,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
}
function metrogas(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getBody();
// Fecha de vencimiento: 17/07/2024
const match = body.match(/Fecha de vencimiento:\s*(\d{2})[./-](\d{2})[./-](\d{4})/i);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year] = match;
return CalendarApp.createAllDayEvent(
`MetroGAS: vencimiento`,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
function edesur(from, email, thread) {
if (from !== '[email protected]')
return;
const body = email.getPlainBody();
const match = body.match(/vencimiento el d.a\s*(\d{2})[./-](\d{2})[./-](\d{4}),.*?Direcci.n:\s+(.*?)(\n|$)/is);
if (match) {
const permalink = thread.getPermalink();
const [, day, month, year, house] = match;
return CalendarApp.createAllDayEvent(
`Edesur: vencimiento ${house.trim()}`,
new Date(parseInt(year, 10), parseInt(month, 10) - 1, parseInt(day, 10)),
{ description: `Ver: ${permalink}` },
);
}
return true;
}
const functions = [
osde,
mastercard,
reba,
wilo,
galicia,
santander,
aysa,
metrogas,
edesur,
];
function getFrom(email) {
const from = email.getFrom();
const match = from.match(emailRe);
if (match)
return match[2];
}
function castArray(v) {
return Array.isArray(v) ? v : [v];
}
function processMail(thread) {
const [email] = thread.getMessages();
const from = getFrom(email);
functions.some(process => {
const processed = process(from, email, thread);
if (!processed) return false;
const events = castArray(processed);
for (const event of events) {
if (event.addPopupReminder) {
thread.markRead();
event.addPopupReminder(12 * 60);
event.addPopupReminder(36 * 60);
}
}
return true;
});
}
function main() {
const labelPending = GmailApp.getUserLabelByName(LabelPending);
const threads = labelPending.getThreads();
for (const thread of threads) {
processMail(thread);
thread.removeLabel(labelPending);
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment