Skip to content

Instantly share code, notes, and snippets.

@rutvij2292
Last active September 26, 2025 12:06
Show Gist options
  • Select an option

  • Save rutvij2292/1941741d24a126078d9bea4d209f62f6 to your computer and use it in GitHub Desktop.

Select an option

Save rutvij2292/1941741d24a126078d9bea4d209f62f6 to your computer and use it in GitHub Desktop.
Auto-delete Gmail emails by labels like delete.in.10.days using Google Apps Script

Gmail Auto-Delete Script

This Google Apps Script automatically deletes Gmail emails based on label-driven rules.
You can create labels like delete.in.7.days or delete.in.3.hours, and the script will check those labels on a schedule, deleting matching emails once the time threshold has passed.

✨ Features

  • Label-based rules: Define auto-deletion policies directly in Gmail using labels:
    • delete.in.7.days
    • delete.in.3.hours
    • delete.in.15.minutes
  • Flexible time units: Supports days, hours, and minutes.
  • Safe testing: Use SOFT_DELETE_MODE to simulate deletions without actually removing emails.
  • Batch processing: Handles large inboxes efficiently by processing emails in configurable chunks (BATCH_SIZE).
  • Logging: Outputs clear logs of actions and errors for easier debugging.

⚙️ How It Works

  1. The script scans all your Gmail labels.
  2. Any label starting with delete.in. is treated as a deletion rule.
    • Example: delete.in.10.days → emails with this label are deleted 10 days after the last message in the thread.
  3. Each thread’s last activity date is compared against the rule.
  4. If the age exceeds the threshold, the email is moved to Trash.
  5. In SOFT_DELETE_MODE, it only logs what would have been deleted.

🏷 Label Naming Convention

  • Format: delete.in.{number}.{unit}

  • Examples:

    • delete.in.30.days → delete after 30 days
    • delete.in.12.hours → delete after 12 hours
    • delete.in.5.minutes → delete after 5 minutes

📦 Example Log Output

Processing label: delete.in.10.days (delete after 10 days)
Deleting email: "Weekly Newsletter" (12 days old)
Email moved to trash
Processed 25 threads for label: delete.in.10.days

🚀 Setup Instructions

  1. Open Google Apps Script.
  2. Create a new project and paste this script.
  3. Adjust the CONFIG values if needed:
    • SOFT_DELETE_MODE: true → safe testing (no deletion)
    • BATCH_SIZE: 50 → number of emails processed per run
  4. Save and authorize the script.
  5. Set up a time-driven trigger (e.g., run every hour or day).

Use Cases

  • Auto-cleanup of newsletters after X days.
  • Temporary labels for time-sensitive emails.
  • Keeping inbox clean without manual intervention.
/**
* Gmail Auto-Delete Script
* Automatically deletes emails based on label naming conventions
* Label format: "delete.in.{number}.{unit}" (e.g., "delete.in.7.days")
* Supported units: days/day, hours/hour, minutes/minute
*/
// Configuration constants
const CONFIG = {
SOFT_DELETE_MODE: false, // Set to true to test without actually deleting emails
BATCH_SIZE: 50, // Number of threads to process per batch
DELETE_LABEL_PREFIX: 'delete.in'
};
// Time conversion constants (in milliseconds)
const TIME_UNITS = {
MINUTE: 60 * 1000,
HOUR: 60 * 60 * 1000,
DAY: 24 * 60 * 60 * 1000
};
/**
* Main execution function
* Processes all labels with deletion rules and applies them
*/
function executeEmailDeletion() {
try {
const deletionLabels = getLabelsWithDeletionRules();
if (deletionLabels.length === 0) {
Logger.log('No deletion labels found');
return;
}
Logger.log(`Found ${deletionLabels.length} deletion labels to process`);
for (const labelName of deletionLabels) {
processLabelForDeletion(labelName);
}
Logger.log('Email deletion process completed');
} catch (error) {
Logger.log(`Error in main execution: ${error.toString()}`);
}
}
/**
* Gets all user labels that contain deletion rules
* @returns {string[]} Array of label names with deletion rules
*/
function getLabelsWithDeletionRules() {
const userLabels = GmailApp.getUserLabels();
const deletionLabels = [];
for (const label of userLabels) {
const labelName = label.getName();
if (labelName.includes(CONFIG.DELETE_LABEL_PREFIX)) {
deletionLabels.push(labelName);
}
}
return deletionLabels;
}
/**
* Processes a specific label for email deletion
* @param {string} labelName - The name of the label to process
*/
function processLabelForDeletion(labelName) {
try {
const deletionRule = parseDeletionRule(labelName);
if (!deletionRule) {
Logger.log(`Invalid deletion rule format for label: ${labelName}`);
return;
}
const label = GmailApp.getUserLabelByName(labelName);
if (!label) {
Logger.log(`Label not found: ${labelName}`);
return;
}
Logger.log(`Processing label: ${labelName} (delete after ${deletionRule.amount} ${deletionRule.unit})`);
let processedCount = 0;
let page = 0;
let hasMoreThreads = true;
while (hasMoreThreads) {
const startIndex = page * CONFIG.BATCH_SIZE;
const threads = label.getThreads(startIndex, CONFIG.BATCH_SIZE);
for (const thread of threads) {
if (shouldDeleteThread(thread, deletionRule)) {
deleteThread(thread);
processedCount++;
}
}
page++;
hasMoreThreads = threads.length >= CONFIG.BATCH_SIZE;
}
Logger.log(`Processed ${processedCount} threads for label: ${labelName}`);
} catch (error) {
Logger.log(`Error processing label ${labelName}: ${error.toString()}`);
}
}
/**
* Parses deletion rule from label name
* @param {string} labelName - Label name containing deletion rule
* @returns {Object|null} Deletion rule object or null if invalid
*/
function parseDeletionRule(labelName) {
try {
const ruleStart = labelName.indexOf(CONFIG.DELETE_LABEL_PREFIX);
if (ruleStart === -1) return null;
const ruleSubstring = labelName.substring(ruleStart);
const ruleParts = ruleSubstring.replace(`${CONFIG.DELETE_LABEL_PREFIX}.`, '').split('.');
if (ruleParts.length < 2) return null;
const amount = parseInt(ruleParts[0]);
const unit = ruleParts[1].toLowerCase();
if (isNaN(amount) || amount <= 0) return null;
// Normalize unit names
const normalizedUnit = normalizeTimeUnit(unit);
if (!normalizedUnit) return null;
return {
amount: amount,
unit: normalizedUnit,
milliseconds: calculateMilliseconds(amount, normalizedUnit)
};
} catch (error) {
Logger.log(`Error parsing deletion rule for ${labelName}: ${error.toString()}`);
return null;
}
}
/**
* Normalizes time unit names to standard format
* @param {string} unit - Time unit from label
* @returns {string|null} Normalized unit name or null if invalid
*/
function normalizeTimeUnit(unit) {
switch (unit) {
case 'day':
case 'days':
return 'days';
case 'hour':
case 'hours':
return 'hours';
case 'minute':
case 'minutes':
return 'minutes';
default:
return null;
}
}
/**
* Calculates milliseconds for given amount and unit
* @param {number} amount - Number of time units
* @param {string} unit - Time unit (days, hours, minutes)
* @returns {number} Time in milliseconds
*/
function calculateMilliseconds(amount, unit) {
switch (unit) {
case 'days':
return amount * TIME_UNITS.DAY;
case 'hours':
return amount * TIME_UNITS.HOUR;
case 'minutes':
return amount * TIME_UNITS.MINUTE;
default:
return 0;
}
}
/**
* Determines if a thread should be deleted based on deletion rule
* @param {GmailThread} thread - Gmail thread to check
* @param {Object} deletionRule - Deletion rule object
* @returns {boolean} True if thread should be deleted
*/
function shouldDeleteThread(thread, deletionRule) {
try {
const threadDate = thread.getLastMessageDate();
const currentDate = new Date();
const timeDifference = currentDate.getTime() - threadDate.getTime();
return timeDifference > deletionRule.milliseconds;
} catch (error) {
Logger.log(`Error checking thread for deletion: ${error.toString()}`);
return false;
}
}
/**
* Deletes or logs deletion of email thread
* @param {GmailThread} thread - Gmail thread to delete
*/
function deleteThread(thread) {
try {
const subject = thread.getFirstMessageSubject();
const threadDate = thread.getLastMessageDate();
const daysSinceReceived = Math.floor((new Date() - threadDate) / TIME_UNITS.DAY);
Logger.log(`Deleting email: "${subject}" (${daysSinceReceived} days old)`);
if (!CONFIG.SOFT_DELETE_MODE) {
thread.moveToTrash();
Logger.log('Email moved to trash');
} else {
Logger.log('SOFT DELETE MODE: Email would be deleted');
}
} catch (error) {
Logger.log(`Error deleting thread: ${error.toString()}`);
}
}
/**
* Test function to list all deletion labels
* Useful for debugging and verification
*/
function testListDeletionLabels() {
Logger.log('=== Testing Deletion Labels ===');
try {
const deletionLabels = getLabelsWithDeletionRules();
if (deletionLabels.length === 0) {
Logger.log('No deletion labels found');
return;
}
Logger.log(`Found ${deletionLabels.length} deletion labels:`);
for (const labelName of deletionLabels) {
const rule = parseDeletionRule(labelName);
if (rule) {
Logger.log(`✓ ${labelName} -> Delete after ${rule.amount} ${rule.unit}`);
} else {
Logger.log(`✗ ${labelName} -> Invalid rule format`);
}
}
} catch (error) {
Logger.log(`Error in test function: ${error.toString()}`);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment