Created
March 18, 2025 12:36
-
-
Save hclivess/81e9c15e02fd94d931ba63c1987459bf to your computer and use it in GitHub Desktop.
Unsubscribe all GMAIL emails for free, open source
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Gmail Mass Unsubscribe - Uses pagination to process ALL emails | |
// Run this in your browser console while in Gmail | |
(async function() { | |
console.log('π Starting Gmail unsubscribe for ALL emails using pagination...'); | |
// Constants | |
const EMAIL_OPEN_DELAY = 1000; | |
const MAX_PAGES = 200; // Safety limit on pages to process | |
// Global trackers | |
window.unsubUrls = []; | |
let totalProcessed = 0; | |
let totalFound = 0; | |
// First search for "unsubscribe" if not already searched | |
if (!window.location.hash.includes('#search/unsubscribe')) { | |
console.log('π§ Searching for emails with "unsubscribe"...'); | |
window.location.hash = '#search/unsubscribe'; | |
await new Promise(resolve => setTimeout(resolve, 3000)); | |
} | |
// Function to get the current page number | |
function getCurrentPage() { | |
// Check pagination controls | |
const paginationText = document.querySelector('.Dj'); | |
if (!paginationText) return 1; | |
const text = paginationText.textContent; | |
const match = text.match(/(\d+)β(\d+)/); | |
if (!match) return 1; | |
return Math.ceil(parseInt(match[1]) / 50); // Assuming 50 per page | |
} | |
// Function to get total emails shown in pagination | |
function getTotalEmailCount() { | |
const paginationText = document.querySelector('.Dj'); | |
if (!paginationText) return 0; | |
const text = paginationText.textContent; | |
const match = text.match(/of\s+(\d+)/); | |
if (!match) return 0; | |
return parseInt(match[1]); | |
} | |
// Function to go to next page | |
async function goToNextPage() { | |
const nextButton = document.querySelector('[act="20"]'); // Gmail's next page button | |
if (!nextButton) return false; | |
console.log('π Going to next page...'); | |
nextButton.click(); | |
await new Promise(resolve => setTimeout(resolve, 2000)); | |
return true; | |
} | |
// Function to process emails on current page | |
async function processCurrentPage() { | |
console.log(`π Processing page ${getCurrentPage()}...`); | |
// Get all emails on this page | |
const emails = document.querySelectorAll('tr.zA'); | |
console.log(`π Found ${emails.length} emails on this page`); | |
let pageProcessed = 0; | |
let pageFound = 0; | |
// Process each email on this page | |
for (let i = 0; i < emails.length; i++) { | |
const email = emails[i]; | |
// Check if email content suggests it's a subscription | |
const emailText = email.textContent.toLowerCase(); | |
if (emailText.includes('unsubscribe') || | |
emailText.includes('opt out') || | |
emailText.includes('opt-out') || | |
emailText.includes('subscription') || | |
emailText.includes('newsletter')) { | |
// Highlight for visibility | |
const originalBackground = email.style.backgroundColor; | |
email.style.backgroundColor = '#e6f7ff'; | |
try { | |
// Get email details before opening | |
const emailSender = email.querySelector('.yW')?.textContent || 'Unknown'; | |
const emailSubjectElem = email.querySelector('.y6'); | |
const emailSubject = emailSubjectElem?.textContent || 'No Subject'; | |
// Click to open the email | |
if (emailSubjectElem) { | |
emailSubjectElem.click(); | |
await new Promise(resolve => setTimeout(resolve, EMAIL_OPEN_DELAY)); | |
// Check for unsubscribe options | |
const emailBody = document.querySelector('.a3s'); | |
if (emailBody) { | |
// First try Gmail's built-in unsubscribe button | |
const gmailUnsubButton = document.querySelector('[aria-label="Unsubscribe"]'); | |
if (gmailUnsubButton) { | |
console.log(`β Found Gmail unsubscribe for: ${emailSubject}`); | |
gmailUnsubButton.click(); | |
await new Promise(resolve => setTimeout(resolve, 1000)); | |
// Confirm unsubscribe if dialog appears | |
const confirmButtons = Array.from(document.querySelectorAll('button')).filter(b => | |
b.textContent.toLowerCase().includes('unsubscribe') || | |
b.textContent.toLowerCase().includes('confirm') | |
); | |
if (confirmButtons.length > 0) { | |
confirmButtons[0].click(); | |
console.log(`β Confirmed unsubscribe for: ${emailSubject}`); | |
} | |
pageFound++; | |
totalFound++; | |
} else { | |
// Look for unsubscribe links in email body | |
const allLinks = emailBody.querySelectorAll('a'); | |
const unsubLinks = Array.from(allLinks).filter(link => { | |
const linkText = (link.textContent || '').toLowerCase(); | |
const linkHref = (link.href || '').toLowerCase(); | |
return linkText.includes('unsubscribe') || | |
linkText.includes('opt out') || | |
linkText.includes('opt-out') || | |
linkHref.includes('unsubscribe') || | |
linkHref.includes('opt-out'); | |
}); | |
if (unsubLinks.length > 0) { | |
console.log(`β Found unsubscribe link for: ${emailSubject}`); | |
// Get the first unsubscribe link | |
const unsubLink = unsubLinks[0]; | |
const unsubUrl = unsubLink.href; | |
// Store the URL | |
window.unsubUrls.push({ | |
sender: emailSender, | |
subject: emailSubject, | |
url: unsubUrl | |
}); | |
// Open in a new tab | |
window.open(unsubUrl, '_blank'); | |
pageFound++; | |
totalFound++; | |
} | |
} | |
} | |
// Go back to inbox | |
const backButton = document.querySelector('[aria-label="Back to Inbox"]'); | |
if (backButton) { | |
backButton.click(); | |
await new Promise(resolve => setTimeout(resolve, 800)); | |
} | |
} | |
} catch (error) { | |
console.error(`Error processing email: ${error.message}`); | |
} | |
// Reset background color | |
email.style.backgroundColor = originalBackground; | |
pageProcessed++; | |
totalProcessed++; | |
} | |
} | |
console.log(`π Page summary: Processed ${pageProcessed} emails, found ${pageFound} unsubscribe links`); | |
return { pageProcessed, pageFound }; | |
} | |
// Process all pages with pagination | |
async function processAllPages() { | |
console.log('π Starting pagination-based processing of ALL emails...'); | |
// Get total emails count | |
const totalEmails = getTotalEmailCount(); | |
console.log(`π Total emails found in search: ${totalEmails}`); | |
// Process first page | |
await processCurrentPage(); | |
// Process subsequent pages | |
let currentPage = 1; | |
let hasMorePages = true; | |
while (hasMorePages && currentPage < MAX_PAGES) { | |
hasMorePages = await goToNextPage(); | |
if (hasMorePages) { | |
currentPage++; | |
console.log(`π Now on page ${currentPage} of search results`); | |
await processCurrentPage(); | |
} | |
} | |
return { totalProcessed, totalFound, totalEmails }; | |
} | |
// Start processing | |
console.log('π Starting to process ALL pages of emails for unsubscribe...'); | |
const result = await processAllPages(); | |
// Final report | |
console.log(`β¨ PAGINATION PROCESS COMPLETE! β¨`); | |
console.log(`π Total emails in search: ${result.totalEmails}`); | |
console.log(`π Total subscription emails processed: ${result.totalProcessed}`); | |
console.log(`π Total unsubscribe links found: ${result.totalFound}`); | |
// Show all unsubscribe URLs | |
console.log('π All unsubscribe links found:'); | |
window.unsubUrls.forEach((item, index) => { | |
console.log(`${index+1}. ${item.sender}: ${item.subject}`); | |
console.log(` π ${item.url}`); | |
}); | |
console.log(`β οΈ Note: Unsubscribe links were opened in new tabs. Please check those tabs to complete the process.`); | |
console.log(`π‘ All links are stored in "window.unsubUrls" if you need them again.`); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment