#GoogleWorkspace #AppsScript
#GoogleWorkspace #AppsScript
ScriptApp.newTrigger("daily").timeBased().atHour(9).everyDays(1).create();
So never derive "yesterday" from when the trigger ran. Filter on the timestamp in the row.
#AppsScript
ScriptApp.newTrigger("daily").timeBased().atHour(9).everyDays(1).create();
So never derive "yesterday" from when the trigger ran. Filter on the timestamp in the row.
#AppsScript
Google Apps Script, weekly trigger:
const ev = CalendarApp.getEvents(mon, sun);
if (!ev.length) return;
sh.getRange(2,1,ev.length,2).setValues(ev.map(e=>[e.getStartTime(),e.getTitle()]));
A quiet week is 0 rows, and setValues throws. #AppsScript
Google Apps Script, weekly trigger:
const ev = CalendarApp.getEvents(mon, sun);
if (!ev.length) return;
sh.getRange(2,1,ev.length,2).setValues(ev.map(e=>[e.getStartTime(),e.getTitle()]));
A quiet week is 0 rows, and setValues throws. #AppsScript
sheet.appendRow(row) is atomic — the one write that cannot lose that race.
If you must setValues(), take a LockService lock first. #AppsScript
sheet.appendRow(row) is atomic — the one write that cannot lose that race.
If you must setValues(), take a LockService lock first. #AppsScript
Need an edit-trigger that sends mail or hits an API? Make it an INSTALLABLE onEdit (Triggers → Add) — same function, full scopes. #AppsScript
Need an edit-trigger that sends mail or hits an API? Make it an INSTALLABLE onEdit (Triggers → Add) — same function, full scopes. #AppsScript
Google Apps Script, once:
GmailApp.search("label:invoices filename:pdf newer_than:7d")
.flatMap(t=>t.getMessages())
.forEach(m=>m.getAttachments()
.forEach(a=>folder.createFile(a)));
Trigger it, done. #AppsScript
Google Apps Script, once:
GmailApp.search("label:invoices filename:pdf newer_than:7d")
.flatMap(t=>t.getMessages())
.forEach(m=>m.getAttachments()
.forEach(a=>folder.createFile(a)));
Trigger it, done. #AppsScript
const sh = SpreadsheetApp.getActive().getActiveSheet();
sh.getDataRange().getValues().forEach((r, i) => {
if (r[2] > 1000) sh.getRange(i+1, 1, 1, r.length).setBackground("#fde68a");
});
One pass, every matching row flagged. #AppsScript
const sh = SpreadsheetApp.getActive().getActiveSheet();
sh.getDataRange().getValues().forEach((r, i) => {
if (r[2] > 1000) sh.getRange(i+1, 1, 1, r.length).setBackground("#fde68a");
});
One pass, every matching row flagged. #AppsScript
const files = DriveApp.getFolderById(ID).getFiles();
while (files.hasNext()) {
const f = files.next();
f.setName(f.getName().replace(/ /g, "_"));
}
Whole folder normalized in one run. #AppsScript
const files = DriveApp.getFolderById(ID).getFiles();
while (files.hasNext()) {
const f = files.next();
f.setName(f.getName().replace(/ /g, "_"));
}
Whole folder normalized in one run. #AppsScript
clearContent() actually removes it. Or filter blanks from getValues() before trusting the length.
#AppsScript
clearContent() actually removes it. Or filter blanks from getValues() before trusting the length.
#AppsScript
onEdit(e): if the edited cell is the Status column and e.value == 'Done', appendRow() it to Archive, then deleteRow() from the source.
~8 lines. Pinning down the spec sentence was harder than the code. #AppsScript #GoogleSheets
onEdit(e): if the edited cell is the Status column and e.value == 'Done', appendRow() it to Archive, then deleteRow() from the source.
~8 lines. Pinning down the spec sentence was harder than the code. #AppsScript #GoogleSheets
function archiveOld() {
GmailApp.search("older_than:1y -is:starred")
.forEach(t => t.moveToArchive());
}
One sentence in, four lines out. Put it on a daily trigger and the inbox count stops climbing. #AppsScript #Gmail
function archiveOld() {
GmailApp.search("older_than:1y -is:starred")
.forEach(t => t.moveToArchive());
}
One sentence in, four lines out. Put it on a daily trigger and the inbox count stops climbing. #AppsScript #Gmail
GmailApp.search("in:inbox older_than:30d")
.forEach(t => t.moveToArchive());
Put it on a daily time-driven trigger and the inbox stops being a graveyard. The search operator does the filtering — no date math, no loop. #AppsScript
GmailApp.search("in:inbox older_than:30d")
.forEach(t => t.moveToArchive());
Put it on a daily time-driven trigger and the inbox stops being a graveyard. The search operator does the filtering — no date math, no loop. #AppsScript
Most people don't know you can automate this in under 5 minutes.
Here's the approach:
1. Set up the base script
2. Configure your triggers
3. Let it run forever
Full free script in thread 👇
#appsScript #automation #free #devto
Most people don't know you can automate this in under 5 minutes.
Here's the approach:
1. Set up the base script
2. Configure your triggers
3. Let it run forever
Full free script in thread 👇
#appsScript #automation #free #devto
Most people don't know you can automate this in under 5 minutes.
Here's the approach:
1. Set up the base script
2. Configure your triggers
3. Let it run forever
Full free script in thread 👇
#appsScript #automation #free #devtools
Most people don't know you can automate this in under 5 minutes.
Here's the approach:
1. Set up the base script
2. Configure your triggers
3. Let it run forever
Full free script in thread 👇
#appsScript #automation #free #devtools
const label = GmailApp.getUserLabelByName('Follow-up');
GmailApp.search('is:unread older_than:3d')
.forEach(t => t.addLabel(label));
A daily time-trigger and you're done — the Gmail search bar does the filtering. #AppsScript
const label = GmailApp.getUserLabelByName('Follow-up');
GmailApp.search('is:unread older_than:3d')
.forEach(t => t.addLabel(label));
A daily time-trigger and you're done — the Gmail search bar does the filtering. #AppsScript
Pass the sheet's zone explicitly:
Utilities.formatDate(d, ss.getSpreadsheetTimeZone(), 'yyyy-MM-dd')
Same trap hits Logger timestamps. #AppsScript
Pass the sheet's zone explicitly:
Utilities.formatDate(d, ss.getSpreadsheetTimeZone(), 'yyyy-MM-dd')
Same trap hits Logger timestamps. #AppsScript