Skip to content

Instantly share code, notes, and snippets.

@LucaCappelletti94
Created February 23, 2026 08:06
Show Gist options
  • Select an option

  • Save LucaCappelletti94/b42a552f7eddd36e8dfd132b9cf3b50e to your computer and use it in GitHub Desktop.

Select an option

Save LucaCappelletti94/b42a552f7eddd36e8dfd132b9cf3b50e to your computer and use it in GitHub Desktop.
Google script to auto-delete spammy notifications

Gmail Auto-Cleanup for GitHub CI (and Other Noisy Notifications)

  • Last verified: February 23, 2026
  • Goal: Automatically move notification emails older than 7 days to Trash in Gmail.

Why this setup is needed

Gmail filters can label/organize incoming messages, but they do not provide a native “delete after N days” retention rule. The reliable pattern is:

  1. Use a Gmail filter to apply a dedicated label (example: github-ci)
  2. Run a daily Google Apps Script that searches older_than:7d and trashes matching threads

Architecture (simple and reliable)

  • Gmail Filter: identifies noisy notifications
  • Label: github-ci (or any label you choose)
  • Apps Script: runs daily, searches old labeled threads, moves them to Trash
  • Trigger: time-driven, once per day

Step 1: Create a dedicated label in Gmail

  1. Open Gmail: https://mail.google.com
  2. Left sidebar -> More -> Create new label
  3. Name it github-ci (or e.g. noisy-notifications)

Important: a new label starts empty until emails are assigned to it.

Step 2: Create a filter that applies that label

  1. In Gmail search bar, click the filter/options icon
  2. Build criteria (example for GitHub CI):
    • From: notifications@github.com
    • Subject: workflow OR failed OR succeeded OR run
    • Optional: add repo keyword in “Has the words”, e.g. "owner/repo"
  3. Click Create filter
  4. Check Apply the label
  5. Select/create label github-ci
  6. (Optional but recommended for initial backfill) check Also apply filter to matching conversations
  7. Click Create filter

Common confusion

If you don’t check “Also apply filter to matching conversations”, the label will be applied only to new incoming matching emails.

Step 3: Create Apps Script project

  1. Open: https://script.google.com
  2. Click New project
  3. Replace default code with the script below
  4. Save project (example: gmail-notification-cleanup)
  function deleteOldLabeledNotifications() {
  // Label assigned by your Gmail filter (change if needed)
  const LABEL = "github-ci";

  // Keep emails newer than this many days
  const DAYS = 7;

  // Number of threads fetched per search loop
  const SEARCH_BATCH = 500;

  // Gmail API limit: max 100 threads per moveThreadsToTrash call
  const MOVE_BATCH = 100;

  // Gmail search query:
  // - only threads with the chosen label
  // - older than N days
  // - not already in Trash
  const query = `label:${LABEL} older_than:${DAYS}d -in:trash`;

  // Keep processing until no matching threads remain
  while (true) {
    // Fetch a batch of matching threads
    const threads = GmailApp.search(query, 0, SEARCH_BATCH);

    // Stop when there is nothing left to process
    if (!threads.length) break;

    // Move threads to Trash in chunks of 100 to respect Gmail limit
    for (let i = 0; i < threads.length; i += MOVE_BATCH) {
      const chunk = threads.slice(i, i + MOVE_BATCH);
      GmailApp.moveThreadsToTrash(chunk);
    }
  }
}

Step 4: Authorize and test manually (once)

  1. In Apps Script, select function deleteOldLabeledNotifications
  2. Click Run
  3. Complete Google authorization prompts
  4. Verify in Gmail:
    • old matching labeled threads moved to Trash
    • recent threads remain untouched

Safe first run (recommended)

Temporarily set:

  • const DAYS = 14;

Validate behavior, then switch back to 7.

Step 5: Add daily trigger

  1. In Apps Script, open Triggers (clock icon)
  2. Click Add Trigger
  3. Configure:
    • Function: deleteOldLabeledNotifications
    • Event source: Time-driven
    • Type: Day timer
    • Frequency: Every day
  4. Save

How to reuse for any other notification source

  1. Create another label (examples: build-bots, social-digests, billing-alerts)
  2. Create Gmail filter(s) that apply that label
  3. Either:
    • duplicate script function per label, or
    • make LABEL configurable and run multiple triggers/functions

Troubleshooting

1) Label has no emails

  • Expected if filter was just created and no new matching email arrived
  • Or filter criteria are too strict
  • Or you didn’t enable “Also apply filter to matching conversations”

2) Wrong emails are getting trashed

  • Tighten filter using:
    • exact sender
    • exact subject keywords
    • repo/project keyword

3) Apps Script error: “This operation can only be applied to at most 100 threads”

  • You must batch trash operations in chunks of 100 (already handled in script above)

4) Authorization issues

  • Re-run function manually
  • Re-grant permissions

5) Multiple Google accounts

  • Ensure Gmail and Apps Script are opened under the same account/mailbox

Operational notes

  • Script moves emails to Trash, not immediate permanent delete
  • Gmail generally auto-deletes Trash after ~30 days
  • If desired, keep a larger retention (e.g. 14 or 30 days) for less aggressive cleanup

Source references

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment