Simulating Google Inbox with Google Apps Script
Like many others, I still mourn the loss of Google Inbox, perhaps the second most missed product in the Google Graveyard.
I’ve made various attempts at replicating the functionality, but have landed on a relatively simple script.
Using two labels it creates (“hidden”, and “surfaced”), it hides emails in the archive temporarily, and resurfaces them once a day. The pesky unread icon still shows up in the labels tab, but it’s the closest I’ve come to replicating my beloved Inbox setup.
It’s deployed in Google Apps Script, a sneakily useful scripting environment (which also has the look and feel of a niche, beloved Google product surviving via benign neglect).
Here’s the code, also available in Github:
HIDDEN_LABEL = GmailApp.getUserLabelByName('hidden')
SURFACED_LABEL = GmailApp.getUserLabelByName('surfaced')
function main() {
hideUnimportantEmails()
cleanupLabels()
markOldUnimportantEmailsRead()
}
/*
* Hide unimportant emails from the main inbox.
* Fetches new incoming emails from Updates, applies 'hidden' label, and removes from inbox.
*/
function hideUnimportantEmails() {
// Find unprocessed emails
var query = 'label:Updates AND label:Inbox AND -label:hidden AND -label:surfaced';
// Fetch threads that match the search query (sanity limit of 500)
var threads = GmailApp.search(query, 0, 500);
if (threads.length > 0) {
// Apply 'hidden' label to each thread
HIDDEN_LABEL.addToThreads(threads);
// Archive each thread
GmailApp.moveThreadsToArchive(threads);
}
}
/*
* Fetches hidden emails, labels as "surfaced" so we know they should be in inbox,
* move to inbox, remove hidden label.
*
* Should be run on cadence unimportant emails should be surfaced (ie 1-2x a day)
*/
function surfaceUnimportantEmails() {
var threads = getThreads('label:hidden AND label:Updates AND -in:inbox');
if (threads.length > 0) {
// Remove 'hidden' label from each thread
HIDDEN_LABEL.removeFromThreads(threads);
// Apply 'surfaced' label to each thread
SURFACED_LABEL.addToThreads(threads);
// Move each thread back to the Inbox
GmailApp.moveThreadsToInbox(threads);
}
}
// Remove surfaced label from emails that have been reviewed (since they are not in inbox)
function cleanupLabels() {
var threads = getThreads('label:surfaced AND -label:Inbox')
if (threads.length > 0) {
SURFACED_LABEL.removeFromThreads(threads)
GmailApp.markThreadsRead(threads)
}
// archive surfaced emails that have been read
var threads = getThreads('label:surfaced AND is:read')
if (threads.length > 0) {
SURFACED_LABEL.removeFromThreads(threads)
GmailApp.moveThreadsToArchive(threads)
}
// archive hidden emails that have been read
threads = getThreads('label:hidden AND is:read')
if (threads.length > 0) {
HIDDEN_LABEL.removeFromThreads(threads)
GmailApp.moveThreadsToArchive(threads)
}
}
/*
* Prevent messy unread emails from piling up in the inbox.
*/
function markOldUnimportantEmailsRead() {
var threads = getThreads('(label:Promotions OR label:Updates) AND -label:hidden AND -label:surfaced AND is:unread AND older_than:7d')
GmailApp.markThreadsRead(threads)
// Gmail will not return spam and non-spam threads in the same query
var threads = getThreads('in:spam AND is:unread')
GmailApp.markThreadsRead(threads)
}
/*
*
* Helper functions
*
*/
function getThreads(query) {
// Limit 100 for sanity check
Logger.log("SEARCHING: " + query)
var threads = GmailApp.search(query, 0, 100)
Logger.log("Found " + threads.length + " threads")
return threads
}
/*
* Run once to set up all relevant labels
*/
function setup() {
GmailApp.createLabel('hidden');
GmailApp.createLabel('surfaced');
}