Skip to content

Instantly share code, notes, and snippets.

@astout
Created October 14, 2024 17:39
Show Gist options
  • Select an option

  • Save astout/6277da7330c03e5b297265dde8c4044c to your computer and use it in GitHub Desktop.

Select an option

Save astout/6277da7330c03e5b297265dde8c4044c to your computer and use it in GitHub Desktop.
Mark Gmails as Read (Oct 2024)

Mark All Gmail Messages as Read

I have a Gmail account that I use primarily for giving out to businesses for promotions, rewards, etc. I don't really pay too much attention to this mailbox and it mostly collects spam. I'm obsessive about having everything "read" in my inboxes, so I wrote this script to mark all messages as read.

How it works

The script uses the following steps:

  1. Simulates keyboard shortcuts to select all unread messages.
  2. Marks the selected messages as read.
  3. Repeats the process until no more unread messages are found.

Configuration

  • Gmail obviously obfuscates its DOM classes and IDs, so the configuration may need to be updated for your use case.
    • Just use 'inspect element' in find the className of your gmail "conversation" row items when they are unread.
    • In my case, it was zA zE
  • You will need to go to your gmail settings and enable "keyboard shortcuts"
    • When this script was written, Gmail's keyboard shortcuts were:
      • Select all conversations: * + a (Shift + 8, then 'a')
      • Mark as read: Shift + i (hold the shift key and press 'i')
  • Filter your emails to only show the unread ones
    • In the search bar, type is:unread
  • Once a batch is marked as read, it will take Gmail a few seconds to "process" the action and update the unread email list.
    • For me, 4 seconds was sufficiently long enough to wait between batches.
  • Modify the CONFIG object to your liking...
  • Once you have all the above, paste the code into the browser console and hit enter. It will stop once unread emails found by the unreadClassName are no longer found.

Code

const CONFIG = {
  unreadClassName: 'zA',
  markAsReadShortcut: 'I',
  selectAllShortcut: '*',
  selectAllShortcutKey: 'A',
  delayBetweenKeyPressesMs: 200,
  delayBetweenIterationsMs: 4000,
  minimumUnreadElements: 0,
};

async function markAllAsRead(config = CONFIG) {
  const options = { ...CONFIG, ...config };

  console.log('Marking all emails as read...');
  console.log('config:', options);

  function simulateKeyPress(key, shiftKey = false) {
    const event = new KeyboardEvent('keypress', {
      bubbles: true,
      cancelable: true,
      key: key,
      shiftKey: shiftKey
    });
    document.body.dispatchEvent(event);
  }

  async function executeShortcuts() {
    // Select all: '*' (Shift + 8) followed by 'a'
    simulateKeyPress(options.selectAllShortcut, true);
    await new Promise(resolve => setTimeout(resolve, 100));
    simulateKeyPress(options.selectAllShortcutKey);

    // Mark as read: 'I' (Shift + i)
    await new Promise(resolve => setTimeout(resolve, 100));
    simulateKeyPress(options.markAsReadShortcut, true);
  }

  async function checkAndExecute() {
    console.log('Checking for unread emails by class name:', options.unreadClassName);
    const unreadEmails = document.getElementsByClassName(options.unreadClassName);
    console.log('unreadEmails:', unreadEmails);
    if (unreadEmails.length > options.minimumUnreadElements) {
      await executeShortcuts();
      console.log('Marked a batch of emails as read.');
      await new Promise(resolve => setTimeout(resolve, options.delayBetweenIterationsMs)); // Wait 1.5 seconds before next iteration
      await checkAndExecute(); // Recursive call
    } else {
      console.log('No more unread emails found.');
    }
  }

  await checkAndExecute();
}

// Run the function
markAllAsRead().catch(error => console.error('An error occurred:', error));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment