Skip to content

Instantly share code, notes, and snippets.

@matthewmueller
Created February 8, 2022 03:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matthewmueller/9adb3d57ea9b03c75d742e8987d3bb13 to your computer and use it in GitHub Desktop.
Save matthewmueller/9adb3d57ea9b03c75d742e8987d3bb13 to your computer and use it in GitHub Desktop.
Some Google Scripts I used to run periodically on my Gmail. Saving for posterity.
/*
* This script goes through your Gmail Inbox and finds recent emails where you
* were the last respondent. It applies a nice label to them, so you can
* see them in Priority Inbox or do something else.
*
* To remove and ignore an email thread, just remove the unrespondedLabel and
* apply the ignoreLabel.
*
* This is most effective when paired with a time-based script trigger.
*
* For installation instructions, read this blog post:
* http://jonathan-kim.com/2013/Gmail-No-Response/
*/
// Edit these to your liking.
var unrespondedLabel = 'Awaiting Response',
minTime = '5d', // 5 days
maxTime = '14d'; // 14 days
// Mapping of Gmail search time units to milliseconds.
var UNIT_MAPPING = {
h: 36e5, // Hours
d: 864e5, // Days
w: 6048e5, // Weeks
m: 263e7, // Months
y: 3156e7 // Years
};
function awaiting_response() {
processUnresponded();
cleanUp();
}
function processUnresponded() {
var threads = GmailApp.search('is:sent from:me -in:chats older_than:' + minTime + ' newer_than:' + maxTime),
threadMessages = GmailApp.getMessagesForThreads(threads),
unrespondedThreads = [],
minTimeAgo = new Date();
minTimeAgo.setTime(subtract(minTimeAgo, minTime));
Logger.log('Processing ' + threads.length + ' threads.');
// Filter threads where I was the last respondent.
threadMessages.forEach(function(messages, i) {
var thread = threads[i],
lastMessage = messages[messages.length - 1],
lastFrom = lastMessage.getFrom(),
lastTo = lastMessage.getTo(), // I don't want to hear about it when I am sender and receiver
lastMessageIsOld = lastMessage.getDate().getTime() < minTimeAgo.getTime();
if (isMe(lastFrom) && !isMe(lastTo) && lastMessageIsOld && thread.isInInbox()) {
unrespondedThreads.push(thread);
}
})
// Mark unresponded in bulk.
markUnresponded(unrespondedThreads);
Logger.log('Updated ' + unrespondedThreads.length + ' messages.');
}
function subtract(date, timeStr) {
// Takes a date object and subtracts a Gmail-style time string (e.g. '5d').
// Returns a new date object.
var re = /^([0-9]+)([a-zA-Z]+)$/,
parts = re.exec(timeStr),
val = parts && parts[1],
unit = parts && parts[2],
ms = UNIT_MAPPING[unit];
return date.getTime() - (val * ms);
}
function isMe(fromAddress) {
var addresses = getEmailAddresses();
for (i = 0; i < addresses.length; i++) {
var address = addresses[i],
r = RegExp(address, 'i');
if (r.test(fromAddress)) {
return true;
}
}
return false;
}
function getEmailAddresses() {
// Cache email addresses to cut down on API calls.
if (!this.emails) {
Logger.log('No cached email addresses. Fetching.');
var me = Session.getActiveUser().getEmail(),
emails = GmailApp.getAliases();
emails.push(me);
this.emails = emails;
Logger.log('Found ' + this.emails.length + ' email addresses that belong to you.');
}
return this.emails;
}
function markUnresponded(threads) {
var label = getLabel(unrespondedLabel);
label.addToThreads(threads);
}
function getLabel(labelName) {
// Cache the labels.
this.labels = this.labels || {};
label = this.labels[labelName];
if (!label) {
Logger.log('Could not find cached label "' + labelName + '". Fetching.', this.labels);
var label = GmailApp.getUserLabelByName(labelName);
if (label) {
Logger.log('Label exists.');
} else {
Logger.log('Label does not exist. Creating it.');
label = GmailApp.createLabel(labelName);
}
this.labels[labelName] = label;
}
return label;
}
function cleanUp() {
var label = getLabel(unrespondedLabel),
threads = label.getThreads(),
expiredThreads = [],
expiredDate = new Date();
expiredDate.setTime(subtract(expiredDate, maxTime));
if (!threads.length) {
Logger.log('No threads with that label');
return;
} else {
Logger.log('Processing ' + threads.length + ' threads.');
}
threads.forEach(function(thread) {
var lastMessageDate = thread.getLastMessageDate();
// Remove all labels from expired threads.
if (lastMessageDate.getTime() < expiredDate.getTime()) {
Logger.log('Thread expired');
expiredThreads.push(thread);
} else {
Logger.log('Thread not expired');
}
});
label.removeFromThreads(expiredThreads);
Logger.log(expiredThreads.length + ' unresponded messages expired.');
}
/**
* Adds a label to messages that are addressed to me from
* known contacts that I haven't responded to yet.
*/
var needs_response_label = 'Needs Response'
function main() {
var contacts = ContactsApp.getAllContacts()
var query = contacts.map(function (contact) {
return 'from:' + contact.getPrimaryEmail()
}).join(' OR ')
Logger.log('running query: ' + query)
var threads = GmailApp.search('to:me -in:chats ' + query)
var thread_messages = GmailApp.getMessagesForThreads(threads)
var needs_response = []
thread_messages.forEach(function (messages, i) {
var thread = threads[i]
var last_message = messages[messages.length - 1]
var last_from = last_message.getFrom()
var last_to = last_message.getTo()
if (!is_me(last_from) && is_me(last_to) && thread.isInInbox()) {
needs_response.push(thread)
}
})
// Mark unresponded in bulk.
mark_needs_response(needs_response);
Logger.log('Updated ' + needs_response.length + ' messages.');
}
function is_me(fromAddress) {
var addresses = get_email_addresses();
for (i = 0; i < addresses.length; i++) {
var address = addresses[i],
r = RegExp(address, 'i');
if (r.test(fromAddress)) {
return true;
}
}
return false;
}
function get_email_addresses() {
// Cache email addresses to cut down on API calls.
if (!this.emails) {
Logger.log('No cached email addresses. Fetching.');
var me = Session.getActiveUser().getEmail(),
emails = GmailApp.getAliases();
emails.push(me);
this.emails = emails;
Logger.log('Found ' + this.emails.length + ' email addresses that belong to you.');
}
return this.emails;
}
function mark_needs_response(threads) {
var label = get_label(needs_response_label);
var i = 0
while (threads.slice(i, 100).length) {
label.addToThreads(threads.slice(i, 100))
i += 100
}
}
function get_label(labelName) {
// Cache the labels.
this.labels = this.labels || {};
label = this.labels[labelName];
if (!label) {
Logger.log('Could not find cached label "' + labelName + '". Fetching.', this.labels);
var label = GmailApp.getUserLabelByName(labelName);
if (label) {
Logger.log('Label exists.');
} else {
Logger.log('Label does not exist. Creating it.');
label = GmailApp.createLabel(labelName);
}
this.labels[labelName] = label;
}
return label;
}
/**
* Remove contacts from the contacts API where I haven't saved the full name.
*/
function remove_email_contacts() {
var contacts = ContactsApp.getAllContacts()
contacts = contacts.filter(function (contact) {
return !contact.getFullName()
})
.map(function (contact) {
ContactsApp.deleteContact(contact)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment