Changelog - Gmail One-Click Cleaner
All notable changes to this project will be documented in this file. This log tracks user-visible behavior, UI changes, and important internal fixes.
10.1.0 - Protected stays protected
Some things you had already settled could come undone in 10.0. With Settings open in a tab, a sender you protected from Sender Triage or the Stats page dropped off your whitelist the next time you saved anything in Settings. A triage run that finished while the popup was open again went back to waiting on your next key press. And the triage decisions the privacy policy says are forgotten after 90 days were only hidden, never deleted.
Added
- See a sender's mail before you decide. The triage card has a See their mail button. It opens a Gmail search for that sender in a new tab, in the mailbox the popup is on.
- Decisions waiting to run show outside the sheet. Both ways into Sender Triage now say how many of your decisions haven't run yet, so a group you sorted and never ran doesn't get forgotten.
- S and Z are on screen. Skip and Undo show their keys the way the four decision buttons do, and the shortcut help lists them.
Changed
- Support links in Settings go to the support inbox the privacy policy names, not a personal address.
Fixed
- Saving Settings no longer unprotects anyone. Save wrote the whitelist box back exactly as the page had loaded it, so a sender added from Sender Triage or the Stats page while Settings was open got dropped. Save now keeps what was added elsewhere and still honours the lines you deleted, and the box updates by itself while you aren't editing it.
- A finished triage run stays finished. Open the popup again while a triage run is going, keep sorting, and the run's senders used to go back to waiting on your next key press. Undo could even take back a decision whose mail had already moved. The popup now picks up the result as the run ends.
- Old triage decisions are deleted, not just hidden. The daily housekeeping now removes decisions older than 90 days, which is what the privacy policy says happens. Before this, the popup only stopped showing them.
- The shortcut help acts like a dialog. Escape closes it before anything under it, and it keeps focus, so a letter typed while you read it no longer sorts the card underneath.
- Keep tells you when your whitelist is full. It used to say "try again", which can't work against a full 100-entry list.
- Diagnostics counts Sender Triage data. The stored sender data card now counts your triage decisions. Triage data on its own used to read as "these are empty".
- What's new points at the full history, not GitHub. The note under the list of releases still said the rest was on GitHub.
Internal
- Eight new suites, each red on 10.0.0.
10.0.0 - One sender at a time
Every other way to clean with this extension starts from a rule: pick a category, an age or a size, and it finds the mail that fits. Sender Triage starts from the people instead. It picks up the senders your scans have already found and shows them one card at a time, heaviest first. For each one you pick Keep, Archive, Delete or Unsubscribe. Nothing moves while you sort. Your decisions are saved as you make them, and each kind runs as its own group when you press its button.
Added
- Sender Triage. Open it from the top of the Report tab, or from the Lists tab under the Unsubscribe button. Each card says who the sender is, how much they have sent you, and which button the scans point to. Every button has its letter key printed on it. S skips a card and Z takes back the last decision.
- Each decision runs through a path the extension already had. Archive and Delete are the same scoped cleanup a Smart Suggestion runs, so the mail is tagged first, a dry run stays a dry run, your safety switches all apply, and Restore on the Stats page can put a run back. Delete only takes mail older than six months. Unsubscribe goes through Gmail's own control and spends the same three free unsubscribes as the Lists tab. Keep adds the sender to your whitelist.
- Free to use, with bigger runs in Pro. Sorting is free and so is running what you sorted. A free press runs three senders of one kind, and Pro runs twenty-five. Cards only come from senders the other tabs already show you, so on a free licence that means the census's top five and the first three suggestions.
- A closed popup loses nothing. The popup closes the moment you click outside it, which is why every decision is saved as soon as you make it. A decision is forgotten 90 days after you made it, and Erase Stored Sender Data in Settings removes all of them at once.
Changed
- The privacy policy, the terms and this changelog now live on the extension's own site. The privacy link used to open a page on GitHub. It now opens gmail-cleaner-pro.netlify.app/privacy, which is built from the same PRIVACY.md, so the two can't say different things. Links to the source code and the issue tracker go through that site too. It sends you to GitHub when GitHub is serving the page, and to a support page when it isn't.
Internal
- New suites for the triage logic, the worker marker that settles decisions when a run ends, the popup sheet driven by keyboard, the policy pages and the /go/ redirector.
9.9.0 - Stay with what you picked
Most of this release is about the extension holding on to a choice you made. With Gmail open in two windows, one account in each, the popup went with the first window's account rather than the one you clicked it from, so a run could land in the other mailbox. On the Unsubscribe tab, a run that took twenty-five of your forty ticked senders finished with the other fifteen unticked. And the daily housekeeping job, the one that prunes old activity and clears a census once it is three months old, reset its own countdown every time the browser started. On a browser that gets closed every night it never ran at all.
Changed
- The Unsubscribe list says its cap before you press. A paid run takes twenty-five senders, and the list can hold two hundred behind a Select all. The count line now says how many this run takes and how many are left for the next, the way the Storage tab has since 9.8.
- Select all follows the rows. The box ticks itself when every row is ticked, clears when one is unticked, and shows a mixed state in between, on all four sender lists. It used to remember only its own last click.
- Turning the Gmail button back on shows it right away. Settings used to ask you to reload Gmail. The extension now puts the button back in every Gmail tab that is already open.
Fixed
- The popup starts on the mailbox in its own window. With one account open in each of two windows, it picked the first window's account. It now looks at the window you opened it from first. A pill you click still wins.
- Ticks stay ticked when a list redraws. The Unsubscribe, Storage and Suggested lists redrew from the selection they had when the popup opened, so anything ticked after that disappeared when a run finished, a rescan landed or a safety switch moved.
- Daily housekeeping runs again. The alarm behind it is left alone when it is already set, and a missing one is set to fire a minute later instead of a day later. This is what removes an expired census from the device, as the privacy policy says it does.
- A restore no longer gets stuck when its Gmail tab closes. The Stats page waited for a message that could not come, and every other Restore said one was already running. It lets go now and tells you to press Restore again, which picks up whatever is still in Trash.
- A custom rule with
-older_than:gets the age warning. A rule on the whole inbox with-older_than:1ymeans mail newer than a year, and it was saved without the warning about recent mail. Same gap 9.8 closed fornewer_than:. - "Moved to Trash", not "Freed", everywhere. The progress page chip and the Diagnostics page still used the old word for mail that is sitting in Trash and still counts against your storage.
Internal
- Eight new suites, each shown to fail on 9.8.0 before its fix.
- Page tests that boot the popup more than once now start exactly one popup per boot, so an earlier one cannot answer for the next.
9.8.0 - Count the senders the button reaches
The census Clear button has a cap. It has had one since the feature shipped: twenty-five senders become rules on one run, and the rest wait for the next press. The line under the button did not know that. Tick forty senders and it quoted what forty would give back, over a button that cleared twenty-five.
This is the bug 9.1 fixed on the button directly beneath it, on the same tab. The receipts clear measures only the senders its cap reaches, and reports the rest as stranded. One card up, the census clear went on measuring every one of them.
The two halves also disagreed about which twenty-five. The subtitle walked the ranked list, biggest sender first. The handler sliced the set of ticked addresses, which is in the order the boxes were ticked. On any selection past the cap those are different senders, so the number was wrong twice over: too big, and about mail the run was never going to touch.
Changed
- The census Clear button says how many senders this run reaches and how many are left for the next. The number beside it now counts only the senders the run will act on. The run takes them ranked, biggest first, so pressing it twice clears the largest fifty rather than whichever fifty boxes were ticked first, and a scheduled sweep carries the same senders the button would.
- The Storage X-ray says its cap before the press, not after. That purge has taken the first twenty-five since 8.0 and has said so in a toast since 8.11, which arrives once the run is already going. The count line beside Select all says it while the boxes are still being ticked.
- The census sender list has a Select all. It was the only ranked sender list without one, and the longest of them at up to sixty rows. A free licence can select the rows it can see.
Fixed
- A custom rule bounded to recent mail no longer reads as protected. A rule that reaches a whole view (
in:inbox,in:all) with no age filter gets a warning, because it will delete mail that arrived this morning. The check for "does this rule have an age filter" acceptednewer_than:andafter:, which bound a rule to recent mail rather than away from it, soin:inbox newer_than:7dwas saved in silence. Onlyolder_than:andbefore:count now; a date range still passes, because thebefore:half is the floor. - The 90-day prune of the daily activity buckets kept to the local calendar. Those buckets are keyed by UTC date. The cutoff walked ninety days back on the local calendar and only then converted, which is the same instant until the timezone offset differs between the two ends. Across a DST change it was an hour out, and an hour moves the date when the local time of day sits near midnight UTC, so a day still inside the window was deleted. Same fix 9.7 made to the chart that draws them.
Internal
- Four suites, 37 tests, each proved to fail on 9.7.0 before the fix that answers it.
- The prune suite pins its own timezone and restores it afterwards, because the bug it covers only appears across a DST change and a runner in UTC would have passed either way.
GCC.smart.whitelistCoverslower-cases the address it is given as well as the entry. Both callers already did; it is exported, and the failure direction for the next one is a protected sender going unprotected.
9.7.0 - Put it back where it came from
Every run surface since 9.2 has been careful about which signed-in account it acts on. The one record that exists so a run can be undone never said. Restore on the Stats page took whichever Gmail tab was in front, searched that account for a label that lived in another one, and reported "Nothing left to restore" about mail sitting in the other Trash. With Google Chat in front, which lives under mail.google.com, it did worse: it injected the engine into Chat, the engine refused with a dialog nobody was looking at and no message back, and the page sat on "Starting restore..." with the button reading Cancel.
The erase button 9.6 called complete missed the two stores it had seeded wrong in its own test: the top senders list on the Stats page, sampled from every delete batch and drawn with a Protect button beside each address, and the search strings the run history keeps, which for a census clear are a list of addresses. Same shape as 9.6's own finding, one release later.
Changed
- Restore goes back to the mailbox the run came from. Each new recovery entry records which signed-in account it was written in, and Restore uses a tab in that account, opening one if none is open, rather than whichever mailbox is in front. Entries written before 9.7 carry no account and keep the old behaviour. Find in Gmail beside the entry opens the same mailbox, and the Search links under Top senders open the mailbox you are looking at.
- Erase Stored Sender Data takes the top senders list and the stored searches. The Stats page's list is emptied, and each run in the cleanup history and the run history keeps its label, count, mode and timing and loses its search string. Run counts and totals stay. The Options page, the dialog, PRIVACY.md and the Diagnostics card all say so now.
- The account pills in the popup show the address. A Gmail tab is titled "Inbox (3) - jude@example.com - Gmail" and the pill showed the first 25 characters of that, which cut the address off at the one part that said which account it was. The full title is on hover.
Fixed
- A run started outside a mailbox now says so and ends. The engine refused with an alert in the tab and nothing else, so the surface that started a scan, a census or a restore waited forever. It ends the run the way every other error does, in the shape every caller already handles, and the alert is gone.
- The Stats page and Diagnostics no longer count Google Chat as a Gmail tab. Both filter to mailbox tabs the way the popup has since 9.0. Diagnostics reported detection OK on a Chat tab the cleaner refuses to run in, and Test Inject probed it.
- The daily activity chart drew the wrong 30 days west of Greenwich. Its keys are UTC dates. The chart walked back 30 local days and read each out as a UTC string, so every evening in the Americas "today" was tomorrow's date, the run just finished sat on a bar the chart never drew, and across a DST change one date came out twice. It walks the UTC calendar now.
- Firefox lost the daily housekeeping after a restart. The alarm behind the 90-day stats prune and the census age-out was created on install only. Chrome keeps alarms across a restart; Firefox does not, so on Firefox the first restart after an update took it away until the next update. It is re-armed on every startup, like the schedules.
Internal
- Eight suites, 54 tests, each proved to fail on 9.6.0 before the fix that answers it.
- Two of them drive the real stats.html and diagnostics.html with a click. Their tab stubs answer the callback shape shared.js uses, since a promise-only stub hangs the page and reads as a missing button.
9.6.0 - Erase means erase
The Options page has a button reading Erase Stored Sender Data, under a heading reading Stored Sender Data. It cleared six things. Eight more stores held the addresses of people who email you, and nothing in the extension removed any of them.
They were not hidden. The Diagnostics page said, in as many words, that the mailbox report and the subscription, storage and suggestion scans "keep their own sender lists, which this card does not count and the Erase button does not clear", and the confirmation dialog said the same thing at greater length. That is a control whose own copy explains why it does not do what its label says. It is the same shape as the word "Freed" in 9.5, in a smaller room, and it has the same answer: make the control do the thing, then delete the paragraph that existed to excuse it.
Two other numbers turned out to be measured through the wrong filter, which is this project's oldest habit, and the guidance panel 9.5 shipped inside Gmail was going to the wrong tab.
Changed
- Erase Stored Sender Data now erases all of it. The sender census, your unsubscribe receipts, the four ticked-sender lists, the mailbox report, the storage X-ray, the suggestion scan, the subscription scan, the record of which suggestions you approved or dismissed, and the three markers naming senders a run was part way through acting on. One write, as before. The price is stated up front rather than discovered: the four scans go back to asking for a scan, so the report the popup opens on comes back empty until you run one.
- Your recovery log is not touched, and the dialog says so. It is what restores mail from Trash. An erase that quietly gave up the last 30 days of recoverable cleanups would be a worse surprise than anything it removed. It still has its own Clear button on the Stats page.
- The Diagnostics card counts the scans instead of explaining that it cannot. A new row, still counts only, still no address on the page and none in Copy Diagnostics. Its chip can now say "these are empty" and mean it.
Fixed
- "Waiting in Trash" was not a floor. Every surface labels that figure "at least" and it was rounded once per pass before being added up, so a run of small passes could only grow. Forty passes clearing three leftovers apiece reported 8 MB against a real 6, and a run whose passes cleared one message each reported double. The same run's own moved-to-Trash total is worked out without rounding, so one run printed two figures that could not agree. Rounded once now, where it is displayed.
- The note inside Gmail went to the wrong tab. Opening Trash from the popup, the progress page or Stats leaves a one-shot mark for the panel that explains Gmail's Empty Trash link. The mark named the mailbox, and a mailbox does not tell two tabs apart, so with a second Gmail open on the same account the panel could be claimed by the tab that had not gone anywhere, and the tab actually sitting in Trash was told there was nothing for it. 9.5 guarded two signed-in accounts and missed the commoner case.
- The Delete button the engine looks for could be one a sender wrote. The search is normally scoped to Gmail's toolbar and reaches no message body. With the toolbar missing, which is the layout change the engine already stops for, it fell back to the whole page, and a control reading Delete is markup anyone can put in an email. The three filters the Restore finders have run since 7.6 now run on the delete, archive, label and overflow finders too, out of one shared list rather than two that had drifted. Links are refused outright: Gmail's toolbar controls are not links, and following one mid-run is how a run gets abandoned.
- The Stats page said the 9.5 Trash sentence in English. All seven translations of it already existed; the page was building the sentence itself instead of asking for one. It also had a second wording of the same fact, which is how one figure starts reading as two.
Internal
- The erase list is one list. The keys and their cleared values were two literals that had to agree, which was a reading hazard at six entries and a bug waiting at fourteen.
- The per-pass size and the toolbar candidate walk are named functions the tests drive, rather than expressions a test can only read. An assertion on the source of an expression says nothing about what the run does with it, which 9.1 learned the hard way.
- Five suites, 66 assertions, every one of them proved to fail on 9.5.0 before the fix that answers it.
9.5.0 - Say where the space went
This extension is sold on freeing up Gmail storage, and every delete run moves mail to Trash rather than destroying it, which is deliberate: it is what the labelling, the 30-day window and the Restore button are all built on. Google counts Trash against your storage limit until it empties. So the bar this thing exists to move does not move for up to 30 days after a run, and four places said "Freed" about that moment: the popup result card, the progress done card, the Stats tile, and the notification, which is the only surface a scheduled sweep ever reaches.
Five notes elsewhere did say storage frees up once Trash empties. None of them said how much was sitting in there, or how to get to it, and the uninstall page already lists "something went to Trash" among the reasons people leave.
The rule this release settles: no surface may call storage freed while the mail is still inside Gmail's window unless the same surface shows the part that is still waiting and where it is. The waiting figure is measured through the recovery log's own eligibility rules, the ones the Restore button obeys, so what this says is in Trash is exactly what Restore will still bring back.
Changed
- A finished delete run says what it did. "At least ~310 MB moved to Trash", on the result card, the progress card and the notification, in place of a figure called Freed. Archive runs are untouched: they have shown no storage figure since 8.9, because archived mail stays in the account. Dry runs are untouched too.
- The Stats tile is labelled Moved to Trash. The lifetime total was never wrong, and it is still cumulative. The word over it was making a claim about the last 30 days of it that had not happened yet.
Added
- A "waiting in Trash" figure, on four surfaces. The result card after a delete run, the Storage tab, the progress done card and the Stats page. It states a floor, says the mail was moved by this extension in the last 30 days, says Gmail clears Trash on its own after about that long, and admits it cannot see a Trash you emptied by hand. Nothing waiting shows nothing at all.
- An Open Trash button beside it. It brings the mailbox the run acted on to the front and takes it to Trash. With two accounts signed in it lands in the one that was cleaned rather than in the first one open, which is the same mistake 8.11 fixed for runs.
- A note inside Gmail, at the door. Arriving in Trash through that button, and only through it, the panel in the corner says that Gmail's own "Empty Trash now" link is at the top of the list, that it is permanent, that it takes mail you deleted yourself along with it, and that Gmail does the job on its own after about 30 days anyway. It appears once and closes when you navigate away. The extension does not click that link, does not point at it, and has no run that touches Trash. Turning the Gmail button off turns this off with it.
- The recovery log records how many megabytes a run moved. It was keeping counts and no sizes, and it is the only store that knows which runs are still inside the window. Runs recorded by earlier versions report their count and no size, so the figure starts as an undercount on an upgrade and corrects itself as those runs age out.
9.4.0 - Ask whose markup it is before clicking it
The unsubscribe run asks three times whether a control belongs to Gmail before it clicks the first one, because a link inside a message was written by whoever sent it and following one takes the tab somewhere they chose. The confirmation that comes next asked nothing at all. It looked for the dialog anywhere on the page, and a sender who puts a dialog in their own message wins that search, because their copy is higher up the page than the one Gmail adds. So a stranger could get their link clicked, in a signed-in mailbox, without the person who owns it touching anything. The same unscoped search sat in the confirmation for a bulk delete, which is the click that turns a page into a whole result set.
The rest of the release is a sweep, and most of it is the extension being made to stop saying things it had not established.
Fixed
- A message can no longer supply the dialog its own unsubscribe gets confirmed in. One rule now answers "is this Gmail's or the sender's" for the dialog, for the buttons inside it, and for the bulk-delete confirmation, which had the same gap and the larger consequence.
- The Skip to main action link works. It is the first thing a keyboard reaches in the popup and it pointed at the Run button, which lives on the Clean tab, and the popup opens on Report. So the one control added for people not using a mouse did nothing at all on the tab it opens on. It goes to whichever tab you are actually looking at now.
- A rule in the mailbox report shows the whole line it was cutting off. The description is one line and six of the ten steps were too long for it, and the part that got cut was the end, which is where it says whether the step deletes or archives.
- Custom rules can be reordered without a mouse, and deleting one removes the one you clicked. The order was drag-only, and the handle was marked as decoration, so the order rules run in could not be changed from a keyboard. The delete worked by counting from the top of the list, which is the wrong rule as soon as anything else has changed the list, and there is no undo for a rule you wrote.
- Importing a backup runs the same checks as typing. It was the one way into this extension that skipped them, so a file could restore a rule the page refuses to accept, including ones aimed at Starred mail, Trash and Spam, and could set a schedule to run more often than any control here offers. The import summary counted those as restored.
- The unsubscribe ledger stops losing the record it keeps. The snapshot of which safety switches a figure was measured through is what lets the extension stop showing that figure once they change, and every write that was not a verification deleted it. A recheck that could not measure kept the previous number and stamped the new date on it.
- The receipts list is not emptied by a failed read. A storage read that did not answer looked exactly like having never unsubscribed from anything, and hid the whole panel.
- The Gmail button stops calling a mailbox clean when it did not measure one. A scan whose searches timed out, and a mailbox holding old mail that falls outside the steps the panel lists, both produced "That is a clean mailbox". They say what happened now, and the second shows the count it had all along.
- A popup watching one mailbox ignores a run in another. With two accounts signed in, a scan in the other tab could end this one's progress and put its numbers on screen.
- Safe Mode, the default skips and the paid feature list say what the code does. Safe Mode protects receipts and shipping by subject and skips Updates and Forums rules; three places described it three different ways and none had both halves. Four skip switches ship on and the welcome named two. The paid list has been eight features since 9.0 and the store page and the popup's own pitch still said six.
- Smaller things. The Rule Intensity list recommended an option three lines above the one it selects. Settings told Firefox users that Chrome would show their notification. The read-me stated a fixed Auto-Pilot sweep size that Pro Settings lets you change. The Clear button blamed a setting that ships empty. The Gmail panel put the cursor on its close button instead of its main one, and lost it entirely when you pressed Hide.
9.3.0 - Reach the mailbox that is already open
Last release put a cleaner button in the corner of Gmail, because everything this extension does had been sitting behind a toolbar icon Chrome hides until you pin it. It worked on the next Gmail you opened. It did not work on the Gmail you already had open, which for most people is the tab they were looking at when they installed it. A browser only runs a page script when the page loads, and it does not go back and run it in tabs that loaded earlier, so the one thing built for that moment was missing from it. The button and its one-time greeting now arrive in the mailboxes that are open right now, on a fresh install and on an update.
The rest is a sweep. The panel was printing "0+ MB" on any mailbox whose old mail is all small, the selection pill on the popup's tabs was landing a few pixels off the tab it selects, a custom rule written with brackets was skipping a warning it should have got, and four places in the engine could still read the conversation list Gmail leaves behind for a moment while it renders a search.
Fixed
- The Gmail button reaches tabs that were already open. On install and on update, rather than on the next Gmail page load. Nothing new is asked for: the extension already had permission for mail.google.com, and the button still decides nothing for itself.
- An update no longer leaves a dead button in Gmail. Updating an extension cuts off the copy of the page script that is already running, and that copy was still watching the page. When the fresh copy cleared the old button out of the way, the cut-off one put it straight back: a button that looks right and answers nothing, holding the spot the working copy needed. The tab had to be reloaded to get out of it.
- "0+ MB" is gone from the panel. Storage figures come from large mail specifically, and plenty of cluttered mailboxes hold none of it. Zero is not a smaller answer there, it is not an answer, so the panel drops the line the way the popup already did and gives the room to the count beside it.
- The selection pill lands on the tab it selects. It was drawn from different measurements than the row of tabs it sits behind, so it was slightly too wide and stepped slightly too short, and the error added up from left to right: the first tab's pill overhung by 3px and the last one fell 3px short. Both are built from the same two numbers now.
- A grouped custom rule gets the same warning a plain one does. Gmail treats
(in:inbox)and{in:inbox in:all}exactly as it treatsin:inbox, and the check that says "this rule has no age limit, so it will act on mail that arrived today" was only reading the plain form. The refusal that blocks genuinely unsafe rules already handled both. - Four more places that could read the wrong conversation list. While Gmail renders a search it leaves the previous list on the page for a moment. Version 8.25 kept the row lookups away from it. Left behind were the link that selects every conversation matching a search, the Unsubscribe control in an opened message, the check for whether a whole result set is selected, and the check for whether a page came back empty. Two of those hand back something the extension then clicks, and unsubscribing cannot be undone. None of them can reach the leftover now, and the shortcut that let them is gone from the file rather than avoided by habit.
9.2.0 - Be where the mailbox is
Everything this extension does has lived behind the toolbar icon, and Chrome folds that icon into the puzzle-piece menu until you pin it. So the mailbox report, the storage x-ray and the whole recovery net sat one click behind a button plenty of people never found. An install could go months without ever scanning anything, which is a strange thing to be true of a cleaner.
There is a small button in the corner of Gmail now. It draws inside a closed shadow root, so nothing it defines can reach Gmail's page, nothing on that page can reach into it, and the counts it shows are not readable by anything else running on mail.google.com. It reads no mail and walks none of Gmail's interface. The only thing it can start is the free read-only report, which is the same scan the popup runs and the one worth running first. Anything that moves mail stays in the popup, behind the confirmations that are already there.
The first mailbox you open after installing gets a greeting, once. After that the button sits closed until you click it, and it opens on whatever the last scan found.
Added
- A cleaner button in the corner of Gmail. Small, in the bottom right, and it opens a panel rather than doing anything on its own. Escape closes it. It never appears on a copy of the extension that was planted by other software rather than installed from a store, which is the same rule that keeps scheduled sweeps off those copies.
- The free mailbox report, started from inside Gmail. One click, the same read-only scan the popup runs, measured through the same safety switches so the counts describe what the popup's buttons would do. The panel then shows how many emails are old enough to clear, how many megabytes are sitting in old and large mail, and the three biggest steps by count.
- Cleaner button inside Gmail, on the Options page. A switch, on by default. The panel can also hide the button for 30 days, and turning the switch back on clears that too, because a switch that reads on while the button stays gone is a switch that lies.
Changed
- The panel refuses to start a scan when anything else is already running in that tab, and says so, instead of injecting a second engine on top of the first.
- The scan the button starts runs in the tab the click came from. Never "whichever Gmail tab is active": with two accounts signed in, that is how you measure one mailbox and report on the other.
- A finished report now records which signed-in mailbox produced it, as an account number and nothing else. The panel in Gmail shows a report only in the mailbox it was measured in, so a second account does not get shown the first one's counts under the words "this mailbox". Reports saved by earlier versions carry no such mark and are still shown, because that is what those versions did.
- Switching the button off, or hiding it, now reaches Gmail tabs that were already open instead of waiting for a reload. The Scan button in a panel that was open when the switch moved refuses rather than running.
9.1.0 - Say it before the click, not after
Three screens in this extension put a number next to a button. Each number is measured through your safety switches, and each button reads those switches fresh at the moment you press it. When you change one in between, the number stops describing the button.
The Mailbox Report learned to say so two releases back. Smart Suggestions learned it one release later. The sender census, added last release, shipped the half that records what it measured through and none of the half that checks. The record sat in storage with a note on it explaining what it was for and nothing read it.
That check is on all three now, and most of this release is that one idea applied everywhere it was missing.
The rest of it is about time rather than switches. Two of the lists this extension builds are made from your mail: the sender census, which is who fills your mailbox, and the unsubscribe receipts, which is who you asked to stop. Both hold real addresses, both sat here with no end date, and there was no button anywhere that removed them. There is one now, and the two stores age out on their own besides. They age out differently, because a census is a photograph and goes out of date, while a receipt is a record of something you did whose whole value is being old enough to prove a sender ignored you.
Added
- Erase Stored Sender Data, on the Options page. One button, with a confirmation that says what it takes and what it leaves. It removes the sender census, the unsubscribe receipt ledger, and the four lists of senders you have ticked in the census, storage, suggestion and subscription panels. It also names the consequence you would otherwise meet weeks later, which is that scheduled cleanups stop clearing the census senders you had ticked.
- A card on the Diagnostics page for what is stored. How many senders the census holds, how many receipts, how many senders you have ticked, and when each was last written. Counts and dates only: no address appears there, and none is copied by Copy Diagnostics.
Changed
- A census older than a month stops printing its counts. It keeps the list and your ticks. The numbers go, because the clear it feeds only takes mail older than six months, so every month that passes pushes more of that sender's mail across the line and the stored figure understates what a clear would take. Understating a delete is the one direction that costs mail, and this extension would rather say nothing than say it low.
- A census older than three months is not used at all. It stops being read, the senders you had ticked in it are dropped, and scheduled cleanups stop clearing them. That path had no upper bound before: a sender ticked last year still built a delete rule on every unattended sweep, off a census that had been replaced a dozen times since.
- An unsubscribe verdict past its recheck window is shown without its number. "Ignored your unsubscribe when last checked" rather than a count. That count was measured against a search anchored to the day your grace window closed, so read months later the same figure has quietly stopped answering "did they ignore me" and started answering "how much does this sender send". No receipt is ever deleted for its age: the date stays, and it stays in the queue to be checked.
Fixed
- The diagnostics Test Inject button no longer logs the Gmail tab's title and full address. A Gmail tab title contains your own email address and a search URL carries whatever you last searched for, and both went into the log that Copy Diagnostics puts on your clipboard. It logs the origin, the path, and whether the engine is attached.
- The census no longer promises a count it cannot keep. Untick Skip Unread after running the census and every row went on saying "Clear would take 12" while the button beside it would have deleted the unread mail too. The rows now drop the promise, the button drops its number, and a line appears saying the switches moved and the census should be run again.
- Sender sizes under a megabyte no longer read as zero. The Storage X-ray works in tenths of a megabyte everywhere it measures and everywhere it stores, and then rounded to whole megabytes on the way to the screen. On a mailbox of ordinary small mail that is most senders: a list of real names beside "at least 0 MB".
- The unsubscribe check no longer reports a sender as stopped when it just proved otherwise. A run whose only finding was a sender still mailing from the Spam folder finished with "All 1 stopped." The closing line counted one verdict and there are five.
- A sender that stopped and started again stays marked that way. The relapse was worked out from the previous verdict, and once a receipt was marked as a relapse the next check thirty days later no longer recognised it, wrote plain "still sending" over the top, and the fact you had watched that list go quiet was gone.
- "Clear their mail" says how much mail, and refuses when the answer is nothing. The button is scoped to what arrived after each sender's grace window closed, but your Minimum Age setting was still added on top, and mail cannot be both newer than two weeks ago and older than three months. The run opened Gmail, searched, found nothing and finished. The measured figure was already on hand and now sits on the button, which says which setting is in the way instead of starting.
- "Re-run for the rest" now reaches the rest. Both the census clear and the unsubscribe clear act on twenty-five senders at a time and neither remembered what it had already taken, so pressing again rebuilt the same twenty-five and sender twenty-six waited forever.
- A ticked sender that falls off the census list can be untangled. The ticks are remembered between sessions and feed the scheduled sweep, so a sender ticked once and then not measured again by a later census kept generating a delete rule with no checkbox anywhere to clear it.
- The check button says what one press checks. With forty receipts past their grace window it said forty and checked twenty-five, which is the cap the two buttons beside it have announced since they were built.
- The receipt list no longer shows one verdict less than the run found. The panel re-read the ledger the instant the run announced it was done, which raced the write of the last sender's answer.
- A suggestion carried over from an earlier scan is checked against the switches it was actually measured under, rather than the ones the most recent scan happened to use.
9.0.0 - Count what the button clears
The last release taught this extension to find the senders that actually fill a mailbox. It then printed the wrong number beside them. A sender would be listed with five emails, you would tick it, press Clear, and get nothing back.
The count came from a plain search for that sender. The button ran a narrower one: mail older than six months, skipping anything starred, important, unread, or filed under a label of your own. On a newsletter sender, unread alone is most of it. Both numbers were true. They were answers to different questions, and only one of them was the question you were asking.
Every count in this extension is now measured through the same filter as the button sitting next to it. That has been the rule here for a long time and the two features added last release were never held to it.
Added
- Every census row says what clearing it would take. The count still answers who fills your mailbox, because that is what the list is for. Underneath it now sits the other number: what the Clear button would actually remove from that sender today. When those two differ, the row says so, and when clearing would take nothing, the row says that too instead of letting you find out by pressing it.
- Senders who kept mailing you from the Spam folder. A Gmail search does not look in Spam, so a sender who ignored your unsubscribe but landed in the spam filter answered the check with a flat zero and the receipt read "Stopped". They had not stopped. There is a third answer now, and it is the one no other tool will give you, because it means saying the unsubscribe failed quietly. Nothing is deleted for this one: the extension will not point a delete at the Spam folder, where Gmail's own control means gone for good.
- Senders who stopped and started again. A list that goes quiet for a month and then comes back is the one you will never think to check, because you watched it stop. It used to be recorded as though it had never stopped at all. It gets its own line now.
- The census total, on screen. It was measured, it was saved, and nothing ever drew it.
Fixed
- Clearing a census sender does what the row promised. The count and the button ask Gmail the same question now. This is the bug above, and it is the reason for the version number.
- Your Never Delete list applies to the census. Neither of last release's two scans passed your whitelist or your protected keywords to the engine, so a sender you had explicitly protected was still ranked, still measured, and still offered with a tick box. Pro's deeper scan setting could not be reached from those screens either.
- The Storage X-ray stops rounding small senders down to nothing. The smaller size bands added last release credit about a tenth of a megabyte per message, and sizes were rounded to whole megabytes, so a real sender holding real mail was listed as "at least 0 MB". It keeps a tenth now, and rounds down rather than up, because the page says at least.
- A Google Chat tab is no longer mistaken for your mailbox. Chat lives on the same address as Gmail. With it open in front, Run and every scan quietly resolved to it, did nothing, and left a progress screen waiting on a run that never began.
- Buying Pro no longer leaves the census and the receipts locked. Whichever finished first decided what you saw, so a licence that verified a moment late left a paying user looking at the free version of both until they reopened the popup.
- Scheduled sweeps use the senders you ticked. They were described as extra rules on your ordinary runs, and the weekly unattended run, which is the one that matters most, was the only one not carrying them.
- A check that could not reach Gmail is retried, not shelved. If the very first check of a sender failed to get an answer, that sender was set aside for a month, while one that had already been answered was retried on the next sweep. Exactly backwards.
- The clear button on the receipts counts what it clears. It said how many senders had ignored you and then acted on the first twenty-five, without mentioning the rest.
8.26.0 - Find the bulk, not the buckets
Every scan in this extension used to describe your mailbox with a Gmail search written before your mailbox existed: promotions, big attachments, mail with the word unsubscribe in it, anything over a year old. Those find mail that fits a bucket. Most mailboxes are not buckets. They are tens of thousands of ordinary small messages from a few dozen senders, and no search on that list names them, so every tool reported a small number and did a small thing.
Tested against a real mailbox while this was built: promotions older than six months returned nothing. Mail older than two years returned nothing. Two broad searches found sixty senders.
Added
- A census of who actually fills your mailbox. It samples widely first, sliced by age and by whether you ever opened the mail rather than by category, then counts each of the senders that keep coming up with its own Gmail search. So the number beside a name is Gmail's answer about that sender, not a guess from one page of results. The list is free. Clearing the senders you tick is Pro.
- Unsubscribe receipts, and a check that they were honoured. Gmail now has its own unsubscribe button, and like every unsubscribe tool ever made it sends the request and greys out the row. Nobody goes back to find out whether the sender stopped. Plenty of them do not. Each unsubscribe you run here is now dated, and once a sender has had two weeks to act on it, Pro checks whether anything new arrived. The ones that ignored you get a button that deletes only what they sent after their window closed.
- The senders you tick keep getting cleaned. A ticked census sender becomes an extra rule on your ordinary runs, so a weekly sweep keeps clearing the senders your mailbox is actually full of. Only senders you ticked, never the whole census.
- Ask for a feature from the Options page. It opens a pre-filled email in your own mail app. Nothing is sent by the extension, which still makes no network requests of any kind.
Fixed
- The Storage X-ray looks below 5 megabytes now. It only ever searched for mail over 5 MB, which finds a few video attachments and misses everything a mailbox is made of. On the account this was tested against: 8 messages over 5 MB, 36 over 1 MB, and more than Gmail would count over 100 KB. Two smaller size bands were added, and the purge button underneath moved with them, so the button still clears exactly the mail the list counted.
- A size written in bytes is read as bytes. Gmail's own help writes sizes as plain numbers of bytes. A custom rule written that way had its storage estimate read as megabytes instead, so one rule could inflate the freed figure at the end of a run by millions.
8.25.0 - Say it when it is a floor
8.24 taught the Mailbox Report to admit when Gmail had given it a page instead of a total. Three other screens were still stating the same kind of number flatly, and one of them is Dry Run, which exists to be believed before you delete anything.
Fixed
- Dry Run says "at least" when it means at least. A preview reads Gmail's own count, and on a relevance-ranked search Gmail does not give one, so the preview was quoting the fifty rows on screen as the size of a rule holding thousands. The number has not moved. The preview now tells you when the number is a floor, on the popup, on the progress dashboard and in the sentence at the end of the run.
- The report stopped inventing a figure for the mail your guards hold back. That line is one search minus another. Either search can come back without a total, and then the subtraction is wrong in whichever direction the missing number fell. It could claim eleven thousand protected emails from a page of fifty. It could also claim none at all on a mailbox holding thousands back. It now says nothing rather than guessing.
- The plus sign is explained in words. A step reading 50+ said what it meant only if you hovered it, which is no help on a phone or from a keyboard. The note under the report spells it out whenever there is one on screen.
- The Storage X-ray counts what it saw. The megabytes have always been marked as a floor and the email count beside them was not, even though both come from the same sample.
- Long runs slow down properly on Traditional Chinese Gmail. When Gmail asks for a pause it says so in words, and the cleaner knew two of the three Simplified phrasings and only one of the Traditional ones.
Safety
- Rows are only ever read from the list you can see. Gmail leaves the previous search results in the page after a new search. A handful of lookups could still reach that leftover list while Gmail was redrawing. They are the lookups that tick the checkboxes a delete acts on, name the senders in your recovery log, and pick the message an unsubscribe is driven from. Unsubscribing cannot be undone. None of them will read anything but the live list now.
Changed
- Small text is readable where it sits. The quiet grey used for hints and secondary links was measured against the plain card. Most of the controls wearing it paint a slightly lighter chip under themselves first, and against that it fell under the readability bar. Six places were writing in a colour picked for a different background: the keyboard hint on the Save button, the Save button itself in light mode, the diagnostics buttons, the Pro line on the Rules page and the privacy link on the Clean tab.
- Storage figures drop the pointless decimal. The X-ray rounds every sender to a whole megabyte, so "900.0 MB" was one digit of precision the scan never had. A real tenth still shows.
8.24.0 - Fifty is not a total
Gmail sorts most searches by relevance now, and when it does that it stops saying how many conversations matched. The pager reads "1-50 of many". The cleaner fell back to counting the rows it could see, which is fifty, and printed that as the answer.
So the Mailbox Report, the screen the store listing tells you to run first, showed 50 beside a step holding thousands. Two mailboxes with wildly different amounts of old mail in them got the same report.
Fixed
- A count Gmail will not total is shown as a floor. A step reading 50+ holds at least fifty and probably far more. Nothing is guessed and no number went up: the plus sign is there because the cleaner can see one page and will not pretend otherwise. Hover it and it says so.
- The headline says "at least" when it means at least, instead of quoting one page of your mailbox as the size of it.
- The Pro line stopped understating what Pro clears. It names one step's count, and that count was the same fifty.
- Suggestions stopped calling every sender 100% unread. A suggestion works out how much of a sender's mail you never open by dividing one search by another, and both searches were coming back as one page, so any sender past fifty messages looked untouched. Unsubscribing cannot be undone, so it is no longer suggested off a figure the cleaner could not measure. Deleting old mail and archiving still are, and Gmail keeps both somewhere you can get them back from.
- Bulk delete works on Traditional Chinese Gmail. Rather than clearing fifty at a time, the cleaner takes Gmail's offer to select every match, and it finds that offer by name. It knew the Simplified spelling of "select all" and not the Traditional one, so on a zh-TW or zh-HK mailbox it never found the offer and crawled the results a page at a time.
- Selecting everything now finds the list on screen. Gmail leaves the previous search results sitting in the page where you cannot see them. When the cleaner's usual way of ticking rows does not work and it falls back to Gmail's own select-all checkbox, it was finding the leftover list's checkbox first, selecting nothing you could see, and then reporting that Gmail's layout had changed.
None of these numbers moved. The report counts what it always counted; it now tells you when what it counted was a page rather than a total.
8.23.0 - It says what it is doing
The Mailbox Report, the Storage X-ray scan, the subscription scan, the suggestion scan and bulk unsubscribe all work inside your Gmail tab, and the popup closes the moment you click anything outside it. So the natural thing to do, click into Gmail to watch, took away the only thing telling you a scan was running. Reopening the popup showed a window with nothing happening in it while your mailbox was visibly being searched.
Fixed
- The popup now says a scan is still going. It asks your Gmail tabs directly rather than looking for a marker, because these runs deliberately never book your mailbox the way a cleanup does. The banner names what is running, so a scan that is only reading is not confused with an unsubscribe that is changing things, and it says the part that matters: you can close the popup, the run keeps going, and the result will be waiting when it finishes.
- The banner clears itself when the run ends, instead of sitting there claiming to be reading a mailbox it already finished reading.
- Reset now aims at the run that is actually going, in whichever Gmail tab it is in. With more than one account open the button had nothing to aim at, so there was no way to stop a scan short of reloading the tab.
The progress dashboard is deliberately not offered for these runs. It is built for cleanups, and the recovery button on it re-injects the last cleanup settings, which is not a thing that should ever be one click away from a read-only scan.
8.22.0 - It counts the list it is looking at
Gmail changed how it draws search results, and it stopped clearing the previous list away. The list you were looking at before the search stays in the page, invisible, with its own counter still attached to it. The cleaner was reading that counter.
Fixed
- The Mailbox Report was counting your Inbox instead of the mail it was reporting on. When Gmail declines to say how many conversations a search found, and on the current Gmail it usually declines, the cleaner looks further down the page for a number. What it found was the leftover counter belonging to the list that had been on screen a moment earlier. Checked against a real mailbox: five of the six report steps came back with the same figure, the size of the Inbox, and two of those five had no matching mail at all. A report like that is worse than no report, and it is the first thing most people run. Every count now comes from the search it belongs to, or it is reported as unknown.
- The "this will delete about N conversations" warning works again. That warning is there for the case where Gmail will not state a total. A number borrowed from another list looked like a perfectly good total, so the warning had nothing left to fire on.
- A subject line still cannot be mistaken for the results counter. 8.21 stopped the cleaner taking a number out of the message list. That protection was written around one list, and the page holds two now, so it was guarding the wrong one. It covers both lists and the container around them.
- Selecting row by row no longer ticks the wrong list. When the select-all checkbox does not take, the cleaner falls back to ticking each row itself. It was ticking rows in the leftover invisible list, so nothing on screen ended up selected, which the cleaner reads as "Gmail has changed underneath me" and stops. The fallback that exists to rescue a run was making sure it failed.
8.21.0 - It reads the mailbox, not the mail
Fourteen fixes. The one that matters most: on a Japanese, Korean, Chinese, Russian, Arabic, Swedish, Danish, Norwegian, Polish, Turkish, Dutch, Italian, Spanish or Portuguese Gmail, the cleaner could not use Gmail's "select all conversations that match" offer at all, so big cleanups crawled fifty at a time and gave up with most of the mail still there. That is fixed for every language the cleaner speaks.
The rest are mostly the same shape twice over: a number read out of your mail instead of out of Gmail's own toolbar, and a guard that had been added in one place and not in the identical place next to it.
Fixed
- Bulk cleanup works in every language now. When a rule matches thousands of conversations, Gmail offers to select all of them at once, and taking that offer is what turns an hour of paging into one action. The cleaner only recognised that offer in English, German and French. Everywhere else it never saw it, so it deleted a page at a time until it hit its own pass limit and stopped, leaving most of the mail behind. It now recognises the offer in all seventeen languages it drives Gmail in. Spanish and Portuguese were doubly affected: the wording it looked for did not allow for Gmail naming the number in the middle of the sentence, which it always does.
- A subject line can no longer be mistaken for the results counter. When Gmail will not say how many conversations a search found, the cleaner reads what it can off the page. It was willing to take that number from an email in the list, so a promotional subject like "Sale 10-20% off: 5000 items left" could be read as the size of the job. That number is what the "this will delete about N conversations" warning is based on, so a wrong one meant no warning at all. It only reads Gmail's own counter now, and it will not read one out of a message.
- Nor for a selection count. The same shape, one step over: a subject like "You have been selected for 3 free rewards" was read as "3 conversations are selected". That mattered because a count of zero is how the cleaner notices Gmail has changed its layout and stops with a clear explanation. With a number invented from a subject line it carried on instead, clicking Delete on an empty selection and retrying every rule until it ran out of attempts.
- Escape in the log filter no longer cancels the cleanup. The progress page has a "Filter logs" box. Typing in it and pressing Escape to clear it, which is what Escape does in every search box, stopped the run instead. Escape still closes a dialog and still cancels from anywhere else on the page.
- A scheduled cleanup will not pick up your Chat window. Gmail serves Chat from the same address as your mail. An unattended cleanup chose whichever of those tabs you were looking at, so if you were chatting when the timer fired, it took that tab, navigated it away from your conversation mid-sentence, and then could not finish. The run was recorded as done, that week's cleanup never happened, and for the next two hours every manual run was refused with "a cleanup is already running". Only real mailbox tabs are used now, and the account picker no longer offers a Chat window either.
- A preview says what it found. The desktop notification after a dry run was headlined "0 emails moved to Trash", because a preview does not move anything. Auto-Pilot's first sweep is a preview by design, so this was the first thing it ever said to a new Pro user. It reports what the preview found.
- A cleanup that skipped some rules says so, even when it cleared others. An unattended run skips a rule too large to run without asking, which is right. If it cleared nothing at all it said so, but if it cleared some it just reported the total, and rules holding tens of thousands of messages went unmentioned. The notification is the only thing an unattended run can tell you, so it now says both.
- The Storage caveat is shown before you pay, not after. The storage scan measures large mail of any age. The purge only takes mail older than six months, and the sentence explaining that difference was only shown to people who had already bought Pro. Everyone else saw the big reclaimable figure, the sender list, and the Purge button with nothing to say the two numbers are not the same number.
- The Auto-Pilot pitch counts what Auto-Pilot can actually do. It led with the number of suggestions on screen and offered to sweep "them" every week. It only ever sweeps the delete and archive suggestions, so nine on screen could mean two swept. It now counts the ones it will take.
- A suggestion stops promising a count once you change your safety switches. "Deletes 40 now" was measured when you ran the scan. Turn off Skip Unread afterwards and the button would reach far more than 40. The suggestions now notice, say your switches have changed, and stop quoting a figure until you scan again, exactly as the Mailbox Report already did.
- The "held back by your guards" note no longer exaggerates. It counted every message a sender had ever sent, when what the guards actually held back was the smaller set the suggested action would have touched.
- "Rate 5 stars" opens one store, and the right one. On Firefox it opened two tabs, one of them the Chrome Web Store.
- Six more things are readable in the light theme. The "Show guards" button on the Report tab was invisible. So was the confirmation on "Force reset", the name of a second mailbox when you have two Gmail tabs open, a step blocked by Safe Mode, a step you have already cleared, and every scheduled cleanup row on the Options page, including whether it is switched on. All of these only appear in situations a quick look at the extension never reaches, which is why they lasted this long.
- A notification setting that fails to save says so instead of looking as though it saved.
Changed
- Norwegian mailboxes get Norwegian search terms whether Gmail reports the language as
nb,nnorno. - The privacy policy now describes the page your browser opens when you uninstall. Nothing about that page changed: it carries no information about you or your mail, and it has been described in the security notes since 8.9. It should have been in the policy too.
- The popup no longer allows a font server it never used in its content security policy.
- The Duration shown after a run is how long the run took. It used to be how long the progress page had been open, so opening it late, or reloading it, gave a smaller number.
- The Stats page stops replaying its opening animation every thirty seconds. The charts were collapsing and regrowing, and the totals were counting up from zero again, twice a minute.
8.20.0 - Skip means skip, and done means done
Eight fixes. Most are the same complaint wearing different clothes: a button, a message or a report told you something had happened when it had not.
Fixed
- "Skip This Rule" skips, even from the keyboard. In Review Mode the cleaner stops before a batch and offers you Proceed or Skip. Tab to Skip, press Enter, and the batch got cleaned anyway. A keyboard shortcut on the page was answering Enter before the button could, and it always answered Proceed. The buttons speak for themselves now. Pressing Enter without moving focus still proceeds, which is what the shortcut was there for.
- A run that refused a rule no longer calls itself finished. A scheduled cleanup will not stop and ask you about a very large batch, because there is nobody there to answer. It skips that rule and moves on, which is right. What was wrong is that the run then reported itself complete. Auto-Pilot printed a partial tally as the week's work with nothing to say it had skipped anything, and the senders it never got to were booked as dealt with, so they stopped being suggested. A refused rule leaves mail behind, and the run says so now.
- An Auto-Pilot sweep that stops or fails gets recorded. Until now it simply vanished. The panel went on quoting last week's number as though it were the latest one, and the weekly timer lost its place and could fire again a minute later. The sweep is recorded either way now, and one that stopped early says so.
- Unsubscribes are saved as they happen. They used to be held until the run ended. Close the Gmail tab halfway through and you lost every one of them: no marks on your list, nothing in your totals, no way to tell which senders you had already done. The most a closed tab can cost you now is the one in progress.
- A sender you have already cleaned stops pushing itself to the top. Cleaning a sender gives a small nudge to others at the same domain, which is the point. It was also nudging that sender, for ever, above senders nobody had touched. So the same handful sat at the top of your suggestions and at the front of every weekly sweep.
- "Schedule removed" and "Log cleared" only appear when they are true. Both were shown whatever happened. A schedule that failed to delete stayed where it was with its timer still running, and a recovery log that failed to clear kept every entry. Both say plainly now when the change did not go through.
- The cleaner tells you when it cannot read your saved rules. If Chrome will not hand over your stored settings, the run falls back to the built-in rules for that level. That is the sensible thing to do, and it used to do it in silence. It says so now, for your rules and for your custom rules separately.
- Two more places are readable in the light theme. The "Restore Default Rules?" confirmation had a fixed dark panel behind theme-coloured text, so Cancel was invisible and the only readable choice was the destructive one. The tooltips on the Diagnostics page had the same problem (they only appear on hover, which is how both went unnoticed for so long). Both follow the theme now. They shift a little in the dark theme too, because they use the shared surface colours instead of their own.
8.19.0 - Things that happened while nobody was watching
Four fixes, and three of them are the same problem: the extension worked out something true and then wrote it down somewhere that stops existing the moment you look away.
Fixed
- Your three free unsubscribes are counted properly now. They used to be counted by the popup, and a popup closes the instant you click anything else. An unsubscribe run opens one message per sender, so most runs finished with the popup already gone and the count never moved. If you clicked into Gmail to watch it work, you kept getting three. The count is kept by the background worker now, which is still there when the run ends. Nothing else changed: only senders that really came back unsubscribed cost anything, and a sender with no one-click link is still free.
- Stopping an unsubscribe run no longer throws away what it already did. Cancel at the eighth of ten senders and the seven that were genuinely unsubscribed went unrecorded: no marks on the list, nothing in your totals. You cannot un-unsubscribe from a mailing list, so those are worth keeping, and they are kept now. They do count against the free three, because they happened.
- A rule that Gmail throttled for too long is reported as unfinished. The cleaner gives up on a rule after five minutes of rate limiting and moves to the next one, which is the right call, but the run then reported itself as complete. That let the Mailbox Report mark the step Cleared and take away its Run button, the Storage X-ray mark a sender Purged, and a suggestion stop being suggested, all over mail that was still there. Two of the three ways a rule can stop early already said so. The third does now.
- Small text on coloured chips is readable in the light theme. A chip tints its own background, so its label was landing on a ground its own colour had already darkened. Every tag, the PRO badge on an active licence, the Cleared mark on a report step and the Apply button on a suggestion were below the readable-contrast bar. They are all above it now, in both themes, and the dark theme looks exactly as it did.
Internal
- The check that keeps Trash, Spam and starred mail out of a bulk delete had a broken escape in it. Nothing was getting through, because none of the terms it guards needs escaping, but the first one that did would have slipped past in silence.
8.18.1 - The privacy policy lives with the source now
Changed
- The Privacy policy link opens the policy in this repository instead of a page on another site. Same policy, same effective date, now version-controlled alongside the code it describes, so a change to what the extension does and a change to the document saying so land in the same commit. The terms of use moved with it.
- The first claim in that policy is that the extension makes no network requests, and the policy now shows you the one-line command that checks it for yourself.
8.18.0 - A calmer popup, and motion that means something
The Clean tab showed thirteen things at once while every other tab showed three or four, and the six controls at the middle of it were one decision pretending to be six. They are drawn as one group now. Nothing was removed and nothing was hidden: the safety and privacy lines still sit right under the button they describe, where they have been since 8.7.
The rest is motion, and the point of it is that the parts you drive now respond. Switching tabs, a scan filling a list, a count landing, a button being pressed: all of those used to happen between one frame and the next. The parts that already animated were mostly the parts nobody touches.
Added
- The tab bar has one indicator that slides between tabs, so the selection travels instead of blinking out on one tab and in on another.
- Scan results arrive a row at a time. Thirty senders appearing in a single frame reads as a flash; the same thirty arriving over a third of a second reads as a result.
- The Mailbox Report's headline count rolls up to its total, as do the four figures on the Stats page.
- Buttons press. They compress quickly under the pointer and spring back, rather than changing colour and nothing else.
- A run with no count yet shows a moving bar instead of an empty one. An empty bar and a stalled run looked the same.
- The daily-activity chart animates. It always carried the instruction to and never once obeyed it: the bars were sized before they were on the page, so there was nothing to animate from.
Fixed
- The skip link on the progress page was almost invisible. White text on the cyan background measured 1.81:1, and that link exists only for people navigating by keyboard or screen reader.
- Half of the Cancel button was unreadable. Its background faded from a light red where the white label measured 2.77:1. Both ends clear 4.5:1 now. It is the button that stops a run, so it should be the easiest one to read.
- The scan buttons were the wrong blue in the light theme. They hardcoded the dark theme's bright cyan, so on the light theme three of the four tabs had a neon edge on a white card.
- Chart bars can be read without a mouse. They are focusable and announce their date and count, instead of showing it only on hover.
- Settings had one panel with a border that never drew, because it named a colour that does not exist.
- Reduced motion now also switches off the row-by-row timing. Without that the new stagger would have survived as a flicker for exactly the people who asked for less movement.
8.17.0 - Three free unsubscribes so you can see it work
Bulk unsubscribe is the one paid feature you cannot try with a Clean-tab rule. You could scan, tick the senders you hate, and then hit a paywall for something you had never seen work. Every unpaid install now gets three real unsubscribes on its own mail, once. After that the usual paywall takes over, and it can name the number you just watched be real.
Added
- Three free unsubscribes, once, for the life of the install. The Lists tab says how many you have left before you click. Only senders that actually unsubscribe count against it. A cancelled run, a failed run, or a sender that needs their website costs you nothing. When the three are used up, Pro is what it was.
- The three are spendable from a Smart Suggestions card too. There are two places to unsubscribe from one sender, and three free ones now mean three in both. Spending one from a card says so as it goes, and the count on the Lists tab moves with it. Bulk apply is still Pro: one card is not bulk.
8.16.0 - Runs that stopped are not runs that finished
A tidy-up release, and most of it comes from one thing being true in more places than anyone had noticed: pressing Cancel, or a rule running out of room, left the extension believing the job was done. The other half is a batch of settings pages that could paint an empty list when storage had a bad second, and then save it.
Fixed
- Cancelling a cleanup marked the work as finished. Stopping a run half way still ticked the Mailbox Report step off as Cleared, still stamped senders as Purged on the Storage X-ray, and still counted a suggestion as applied. The Cleared badge also takes that step's Run button away, and on the free plan that is the one step you have, so cancelling could cost you it. A run that errors out did the same. All four of those marks now wait for a run that really finished.
- A run that ran out of room said nothing afterwards. A single rule can hold more mail than one run can get through, and Gmail sometimes slows a rule down until the extension gives up on it and moves on. It says so at the time, in the progress log, and that was the only place it ever said it: the result screen still read "Cleanup Complete!", the desktop notification still read like a finished sweep, and the Mailbox Report ticked the step off. The result screen, the recap, the notification and the Auto-Pilot line now all say a rule stopped early and that running it again carries on where it left off.
- The number of emails a search had found could be read off your mail instead. The extension looks for Gmail's "1-50 of 12,438" counter to size a run. It searched the message list before the toolbar the counter actually sits in, and accepted any short text with "of" and a number in it, so a subject line like "Part 3 of 12" or "Best of 2024" could stand in for the total. That number is what the Mailbox Report shows against every step, what Smart Suggestions ranks senders by, what Dry Run quotes and what the too-big-to-run-unattended check is measured against. It reads the toolbar first now, and only accepts text shaped like a real counter.
- The Settings page could save an empty Never Delete list over your real one. If reading your synced settings failed for a moment, the page drew empty lists, said "Settings loaded", and treated that emptiness as your settings. Pressing Save then wrote it. The page now refuses to draw or save anything until it has actually read what is there, and says so. Exporting and importing refuse on the same page state: a backup built from lists that were never read would record an empty Never Delete list as your settings, and an import cannot be undone when the storage its rollback needs is the storage that is failing.
- Pro: opening Settings during a storage hiccup could reset four of your Pro settings. The card drew the defaults, took them as your current values, and wrote all six back the moment you changed one. One of them decides how much of your recovery log is kept, so a 300 entry log was trimmed to 60 on the next run and runs you could still have undone stopped being restorable. The card now stays blank and locked rather than showing values that are not yours.
- Pro: Auto-Pilot could switch itself off in the middle of a sweep. If reading its settings failed while a sweep was finishing, "off, and not yet confirmed" was written back over your real settings. The weekly timer kept firing and nothing happened, the switch read as off, and turning it back on dropped it to preview mode until you found the confirm button again. The same read failure at browser startup deleted the weekly timer for the whole session while the switch still showed as on.
- Importing a settings file with no whitelist in it emptied yours. Custom rules, protected keywords and schedules were all left alone when a file did not carry them. The whitelist, which is the one that decides what never gets deleted, was overwritten with nothing.
- Vacation mode could be ignored by the runs it is for. If the extension could not read whether you had snoozed, it treated that as "not snoozed" and let the scheduled and Auto-Pilot sweeps go ahead. Unattended work now waits when it cannot tell.
- Snooze reported success whether or not it saved. The Settings page said "Schedules snoozed 14 days" without checking, so a write that failed left the sweeps running with nothing to suggest it.
- Clearing the recovery log could be undone by a run finishing beside it. The two writes were not queued against each other, so a cleanup that finished at that moment put every entry back.
- Traditional Chinese: cleanup could not find the Delete button. The extension knew the Simplified Chinese word and not the Traditional one, which are different characters, so a run selected the mail and then stopped, having done nothing. Archive and labelling already knew both.
- Safe Mode did not shield receipts in six languages. Swedish, Danish, Norwegian, Polish, Turkish and Arabic mailboxes were checked against the English words only, and Traditional Chinese against the Simplified ones, while Safe Mode reported itself as on. Norwegian is covered whichever of the two language codes Gmail uses.
- "Find in Gmail" in the recovery log searched for nothing. Every recovery label has a space in it, and the link did not quote it, so Gmail searched for a label that does not exist and showed an empty result next to a Restore button that would have worked.
- A refused cleanup left the popup looking like a live one. Starting a cleanup while a scan was still running is correctly refused, but the popup kept the running status, the Cancel button and an Open progress button that handed back a finished dashboard for somebody else's run.
- Five refusals on the scan buttons were in English only. The one that matters most tells you to allow Gmail access, which is the single thing that fixes it. Every other copy of the same sentence in the popup was already translated.
Changed
- Very long searches say so. With a big whitelist and a long list of protected keywords, the search the extension builds can get long enough to be worth trimming, and the exclusions are the part on the end. A run now says so once, and names the two lists to trim.
- The Pro panel counts its own history correctly. It said buyers from the first version got the four features that came after. There have been five.
- The Settings page stops selling something that is already free. It described the full Storage X-ray as part of Pro. The list of what is filling your mailbox has been free since 8.13; the one-click purge under it is the paid part. Pro Settings was missing from the same sentence.
8.15.0 - Quality of life, and the safety lists that would not say no
A tidy-up release. Most of it is small things that were quietly in the way: steps you had already cleaned that would not offer to run again, lists that made you scroll to find out what you could still undo, and a Pro setting that did not do what it said. One fix underneath all of that matters more than the rest, and it is the first one below.
Fixed
- A cleanup could run with your Never Delete list missing. Your whitelist and your protected keywords are read when a run starts and handed to the cleaner, which is the only way it knows to leave that mail alone. If either read failed for a moment, and storage does fail for a moment sometimes, the answer came back as an empty list rather than as an error, and the run went ahead with nothing protected. The popup, the progress page and the recovery log all reported an ordinary successful cleanup. A run and a scan now stop and say so instead.
- A step you cleaned part of the way was marked Cleared for good. A big step can stop part-way, and the cleaner says so at the time: "run the cleaner again to continue this rule." The Mailbox Report ticked it off anyway. The row kept showing thousands of emails with a Cleared badge and no Run button, "Run the whole plan" skipped it, and nothing ever put it back. The badge now means the step is empty, so a fresh scan that still finds mail there gives you the button back.
- A second Gmail account could be told to stop by the wrong window. With two mailboxes open, a finished progress dashboard left open for the first one joined in on the second one's run: it filled its table with the other account's rows and raised the other account's confirmation. Answering on that window sent the answer to a run that was already over, so the live one waited, gave up and stopped after you had clicked Continue. Each dashboard now only listens to its own Gmail tab.
- Clear stuck run could start a fresh cleanup a minute later. That button clears the flag that says a cleaner is attached to the tab, and the dashboard reads that same flag when it decides whether to reconnect a run that has gone quiet. So pressing it and walking away looked like a cleaner that had vanished mid-run, and one was started again, from whatever settings ran last. The dashboard now treats a cleared run as over, and it will never re-inject on a page that has not heard from a run at all.
- An imported schedule never actually ran. Importing a settings backup wrote the schedule and showed it as Enabled, but nothing told the extension to set the timer, so the unattended cleanup sat there doing nothing until the next time the browser restarted. Import now sets the timers, and the list on screen updates to match.
- The account picker could name the wrong mailbox. With two Gmail tabs open it always highlighted the first one, while a run went to whichever mailbox you were looking at. The other half of the same split: choosing an account and then having any run finish, including a scheduled one you did not start, threw the choice away while the highlight stayed put.
- A backup with more rules than the extension stores said nothing about the ones it dropped. Version 8.14 fixed this for the whitelist and the keywords. Rules were still counted in a way that hid it, because the missing categories get filled in from the defaults.
- The summary after an archive run said your mail went to Trash. An archive run that found nothing to move was filed as a deletion, so the popup offered to reassure you about a 30 day Trash window for mail that was never deleted.
- Auto-Pilot could start a sweep just after you turned it off. Between the weekly timer firing and the sweep starting there is a second or so of checks, and switching Auto-Pilot off inside that gap was missed. Your mail was never touched, that part was already guarded, but the scan still ran and your Gmail tab still churned through it.
Changed
- Pro: 50 senders per Auto-Pilot sweep now clears 50. The setting chose the senders correctly and then built the sweep from the first 25 of them, so picking 50 cleared exactly what 25 cleared. 10 and 25 were never affected.
- The recovery log says how long you have left. Every deleted run now shows the days remaining before Gmail empties that mail out of Trash, while there is still time to do something about it, rather than only explaining itself once the deadline had passed.
- Cleanup results say when the space actually comes back. Deleting moves mail to Trash and Google keeps counting it until Trash empties, about 30 days later. The result screen and the progress dashboard now say so, so a storage bar that has not moved yet is not a surprise.
- Cleaning by sender or by inbox gets a name. Those runs were all labelled "Other" in Gmail, in the recovery log and on the Stats page, which made a weekly Auto-Pilot sweep hard to tell from anything else. They are labelled Senders and Inbox now. Runs that already had a name keep it exactly as it was.
- Protect on the Stats page knows who is already protected. It offered itself on every sender, including ones your whitelist already covers, and reported adding a duplicate as a fresh success. Senders already covered now show as protected instead.
- Bulk unsubscribe stops re-doing senders it has finished. Ticks are remembered between sessions, which is right up until a run settles a sender: after that every later run started with them ticked again and spent part of its 25 sender budget repeating itself. Senders that still need their own website are marked and left out; senders where Gmail's control simply could not be found stay available to retry.
- Pro Settings warns before you lose an edit. That card saves on its own button, and it was the one part of the Settings page that could be changed and closed without a word.
- The scheduled cleanup rows announce themselves properly. Their enable and remove buttons read as a state word and a punctuation mark to a screen reader, identically on every row, for controls that change and delete an unattended cleanup with no confirmation step.
8.14.0 - Imports that say what they drop, and a recovery log that stays put
A tidy-up release. Nothing new to learn: importing a settings backup now tells you the truth about what it kept, your recovery log stops shrinking when it should not, and buying Pro updates the page you are already looking at.
Fixed
- Importing a settings backup no longer drops entries quietly. The confirmation counted what was in the file, but the extension stores at most 100 whitelist entries, 50 rules per level and 25 protected keywords, and it skips anything it cannot read, such as a mistyped address. So a backup with 150 whitelist entries asked about 150, kept 100, and finished with a plain "imported successfully" - and the 50 senders that fell off were 50 senders whose mail was no longer protected from a cleanup. The confirmation now counts what will actually be stored, spells out anything that will be dropped, and says so again once the import is done.
- The recovery log stops trimming itself when it cannot check your key. With Pro you can raise the log from 60 entries to 300, and the cap is applied every time a run is recorded. If the licence check could not complete at that moment, for instance because storage was briefly unavailable, it was read as "no licence" and the log was cut back to 60 on the spot. Those entries are how one-click Restore finds an old run, and they were not coming back. The log is now left alone whenever the answer is not certain.
- The daily stats cleanup can no longer erase a cleanup that finished beside it. Once a day the extension drops day counters older than 90 days. If a run finished while that was in progress, the tidy-up could write back what it had read a moment earlier, taking the run's totals and its entry in the Stats history with it - including the Restore button attached to that entry.
- The version announced to screen readers on the popup was four releases out of date. The button showed the right number; the label read aloud did not.
Changed
- Activating Pro updates a Settings page you already have open. Buying in one tab and having Settings open in another left the second one showing "Get Pro" and a locked Pro Settings card until you reloaded it. It now notices, in both directions: removing your key elsewhere locks the card again.
- The Pro line on the completion notification has a limit. It was appended to every qualifying run, so cleaning your mail daily meant a daily sales line in a desktop notification, with no way to stop it except turning completion notifications off entirely. It now waits a week between showings and stops after three.
- The Pro summary in the popup names all six paid features. It had been listing three of them since two more shipped.
8.13.0 - The whole storage list, and one-click activation
A smaller release. The Storage X-ray stops hiding most of what it found, buying Pro no longer means copying a long key by hand, and the Pro Settings card gained three more knobs.
Changed
- The Storage X-ray shows every sender it ranked. The free scan listed the top three and counted the rest behind a line about Pro. That scan is read-only and the numbers in it are your own mailbox, so there was never a good reason to hold most of it back. The whole ranked list is free now. The one-click purge underneath it is still the paid part.
- The rating prompt asks more than once. It used to appear after one good cleanup and then stay quiet for 90 days if you picked "Maybe later", which in practice meant most people were asked exactly once ever. It now appears after any cleanup big enough to be worth asking about, with three limits: never on your first run, nothing for three days after you decline, and nothing ever again after three declines or one press of the new "Don't ask again".
- The completion notification mentions Pro if you do not have it. One line, appended only to a run that really cleared mail, and never shown to anyone with a key. Desktop notifications are off unless you turned them on, and turning them off again stops this too.
Added
- Activate Pro in one click. The page you land on after checkout, and the key recovery page, can now hand the key straight to the extension instead of asking you to paste it into Options. This works in Chrome and Edge; Firefox does not support the mechanism, so it still shows the key to copy, exactly as before. Two things make it safe to have at all: the extension accepts messages from gmail-cleaner-pro.netlify.app and from nowhere else, and any key that arrives is checked against the same public key built into the extension before it is stored, so a web page cannot grant itself Pro.
- Three more Pro settings. How many senders one Auto-Pilot sweep clears (10, 25 or 50; it was fixed at 25). An age floor for unattended runs only, applied on top of everything else and only when it is stricter, so it can narrow a sweep and never widen one. And how many entries the recovery log keeps before the oldest fall off (60, 150 or 300; it was fixed at 60, and a bigger log means a run stays restorable for longer). All three default to exactly what 8.12 did.
- A 30-day money-back guarantee on Pro. Worth saying plainly: a refunded key keeps working. Keys are verified on your device with no network call, so there is nothing to switch off remotely, and adding that would mean the extension phoning home.
- A Pro card on the Stats page, for people without a key. It quotes the totals already on that page and disappears once a key is activated.
8.12.0 - The views mail does not come back from, and settings for Pro
Two halves. The first closes the ways a cleanup could reach Trash and Spam, which are the only two places in Gmail where deleting is permanent and where nothing this extension does can get your mail back. The second is a new Pro Settings card: three things buyers have asked to control, none of which take anything away from the free version.
Fixed
- Trash and Spam could be reached by a spelling the refusal missed. A rule scoped to Trash or Spam has been refused since 8.8, because in those two views Gmail's delete button means Delete forever and the recovery label this extension writes cannot help you. That refusal only ever covered one way of writing it. Gmail also accepts
label:trashandlabel:spam, which sailed through, andin:anywhere, which covers both and needed nothing but a date to pass every check. All three are refused now. If you have a rule using one of them it will be refused with a message rather than run; plainolder_than:searches already leave Trash and Spam alone, so that is the rule to use instead. - The button the cleaner presses could have been Delete forever. Every part of this extension that restores mail has refused a control labelled Delete forever since 7.6, before it even scores the candidates. The part that deletes had no such check, and its own pattern matches the words "Delete forever" perfectly well. It now refuses it too, in all twenty-one languages the restore side already covered, so even a Gmail redesign nobody predicted cannot hand it that button.
- The biggest cleanups were the ones measured at a single page. When a search matches more than fits on screen, Gmail offers to select every match, and this extension takes that offer. To size the confirmation you get, it then reads Gmail's "1-50 of 3,200" counter. On very large result sets Gmail does not print a number there at all, it prints "of many", so the count came back empty and everything fell back to the fifty rows on screen: no large-run confirmation, a Dry Run quoting fifty for a sweep of forty thousand, and a receipt to match. It now also reads the total out of Gmail's own "Select all 9,000 conversations" offer, which names it in every language. If neither can be read, the run is treated as too large to do quietly, and asks.
- Safe Mode only protected receipts written in English. Safe Mode skips receipts, invoices, orders and shipping notices, and the popup offers it in seven languages. The list of words it looked for was English only, so on a German, Japanese or Spanish mailbox Safe Mode was on, said it was protecting your receipts, and matched none of them. It now looks for the equivalent words in eleven languages and keeps the English ones as well, since a lot of commercial mail is in English whatever your Gmail is set to.
- An unattended cleanup that skipped everything said nothing matched. Scheduled cleanups and Auto-Pilot decline anything large enough to need a confirmation, because there is nobody there to give one. That decline looked exactly like finding no mail, so the notification said your rules matched nothing, and a schedule could quietly stop doing anything for weeks. It now says how many rules were skipped and why.
- Gmail's "all 50 on this page are selected" was read as "all of them". The sentence Gmail shows to tell you only the visible page is selected contains the words "all" and "selected", which is exactly what the check was looking for. If the select-everything click did not take, the run then recorded the full match total against an action that touched fifty. The check now treats Gmail still offering to select everything as proof that it has not happened.
- Auto-Pilot swept further back than it measured. If your minimum age was set to a year, the weekly scan counted your mail through that floor and the sweep that followed ignored it and went back six months. The two now use the same floor. This can only ever narrow a sweep.
- Never Delete quietly held 100 addresses. Paste 150 protected senders in, press Save, and the page said "Settings saved successfully!", the counter said 150, and 100 were stored. The rest were not protected. Over-long lists are refused now, with a message saying how many to remove, and nothing is written until they are. The same was true of Protected Keywords at 25 entries, and of the per-intensity rule boxes at 50 rules each.
- Restore defaults said it worked even when the save failed. It never checked, so a refusal showed a red message and then a green one, and left the page displaying settings that had not been stored.
- Schedules reported success when the extension had refused them. Adding, enabling, disabling and removing a scheduled cleanup all ignored the answer and always said it worked.
- Enter ran a cleanup from any button in the popup. Focus anything that was not a dropdown or a tab, press Enter, and a real cleanup started instead of the button doing its job. Opening the Pro panel puts focus on Get Pro, so pressing Enter to buy started a cleanup. Enter now only starts a run when nothing else has a use for it.
- Buyers saw the Pro padlocks on every popup open. Checking a licence takes a fraction of a second, and until it finished the popup showed the padlocks and the gold Pro badge meant for people who have not bought it. It now remembers the answer and shows the right thing immediately.
- The storage purge forgot which age you picked. It remembers which senders you ticked so you can run it again for the rest, but the age reset to six months every time the popup closed, which is wider than anything else the menu offers.
- A storage purge that failed part way marked every sender done. A purge of ten senders that cleared one and then stopped ticked all ten as purged, so the ones still to do looked finished.
- Turning Auto-Pilot off during a sweep did not stop the sweep. It cleared the paperwork, and the sweep carried on archiving in the background without recording anything it did. The stop checks that the sweep it is stopping is still the one running in that tab, so it can never interrupt a cleanup you started yourself.
- An unattended run that was refused now says so in the notification. The notification is the only thing an unattended run can show you, and it was reporting "0 emails moved to Trash", which reads as a clean mailbox.
- Diagnostics reported a size band as megabytes freed, still counted storage freed for archive runs, which move mail without freeing anything, and probed eight settings that have never existed. The Gmail-layout warning can also be dismissed now, instead of staying on the page forever after one bad run.
Added
Pro Settings. A new card on the Options page, for people with a licence. Everything on it defaults to what the extension already did, so nothing changes unless you change it, and nothing that used to be free has moved behind it.
- Recovery label. The label put on mail before it is cleaned, so you can find it again. It has always been "GmailCleaner"; now it can be whatever you like. Older cleanups keep the label they were tagged with, so this never breaks a Restore you could do yesterday.
- Auto-Pilot interval. Weekly, every two weeks, or every 30 days.
- Smart Suggestions scan depth. The standard scan measures your ten heaviest senders. Deep measures twenty, finds more, and takes about twice as long.
8.11.0 - The paid half, and previews that say they were previews
Most of this release is on the parts of the extension you only see after you have paid for it. Five of the fixes are on Pro controls, three of them are the same problem in three places: a button that quietly did less than you asked it to and never said so.
Fixed
- Apply selected threw away your Unsubscribe suggestions. Suggestion cards come in two kinds. Most of them build a cleanup rule, and one of them, Unsubscribe, drives Gmail's own unsubscribe control instead. Bulk apply can only run the first kind, and rather than say so it dropped the others on the floor. Tick three Unsubscribe cards and two Archive cards, press Apply selected, and two ran while nothing on screen mentioned the other three. Unsubscribe cards no longer offer a tick box they cannot honour, Select all skips them, and if any do reach the button it now names the one that will actually run them.
- The storage purge stopped at 25 senders without a word. One purge takes at most 25 senders, and the list above it holds up to 100 with a Select all sitting on top. So the ordinary way to use the feature, tick everything and press Purge, cleaned the biggest 25 and abandoned the rest in silence. It now tells you how many of your selection it is taking and to run it again for the remainder, which is what the Unsubscribe tab has said about its own identical limit since Pro launched.
- Auto-Pilot could sweep a different Google account than it measured. The weekly scan takes a few minutes and pins the mailbox it is looking at. The sweep that follows went and found a Gmail tab of its own instead, preferring whichever one you happened to be looking at. If you are signed in to two accounts and switched to the other one mid-scan, the sweep archived that mailbox using suggestions measured in the first, unattended. It now runs in the mailbox it measured, or waits for next week.
- Auto-Pilot's scan measured your suggestions against settings you had turned off. Every suggestion card promises a number, and the promise is only honest if it was counted through the same filters the button applies. The three scans you start yourself send your safety switches along for exactly that reason. The weekly background scan never did, so it counted everything as though Skip Unread, Skip Starred, Skip Important and Skip Labeled were all on, and then wrote those numbers over the ones your own scan had measured. If you had turned Skip Unread off, a card reading "Deletes 200 now" sat above a button that would take every unread message too. The background scan now uses your switches. The sweep itself is unchanged and still runs with every guard on, so it can only ever take less than it counted.
- Closing the Gmail tab stopped Auto-Pilot for two hours. If the tab went away mid-sweep, nothing was left to report that the sweep had ended, so the next weekly run skipped, and the one after that, until the record aged out. The popup meanwhile said a sweep was running right now. Closing the tab now ends the sweep properly, and the popup stops believing in one that died.
- Dry runs were counted as cleanups. A dry run moves nothing, and it was still adding its projections to the lifetime totals on the Stats page. Preview five thousand old promotions to check a rule before you trust it, which is what the feature is for, and the chart claimed five thousand promotions cleaned, permanently. Previews are kept out of the totals now and still appear in the run history with their dry run tag, which is the one place they belong.
- The finish screen described work that had not happened. A dry run that ended while the popup was open said "Cleanup Complete!", counted the mail as cleaned, said it had gone to Trash, and offered you the recovery log to undo it. It now says a dry run finished and that nothing was moved, which is what the progress page has said all along. Archive runs had a smaller version of the same problem: the note under the result promised Gmail's 30 day Trash window, and archived mail never goes to Trash. It now says where the mail actually is.
- Safe Mode's receipt protection could switch itself off. Safe Mode keeps receipts, invoices, orders, shipping and refund mail out of a cleanup by excluding those words from the subject. If your own rule already excluded any subject at all, for any reason, the whole protection was skipped while Safe Mode carried on showing as on. Gmail is perfectly happy to apply both exclusions, and the protected keywords feature has relied on that for years. Both apply now.
- A Never Delete entry could be rejected and reported as saved. If a line in the Never Delete list was not in a form the extension can use, a name and address pasted together, or an address with an apostrophe in it, it was dropped before it was stored, and Settings still said "Settings saved successfully!". You would leave believing a sender was protected. Settings now tells you which line it could not use.
- Buying Pro did not stop the extension asking you to buy Pro. The strip offering somewhere to paste a key kept appearing for people whose key was already stored and verified, because it was drawn before the check finished. The Storage tab's upgrade pitch had the same problem from the other direction: it could be shown but never hidden again, so it stayed up for the rest of the session after a key was entered. Both are gone the moment a licence verifies.
- Settings said Pro unlocked one feature. That was true when the only paid feature was bulk unsubscribe. Four more have been added since and the sentence never changed, so anyone opening Settings after paying was told they had bought a fifth of what they had bought. Settings now lists all five.
- The What's new page flashed an empty jump bar before its contents loaded.
Improved
- The Storage and Suggestions lists remember what you ticked, minus what already ran. Both cap one run at 25 senders out of a list that can hold a hundred, and the popup closes when a run starts, so working through a long list means going back and forth. Every trip back used to start from an empty selection with no record of where you had got to. They now come back with your selection intact and the senders that just ran taken off it, so "run it again for the rest" reaches the rest instead of the same twenty-five. A dry run keeps the whole selection, because it did not take anything. Nothing about this leaves your browser.
- Settings shows what a Pro key unlocks, as a list, in one place, so it stays right the next time something is added to it.
8.10.0 - What the numbers promise, the runs deliver
Fixed
- Auto-Pilot swept senders it had never measured that way. Every suggestion card picks its own action and counts the mail that action would actually move: "40 large emails" is counted with the large-file filter applied, and an Unsubscribe card moves no mail at all. The weekly sweep read those counts and then archived six months of everything from the same sender, because the one rule it builds drops the filter the number was measured through. A card promising 40 could quietly archive thousands. The sweep now only takes suggestions its own rule genuinely fits, says on the Clean tab how many it left for you, and leaves the rest to be run by hand where you can see them.
- Steps in the Mailbox Report that were never searched looked empty. When one of the report's searches times out, the report is meant to say "not measured" rather than print a confident zero. It has said so in the code since 8.9 and never once on screen: the step was dropped from the list before it could be drawn, so a report missing a whole section read as a mailbox with nothing in it. Unsearched steps now appear, and say what they are. They carry no Run button: there is no figure behind one yet, and this is an extension that does not act on numbers it has not measured. They ask you to scan again instead.
- A custom rule could reach your Google Chat history. The rule checker refuses queries that point at Sent, Drafts, Trash, Spam and anything starred or important, because a bulk delete there is not something Restore can undo. It has been refusing
in:chatsince the check was written, and Gmail's operator isin:chats, so the one spelling anybody would type went straight through. Both are refused now. Excluding chat with a leading minus still works. - Archive sweeps announced storage they had not freed. Archiving moves mail to All Mail, where it still counts against your Google storage. 8.9 took the storage figure off every screen that showed one, and missed the desktop notification, which kept telling anyone who had turned notifications on that an archive run had freed about 0 MB. That is the only report an unattended sweep ever gives you. It now says where the mail went and makes no storage claim.
- Changing a setting could make a finished cleanup run again. A scheduled cleanup writes down when it last ran, and the alarm for the next one is anchored to that. Editing any schedule at the same moment could write an older copy of that record back over it, leaving the cleanup that had just finished looking overdue, so it ran a second time about a minute later with nobody watching. The same race could lose an Auto-Pilot confirmation and put it silently back into preview. Every one of these writes now takes its turn instead of racing.
- Protect could quietly stop protecting. The Protect button on the Stats page accepted twice as many senders as the Settings page keeps. Going past that limit and then opening Settings and pressing Save, without touching the whitelist at all, wrote the shorter list back and unprotected the extra senders. Both pages use one limit now, and a full list says so rather than dropping the oldest entry.
- Dry Run counted the same mail more than once. The preview totals each rule separately, and the rule sets overlap on purpose: mail older than a year is also older than three months. A real run clears the first rule before the second one looks, so it never double counts, but the preview moves nothing and counted every overlap again. The summary said "conversations", which made a sum of overlapping rules look like a headcount. It now reports matches across rules and says plainly that mail matching two rules is counted twice.
- The per-rule storage column always read zero. The progress page has a Freed MB column beside each rule, and the run never sent it a figure, so every row of every run showed zero while the total at the end was correct. Each rule now reports its own share, and archive runs and dry runs correctly report none.
8.9.1 - Store listing wording
Changed
- The store listing no longer names languages one by one. The description used to spell out which languages the cleaner can drive Gmail in, twice over, in all seven listing languages. The Chrome Web Store read that list as keyword spam and turned the update down, so the listing now makes the same point without the roll call. The extension itself is unchanged: this release exists to carry the corrected listing.
8.9.0 - Release notes, a proper goodbye, and honest storage numbers
Added
- A What's new page inside the extension. The version number in the popup footer is now a button: press it and you get the release notes for this version and the eleven before it, written for people who use the extension rather than people who read the code. There is also a link on the Settings page. A small dot sits on the version after an update until you have read them once. The notes ship inside the package, so opening them makes no network request, same as everything else here.
- An uninstall page. Removing the extension now opens a short page that covers the four things people actually leave over, and tells anyone who bought Pro that their lifetime key survived the uninstall and where to have it reissued. The address it opens carries no identifier, no version and nothing from your mailbox.
Changed
- Pro is $9.99 again, down from $19.99. Existing keys are unaffected: a lifetime licence does not re-price, and nothing about it is checked against a server. Anyone who bought at $19.99 keeps exactly what they paid for. The older checkout links stay open for activation and key recovery, so no past purchase can be stranded by the change.
Fixed
- Archive runs claimed to have freed storage. Archiving moves mail to All Mail, where it still belongs to your account and still counts against your Google storage. Every run that archived anything reported megabytes freed anyway, on the progress card, the run receipt, the popup summary, the recap and the lifetime total on the Stats page. Only the one line at the end of the run had it right. Archive runs no longer report a storage figure at all, and old archive runs already in your history stop showing one too.
- On some languages a bulk delete of thousands was recorded as about fifty. When a rule matches more mail than one page, the extension asks Gmail to select the whole match set, and it proves the click worked by checking that Gmail withdrew the offer. Gmail replaces that offer with a Clear selection control, and in Dutch, Swedish and several other languages that control was mistaken for the offer still being there. The run went ahead and deleted everything, but the receipt, the Stats row, the undo entry and the safety limit that stops runaway runs were all sized against one page. The check now looks at what the control says, not merely whether one is present.
- A step the report could not measure looked like an empty one. If a search timed out while the mailbox report was running, that step was filed as zero, disappeared from the plan and read as "nothing here" for a part of your mailbox that was never actually looked at. Those steps now say "not measured".
- A cleanup started from the popup could overwrite the scope of a different run. If a narrow run was already working in that Gmail tab (a storage purge, a suggestion, a report step) and you pressed Run Cleaner, the second run was correctly refused, but it had already recorded itself as the run to resume. Reconnecting from the progress page then restarted the full cleanup instead of the narrow one.
- A finished scheduled cleanup could undo edits made while it ran. Stamping the schedule as done wrote back every schedule as they had been when the run started, so a schedule deleted or edited in the meantime reverted, and another schedule that had just finished could be re-armed and run a second time.
- Two unattended runs could both believe they had the mailbox. A scheduled cleanup and an Auto-Pilot sweep due in the same minute could each claim the run marker, and the one that lost the race carried on as though it had won. Both now check that the claim they wrote is still theirs.
- Auto-Pilot could be knocked off course by an unrelated run. Its scan stage has checked since 8.7 that the run reporting in is the one it started; its apply stage only checked which tab the message came from, so any cleanup finishing in that tab could clear its state.
- Applying a suggestion said it was applied before anything had moved. The confirmation appeared the instant the run was handed to Gmail, then the popup closed on it, so a run that was cancelled or matched nothing still ended on a success message. It now says the run started, which is what every other button here already said.
- Settings saved rules the cleaner would refuse. Typing a rule aimed at starred, sent, trashed or spam mail into one of the intensity boxes showed a warning and then saved anyway under "Settings saved successfully", and the next run skipped that intensity without explaining why. Those rules now block the save and say which one is the problem.
- The Storage purge could apply a stricter age than its own note promised. The Minimum Age set on the Clean tab also applies to a purge, so with Minimum Age at 1 year and the purge set to 6 months, the note under the sizes named the wrong filter. It now names whichever one the run will really use.
- Safe Mode's refusal only arrived after the click. Safe Mode skips Updates and Forums, and for a free user whose one unlocked report step was one of those, pressing Run did nothing but raise a toast. The row now says so up front.
- Restore blamed the wrong thing when it ran out of passes. A very large restore that reached its page limit reported "Selection failed", which sends you looking for a problem that is not there. It now says it hit the limit and that running Restore again continues from where it stopped.
- An age limit written inside Gmail's curly-brace groups was not seen. A custom rule like
{older_than:2y category:promotions}did not register as carrying its own age floor, so a redundant one could be added on top.
8.8.0 - Unattended runs work again
Fixed
- Scheduled cleanups and Auto-Pilot stopped running on any tab that had already run once. After a run finished, the old run's messaging hook stayed live in the Gmail tab and answered on behalf of the next one. The extension checks that the run it just started is really the run that answered, got the previous run's name back, decided its own injection had been swallowed, and gave up. The first sweep in a fresh tab worked and every one after it silently did nothing.
- Purge selected on the Storage tab could archive instead of delete. It borrowed the Delete or Archive setting from the Clean tab, so if that had ever been switched to Archive, the purge moved your biggest mail to All Mail. The button said Trash, the summary said megabytes freed, and the senders were marked Purged so a rescan stopped offering them, while the storage that feature exists to reclaim never moved. It now always deletes, whatever the Clean tab says.
- A rule that needed more than one pass claimed it had given up. Any rule with more mail than one pass clears announced "stopped at the pass limit" while it was still working, and filed a duplicate entry each time. A rule that cleared 150 messages over three passes was recorded as 300, in the progress table, the run receipt and the category totals on the Stats page.
- Applying many suggestions at once could search for fewer senders than you picked. Twenty-five addresses do not fit in one Gmail search, so the search was cut short while the status line and the run history still claimed all of them. Both the bulk button and Auto-Pilot now split the work into as many searches as it takes.
- Rules aimed at Trash or Spam could destroy mail permanently. Those are the two places where Gmail's delete button means delete forever, so a custom rule pointed at either one skipped the Trash entirely and left nothing for Undo or Restore to find. They are now refused, the same way rules aimed at starred or sent mail already were.
- Some whitelisted senders were never actually protected. An address with a standalone "and" or "or" in it, like sales.and.marketing@company.com, was dropped from the Global Whitelist without a word, and the next run treated that sender as fair game.
- Picking Maximum still ran Normal for some people. 8.7 fixed this for anyone who had never saved Settings. Anyone who had saved before Maximum existed still got the Normal rules under a progress page announcing Maximum.
- The Apply checked button always said Trash. When the suggestions it was about to run were archive suggestions, it archived them, which is what the individual cards said all along. Now the button says so too.
8.7.0 - Bulk actions do what the card says
Fixed
- Apply checked suggestions ignored what each card promised. Every suggestion leads with one action and states the number that action will reach. The bulk button underneath ran one Delete old mail over all of them, so a card reading "Archives 200 now" sent that mail to Trash instead, and a card reading "Deletes 40 large emails now" lost its own size filter and took every old message from that sender. Bulk apply now runs the action the cards were measured for. If you check a mix, it runs one group and says to apply again for the rest.
- Run the whole plan archived the steps it was selling in megabytes. A run has one setting for delete or archive, and a plan holding both kinds took the gentler one, so the large-attachment steps were archived. Archiving a 25 MB email frees no storage at all, under a button whose own subtitle said Trash. The plan now runs one kind at a time and the subtitle says which.
- Picking Maximum ran Normal. Unless you had opened Settings and saved at least once, the engine had no Maximum rule list to load and quietly fell back to Normal, while the progress page announced Maximum. The most aggressive preset in the product was not the one running.
- Dry Run could quote one page for a run that would clear thousands. A preview acts on a single page; a real run keeps going until the rule is empty. When Gmail's "select all conversations that match" link was not available, the preview reported the page it had selected rather than the size of the match, so a rule Gmail itself described as 3,000 results previewed as 50.
- Restore counted a whole-mailbox move as one page on any Gmail that is not in English. The mail all came back; the number you were shown did not describe it.
- The mailbox report treated a search that timed out as a zero. A step whose search failed was stored as empty, which looks exactly like a step with nothing in it, and a failed headline search printed "Nothing older than 6 months turned up" over a mailbox full of it. The report now says how much of it completed.
- Scans stopped hiding their own warnings. The engine has always said when a scan was incomplete; every screen showed the count and dropped the sentence explaining it.
- The report goes stale when you change a safety switch, and now says so. Every number in it is measured through the switches as they were set when you scanned. Turning one off afterwards means the buttons would reach more mail than the counts beside them.
- Safe Mode silently refused two of the report's own steps. It skips Updates and Forums, and the report counted them anyway and offered a button that could only end in "no rules to run".
- Storage sizes count large mail of any age; the purge defaults to six months. The rows and the button disagreed by design and nothing said so. It does now.
- Protect could quietly protect nothing. When Gmail gives a display name and no address, that name was saved to your whitelist, where the cleaner cannot match it. The button reported success. It now explains what to do instead.
- A sender could aim your unsubscribe at somebody else's mailing list by starting its address with a dash, which Gmail reads as "not this". Two other places in the code already refused it.
- Auto-Pilot could be handed a scan you started. It waited for a scan in a particular tab, and any suggestion scan in that tab would do, including one you ran yourself, which started an unattended sweep you had not asked for. It now waits for its own.
- A weekly sweep or scheduled run that never started could lock out every manual run for two hours and, for schedules, mark the week as done. Starting the cleaner into a tab that already has one running is ignored by design, and nothing checked whether that had happened.
- Auto-Pilot could quietly switch itself off for good. It read your Pro key from one place and gave up if what it found there did not verify, even when a valid key sat in the other. The rest of the extension has read both since 8.6.
- The run history filed an archive run that moved nothing as a deletion, in red, permanently.
- A failed unsubscribe from a suggestion card jammed the panel. Scans and unsubscribes afterwards did nothing, silently, under a status line that still said it was working.
Changed
- The safety line under Run no longer says unread mail is "never" touched. It is skipped while the switch is on, and the switch is yours to turn off.
8.6.0 - Suggestions count what they clean
Fixed
- A suggestion could be sold on exactly the mail its own button refused to touch. A card reading "402 emails, 100% unread, mostly older than 6 months" with a Delete old mail button underneath it cleaned nothing, every time, on every mailbox. The count came from a plain search for that sender; the button sent that search plus your safety switches, one of which is Skip Unread. The more unread mail a sender had, the higher it ranked, and the more certain it was that the run would find nothing. Suggestions are now measured through the same switches the button applies, so the number beside a button is the number that button will act on.
- Senders your switches hold back entirely are no longer suggested, and no longer disappear without explanation. The list says how many were held back, which switches did it, and takes you to them.
- The suggestion scan never sent your switch settings, so it measured everyone against the defaults. If you had turned Skip Unread off, the scan still counted as though it were on.
- Checking more than 25 suggestions quietly cleaned only 25. The status line said it was cleaning all of them and the run history recorded all of them. It now says which it is running, the way the bulk unsubscribe button already did.
- Your Pro key survives an update. It was stored in one place, so one storage hiccup lost something you paid for; it now lives in two and repairs whichever copy goes missing. A stale copy in one can no longer hide a good key in the other. Removing a key clears both, and says so plainly if it could only clear one.
- Unpacked builds keep one identity. Chrome derives an unpacked extension's ID from the folder it was loaded from, and all extension storage is scoped to that ID, so unzipping each release next to the last one made every update a brand new extension with nothing in it. The key was never forgotten; it belonged to a different extension. Builds now pin an ID. Firefox already did.
Note
- Pinning the ID changes it once, so an unpacked install has to be given its Pro key one more time. After that it stays.
8.5.1 - Unsubscribe actually unsubscribes
Fixed
- Bulk unsubscribe skipped senders whose unsubscribe link was plainly on screen, and blamed them for it. The engine looked for Gmail's Unsubscribe control exactly once, 300 milliseconds after opening the message, with no retry, while every other control it drives is waited for with a multi-second budget. Gmail renders that link only after it has processed the message's List-Unsubscribe header, which is routinely later than that. So the engine lost a race it did not know it was running, and the row read "No 1-click option", which sounds like the sender's fault and is not. It now waits up to six seconds.
- "No 1-click option" and "Manual step needed" were describing the sender when they were describing us. They now read "No unsubscribe link" and "Needs their website".
- A confirmation Gmail never acknowledged was reported as success. The code waited for the dialog to close and then ignored the answer, always returning "Unsubscribed". A dialog still sitting there means the click did not take, and that is the one failure a user cannot detect for themselves: they cross the sender off and keep getting the mail. It now reports "Unconfirmed".
- Finding the control no longer rests on one Gmail class surviving forever. There is a third fallback for markup carrying neither the class nor the role. It still refuses anything the sender wrote: the message body, list rows, and any real link, because Gmail's control acts in place while a sender's link navigates your tab to them.
- The report headline counted mail no run could ever touch. A bare
older_than:6msearches all mail, which includes Sent, Drafts and Chats, all three of which the cleaner refuses to act on by design. A mailbox full of sent mail produced a five-figure headline above a plan with no steps in it. - "Nothing matched the plan. Your mailbox is already clean." printed directly under a headline of 5,120, which is not a sentence anyone should have to read. Empty bands and an empty mailbox are different findings, and it now says which one it found.
Changed
- The popup is 440px wide, up from 380. Four tabs could not hold their own labels at the old width and every list row was fighting for space.
8.5.0 - The number matches the run
Fixed
A report band said 5,000 and cleaning it removed nothing. The count and the button were asking Gmail two different questions. The band was counted with its own query,
category:updates older_than:1y, while the run that followed searchedcategory:updates older_than:1y -is:starred -is:important -is:unread -has:userlabels. Updates are notification mail nobody opens, so-is:unreadremoved the entire band and the run cleared zero.Every count in the Mailbox Report is now measured through exactly the filter its Clean button applies, so the number on screen is the number that button acts on. Sender attribution is measured the same way, and band ranking changes as a result: a band with more mail but less reachable mail no longer outranks one you can actually clear.
The Storage X-ray had the identical bug and got the identical fix.
- A report that reads honestly can still read as empty, so it now says why. The headline is measured twice, once raw and once guarded, and the difference is shown: "12,431 more old emails are protected by your guards (Skip Unread, Skip Labeled)", with a button that takes you straight to those switches. That costs one extra search.
- The tab bar overflowed the popup. Four tabs, two of them carrying a padlock, in 380px, and the labels were long: "Unsubscribe" barely fit, "Cancelar inscrição" and "Se désabonner" never did. The labels are short now, and a tab can shrink below its own text instead of pushing the bar wider, so a long translation ellipsises rather than breaking the layout.
8.4.0 - Sender marks, and a way out of a stuck run
Added
The Unsubscribe list draws a mark for every sender, a coloured square with the sender's initial, so a row is something you can spot instead of a line of text to read. Addresses at one company share a mark:
news@substack.com,noreply@email.substack.comanddigest@mg.substack.comall draw the same S, so they group visually. The Suggested cards on the Clean tab use the same marks.The obvious way to build this is a favicon per sender, and that is exactly why it is not built that way. A favicon means one network request per sender, to a third party, handing over the list of who mails you, in an extension whose whole claim is that it makes no requests at all. Every mark here is arithmetic on the address: same sender, same mark, on every machine, offline, forever. The test suite now fails the build if an image or a URL ever appears in that path.
"Reset stuck run", in the popup and on the progress page. Two separate flags could say "a run is happening", and neither had any way to clear: the stored run claim, which expired after two hours, and a flag inside the Gmail tab, which expired never. When a run died without reporting back, both were stranded and every later run was refused with "a cleanup is already running" while pointing at nothing. Reloading the Gmail tab was the only cure, and nothing said so.
The refusal now arrives with a banner attached, and the banner says which case you are in. If the cleaner answers and says it is genuinely working, the banner says so, offers to show you its progress page, and will not clear anything without a second, explicit click; that click cancels the run and then waits for it to actually stop before clearing, because the flag it is clearing is the only thing keeping a second cleaner off the same mailbox. If nothing answers, one click clears it and you can start again.
One case gets special handling. If the tab flag is set but nothing answers at all, a cleaner is probably still running in there with its connection to the extension severed, which is what reloading or updating the extension mid-run leaves behind. It cannot be told to stop, so Reset reloads the Gmail tab, which does stop it. That is the same tab reload that was the only cure for any of this before 8.4, except now the extension knows when it is needed and does it for you.
Reset never reports success it did not achieve. If the run will not stop, or the Gmail tab is open but refuses to be reached, nothing is cleared at all and it says so, because a cheerful "you can start again" backed by nothing is how you end up with two cleaners on one mailbox.
Fixed
- "Unsaved changes" appeared mid-sentence in the Options subtitle, several screens above the Save button it was talking about. It now sits beside Save.
8.3.0 - Real result counts
Fixed
- The Mailbox Report showed 50 against band after band, and a run then cleared far less than the plan implied. Gmail renders its "1-50 of 1,234" counter in the toolbar, outside the results element, and the code only ever looked inside that element. So the total was never found on a normal result page and every caller fell back to counting the rows on screen: one page, fifty. The counter is now looked for in the results area, then the toolbar, then the page. The same total sizes the large-run guardrails, so those were reading a page instead of a match set too.
8.2.0 - The guards you could not see
Reported from real use: "unsubscribe doesn't work, storage doesn't work, it gets randomly stuck a lot". All of it traced back to guards and state the product never showed you.
Fixed
- Two safety guards had been forced on since v3.x with no control anywhere. Every run silently added
-is:unreadand-has:userlabelsto your rules, so on a mailbox where the clutter is unread or labelled, most of it was excluded and the run reported "nothing matched your rules". Both are now real switches in the popup, still on by default, and both are actually sent to the engine (the popup never sent them, and a missing value reads as "on"). - A scan that timed out reported success. If Gmail did not answer a search, the scan skipped it and finished with a tidy "No large mail found" or an empty sender list. It now says how many searches timed out, and says so plainly when all of them did.
- Bulk unsubscribe was opening unread mail and marking it read. It picked rows by a CSS class the code documented as "already read"; in Gmail that class means unread. It now prefers genuinely read rows.
- The Pro padlock stayed on the tabs after you bought Pro, and the Auto-Pilot "Pro" badge never went away at all. The padlocks are SVG, and
hiddenis an HTML property that does nothing on an SVG element, so it was never actually applied; the Auto-Pilot badge was static markup no code ever touched. All the Pro markers now disappear once a licence verifies, since they exist to tell free users the tier is there.
Added
Maximum, a fourth cleanup intensity above Deep, for a mailbox that has never been cleaned. It shortens Deep's age floors, drops the attachment size thresholds, and adds two more ways of naming bulk mail that Gmail never filed into a category: the sender names marketing actually uses, and the "view in browser" line that only ever appears in a mass mailing.
- It deliberately does not sweep your Inbox wholesale or a bare age range. Both of those reach ordinary correspondence, which the guards narrow but do not protect: a two-year-old reply from a person is not starred, not important, and not unread. Every rule it ships is either size-bounded or age-bounded.
- Like Deep, it will not start on a single click, and it says which intensity it is asking you to confirm.
- Editable on the Options page like the other three, and available to scheduled cleanups.
Fixed
- Saving on the Options page rebuilt the rule map from a hardcoded list of the three intensities that existed at the time, so any intensity added later was silently dropped on the next save, and its editor was never watched for unsaved changes. Both now derive from the real key list.
8.0.0 - Mailbox Report, and a popup that finally explains itself
The biggest release since Pro shipped. It adds the thing the product was missing, which is an answer to "what is actually in here", and it rebuilds the two screens where that answer matters: the popup you open, and the dashboard you watch a run finish on.
Added
Mailbox Report. One read-only pass counts what is in your mailbox and turns it into a ranked cleanup plan: old promotions, big attachments, forgotten newsletters, social and forum mail, and inbox mail you never archived. Eleven Gmail searches, no message opened, nothing moved. It is now the tab the popup opens on.
- The whole report is free, and so is running its biggest step, so you watch the mechanism work on your own mail before deciding anything. Pro unlocks the remaining steps and Run the whole plan.
- Every step is an ordinary cleanup run. Matches are labelled first, Dry Run is honoured, your whitelist, protected keywords and Minimum Age all apply, and the run lands in the Recovery Log with one-click Restore like any other.
- Storage figures are floors, built from Gmail's own size tiers, so the report says "at least N MB". Nothing is compared against Google's 15 GB bar, which is shared with Drive and Photos and which no extension can see.
- A run-completion card on the progress dashboard. Watching a run end used to leave you with a disabled button reading "Run finished". You now get the number, the labels that were actually applied, what Trash keeps and for how long, a link straight into the Recovery Log, and a copyable receipt.
- A Pro screen inside the popup. Clicking a locked control used to open a payment form in a new tab, with no explanation, from a developer you have never heard of. It now opens a panel that leads with your own scan numbers, says what the five paid features do, and states the three things people actually want to know: one payment and never a subscription, the key is checked on your device, and every feature added later is included. The buy button does exactly what the old click did.
- Two lines under the Run button that say, without a click, what the cleaner protects and what it never sends anywhere.
- "Bought Pro? Paste your key" appears once you have run a cleanup and have no licence, because the post-purchase page told buyers to right-click the toolbar icon and hunt for Options.
Changed
- The popup got a real type scale and spacing grid, sentence-case buttons, and a gold accent reserved for Pro. Green used to mean both "your cleanup worked" and "pay us".
- Pro is visible before you scan: the tabs that lead to paid features carry a small padlock, and the Pro badge now says whether it is locked or active instead of appearing only after you buy.
- The popup remembers which tab you were on, and which senders you had ticked on the Unsubscribe tab, so a trip to checkout no longer throws away your triage.
- Scans show placeholder rows while they run, and each list explains what the scan will produce before you start it.
- "Maybe later" on the rating ask now lasts 90 days instead of forever.
Fixed
- The Recovery Log stopped eating itself. An entry was written once per pass and the log kept only 20, so a first sweep on a large mailbox pushed out its own earliest entries before it finished and always destroyed the previous run's. Passes of the same rule in one run are now a single entry, and the log holds 60 of them.
- The large-run confirmation appears on the screen you are looking at. The 10,000 and 20,000 conversation checks were browser dialogs raised inside the Gmail tab, which every run path had just pushed into the background, and they froze Gmail's page while they waited. They are now asked on the progress dashboard, with stopping as the default, and a run that gets no answer stops rather than proceeding. Declining also stops the whole run now, which is what the button says: it used to end only the current rule and carry on to the next one. Scheduled sweeps are unchanged, they still decline unattended and skip that rule.
- A storage purge no longer builds an over-length search. Picking 25 senders produced a query far past the length this project's own validator allows. Addresses are now packed into as many searches as the limit permits and run as an ordinary multi-rule cleanup.
- Rate this extension sent Firefox users to the Chrome Web Store, under a button that named it. It now resolves to whichever store the copy was installed from, and it only appears after a run big enough to have earned the ask.
- Removed a "protect this sender" suggestion strip that could never appear: it scored senders by opens and replies, and nothing in the extension has ever recorded either.
SECURITY.mddescribed the run counter as synced when it has always been device-local, and the README compared Pro against a monthly price when the competitors' annual plans are the honest comparison.
7.15.0 - Safety, locale and scheduling fixes
A second sweep, in the same spirit as 7.14.2 and reaching the places that one did not: the paths that only run when nobody is watching, and the ones that only misbehave when Gmail is not in English.
Fixed
- Scheduled cleanups now honour your Global Whitelist. They never did. The list you fill in under "Never Delete" was applied to every manual run and to Auto-Pilot, but a scheduled cleanup read a separate, per-schedule list that nothing has ever been able to fill in, so it ran with no whitelist at all. The one kind of run you are not watching was the one that could delete mail from a sender you had protected.
- Custom rules now respect their own Action. A custom rule saved as "Archive" or "Label only" was stored, shown with its badge, and then executed with the run's action anyway, so a rule you set to label your invoices was deleting them. Archive rules are now used when you run the cleaner in Archive mode, and Label-only rules are never executed by a cleanup run.
- The big-run guardrails work in every language. 7.14.2 made them measure the real match total instead of the page on screen, but it found that total by reading Gmail's English "1-50 of 3,200" and its English "all conversations selected" banner. On a German, French, Japanese or Korean Gmail both reads failed, so the guardrails were back to sizing a 25,000-conversation sweep at about 50. The counter is now read without relying on any particular language, an all-matching selection is detected structurally, and the guardrails always measure what the click can actually touch.
- Bulk deletes complete on a non-English Gmail. The confirmation dialog Gmail shows for a very large batch was only ever found by English phrases, so on other languages the run waited, timed out and quietly did nothing. It is now found by its buttons, which were already translated.
- A whitelist entry like
*@bank.comprotects that domain. The Options page accepts and documents that shape, and Smart Suggestions already treated it as the whole domain, but the cleanup query passed it to Gmail verbatim. Gmail has no wildcard there, so the entry protected nothing. - Rules that target protected mail are refused wherever they come from. Custom rules were checked; the Light / Normal / Deep boxes were not, and saving one that targeted starred or sent mail raised no objection at all. Both sides now refuse them, and a Gmail
{a b}group can no longer hide the token from the check. - "Restore defaults" no longer wipes your safety lists. It said it would replace your rules. It also silently emptied the Global Whitelist and your Protected Keywords. It now restores rules only.
- Auto-Pilot only ever acts on its own scan. A Smart Suggestions scan you started yourself could hand a pending sweep its "scan finished" and set an unattended archive run going. It also now re-checks vacation mode before it acts, so switching that on while the scan is running stops the sweep.
- Two overdue schedules no longer fire in the same instant, which could start one cleanup running the other schedule's settings, and changing a schedule after a run can no longer make that run repeat a minute later.
- Cancel is now honoured between selecting mail and moving it during a Restore, and between opening an unsubscribe dialog and confirming it.
- A restore that moves everything matching now reports how much it actually moved instead of the page count.
- A rule that stops because it hit the per-run pass limit now says so and appears in the run summary instead of vanishing from it.
- The large-batch warning can fire again; it was comparing a page of at most 100 rows against a threshold of 2,000.
Changed
- Scoped runs keep your Minimum Age. A Storage X-ray purge or a Smart Suggestion used to drop it for that run. "Archive all" carries no age of its own, so with the floor dropped it could act on mail that arrived today. Your floor is now applied whenever it is stricter than the run's own age, exactly as it is for a normal cleanup.
- Editing settings in the popup while a run is in progress no longer rewrites what a reconnect would run, and a run that was refused because another was already going no longer leaves its settings behind.
- Opening the progress dashboard for a scheduled or Auto-Pilot run now refreshes a leftover tab instead of showing you the previous run's finished screen with Cancel greyed out.
Privacy
- The last-run summary is synced so you see it on your other browsers, and it carried the literal Gmail searches that ran. For a Storage X-ray or Smart Suggestions run those searches contain sender addresses read from your mailbox. The searches are now removed before that summary is synced; the counts and labels it displays are unchanged. SECURITY.md has also been corrected: it said no message IDs were stored, when the recovery log keeps a sample of Gmail thread IDs on your device so you can find cleaned mail again.
7.14.2 - Safety and reliability fixes
Fixed
- Minimum Age now actually applies. The setting promises to leave anything newer than your cutoff alone, but it was skipped whenever a rule already mentioned an age of its own, and every built-in rule does. In practice that meant choosing "older than 1 year" while running the normal preset still cleaned promotions from three months ago. The cutoff is now applied whenever it is stricter than the rule, and ignored when the rule is already stricter, so it can only ever narrow what a run touches.
- The big-run confirmations no longer miss the biggest runs. When Gmail confirms that every conversation matching a search is selected, it acts on all of them at once. The cleaner was still measuring only the page on screen, so a sweep of tens of thousands sailed past both the 10,000 warning and the large-run confirmation, and was then recorded as a few dozen. Both now use the real match total, and run totals stop under-reporting.
- Cancel is honoured right up to the moment mail moves. Cancelling during tagging, a confirmation prompt or one of the short waits before a batch was actioned used to let that batch go through anyway. A cancelled run now also ends as cancelled rather than reporting itself finished.
- Dry Run previews the real number. On a confirmed "all N conversations" selection it quoted the page on screen, so the preview for a 12,000 conversation sweep read as a few dozen.
- Custom rules can no longer smuggle starred or sent mail past the guards. A rule written as
(is:starred)slipped through the refusal because of the bracket, and the same bracket stopped the automatic "skip starred" protection from being added. - Scheduled and unattended runs stop locking the cleaner out. A few paths could leave a run marker behind after nothing had actually started, and every manual run was then refused for up to two hours. A finishing run could also clear a marker belonging to a newer run.
- Archive runs are labelled as archive runs. The Diagnostics page reported every archive run as a deletion, red tag included.
- The progress tab recovers properly. Reconnecting to a run that had already finished left it retrying in a loop for the life of the tab, and a reconnect during a Storage X-ray purge or a Smart suggestion could restart the previous full cleanup instead of the run you asked for.
- Smaller UI fixes. The Save button on Options no longer ends up permanently reading "Saving...", and the Diagnostics "Test inject" button no longer sticks disabled after a scan that finds no Gmail tab.
7.14.1 - Pro is now $19.99 lifetime
Changed
- Pro is $19.99, still a single payment and still lifetime. Everyone who already bought keeps everything, at the price they paid, forever, including every feature added from here on. Nothing about an existing key changes. Competing inbox cleaners charge $9 to $10 every month; this stays one payment, and the free tier is untouched.
7.14.0 - Key recovery, safer unattended runs
Added
- Get your Pro key back with the email you paid with. Until now the only self-serve route was revisiting the link Stripe sent you after checkout, which is no help once that link is gone. There is now a recovery page that re-issues a working key to the address on the purchase, free and as often as you need. Your existing key keeps working; this just gets you another one.
- Your key is readable again from Options. If Pro is active on one browser, Options now has Show key and Copy key buttons plus an "email yourself a backup" link, so moving Pro to a second browser or a new computer no longer needs the recovery flow at all. The key stays hidden until you ask for it.
- A proper welcome page after checkout, with the key, a one-click backup, what just unlocked, and the three steps to a first clean inbox.
Fixed
- A failed scheduled cleanup no longer blocks manual runs for two hours. When a scheduled sweep could not inject into the Gmail tab, it left its "a run is in progress" marker behind and never cleared it. Every manual cleanup after that was refused with "a cleanup is already running" until the marker aged out two hours later. The marker is now released when the run never starts.
- Scheduled sweeps and Auto-Pilot no longer walk into a run already in progress. Scans, restores and the other read-only runs attach to the Gmail tab without setting that marker, so an unattended sweep could not see them: it would inject anyway, get silently ignored, record itself as having run, and strand its marker for two hours. Both now check the tab first and stand down cleanly, leaving the schedule to fire next time.
- The progress page will no longer start a second cleaner on top of a live one. A large run pauses to ask for confirmation in the Gmail tab, which freezes that page's scripting; the progress page read the silence as a dead engine and, after a minute, re-injected. Two engines then worked the same mailbox. Auto-reconnect now checks whether the cleaner is still attached and stops instead, pointing you at the waiting prompt, and the manual Re-inject button asks before overriding.
- A cleanup that failed to start could clear a different run's progress marker, undoing the protection against two runs at once. Each run now only ever releases its own.
- Storage purges and smart applies no longer register work for a run that was refused, which left the worker holding a marker for a run that never happened.
- Estimated result totals are read correctly again. Gmail writes large result counts as "of about 3,200"; the parser expected the digits immediately after "of", failed, and fell back to counting only the current page, so dry runs and bulk actions under-reported what they would affect.
Changed
- Each Get Pro button now tags its checkout link with which feature it came from, so the sales record itself shows which one convinced people. Nothing is sent from the extension, nothing is recorded for anyone who does not buy, and the tag is a fixed label with no personal data in it.
npm run analyticsreads it back from Stripe.
7.13.1 - Steadier progress tab
Fixed
- A reused progress tab no longer stays stuck on the previous run. If you left a finished progress tab open and started another cleanup, the extension brought that tab back to the front without refreshing it, so it kept showing the old run as over: the Cancel button stayed greyed out reading "Run finished" and the reconnect controls stayed disabled, even though a new cleanup really was running. There was no way to stop that run from the dashboard. The tab is now refreshed when it is reused, so it always tracks the run you just started.
- Declining a duplicate run no longer leaves a dead dashboard behind. When a cleanup was already running in the Gmail tab, the extension opened a progress page first and only then noticed and refused, stranding you on a fresh dashboard that sat on "Waiting for Gmail tab" forever. It now checks first and simply tells you a cleanup is already running, opening nothing.
Changed
- The "is a run already attached" probe and the progress-tab opener are each written once and shared by all four run paths (cleanup, storage purge, smart apply, and the read-only scans) instead of being copied into each one. No behavior change beyond the two fixes above.
7.13.0 - Speaks your language
Added
- The popup now speaks 7 languages. Every control, hint, upsell, status line, toast and the completion notification are localized into Portuguese (Brazil), Spanish, French, German, Russian and Japanese, following the browser's UI language automatically (English stays the default and the fallback). The cleaning engine has been locale-aware since 7.5.0; this release closes the gap for the interface itself. Terminology follows Gmail's own per-language vocabulary (Papierkorb, Papelera, Corbeille, Lixeira, Корзина, ゴミ箱...). The options, stats, progress and diagnostics pages remain English for now, as do rare error branches that quote raw browser errors.
- Install-source guard. The extension now checks how this copy was installed (
chrome.management.getSelf, no new permissions). Copies planted by third-party software instead of an official store show a permanent warning banner with a link to the real listing, and scheduled cleanups plus Auto-Pilot refuse to run unattended on such copies, so a planted copy can never act on a mailbox by itself. Store installs, unpacked developer builds and enterprise-policy deployments are unaffected. The Diagnostics page now reports the install source next to the version.
Changed
- The footer navigation wraps to a second line when a language needs more room than the 380px row offers (Russian does); previously long labels would have collided with the version text.
Internal
- New
GCC.i18nhelper (catalog message with inline-English fallback, so tests and plain-page rendering keep working withoutchrome.i18n), full message catalogs for 7 locales, and a catalog integrity suite (key parity across locales, placeholder parity, escaped literal prices, markup/code key coverage). 720 tests across 30 suites.
7.12.1 - Auto-Pilot
Added
- Auto-Pilot (Pro). A weekly scheduled Smart Suggestions sweep that keeps the inbox clean automatically. Each sweep runs the same read-only suggestion scan the popup offers, then archives the top recommendations in one ordinary cleanup run: archive only (Auto-Pilot never deletes), at most 25 senders per sweep, tag-before-action stays on so one-click Restore works, and the whitelist, protected keywords, starred and important guards all apply unchanged. The first scheduled sweep is always a dry run: the popup reports "would have archived N emails" and waits for an explicit confirm before any sweep goes live. The license is verified on-device before every sweep, sweeps honour vacation mode, and runs land in stats history and the Recovery Log like every other run. No new permissions, no new Gmail surface.
Changed
- The progress page's log toggle actually collapses now. The old button only switched the log box between a capped height and full height, which usually looked like nothing happened. Hide logs now folds the whole section into a single line that keeps the entry count and the newest log entry in view, updates live, and clicks back open (reopening lands on the newest line). The log tools also work on the bad-URL error screen instead of being dead buttons.
- Locked Pro controls now open checkout directly. Toggling Auto-Pilot, clicking Unsubscribe selected, Purge selected or bulk apply without a license used to show a pitch line and stop; the click now goes straight to the $9.99 lifetime checkout page. The inline Get Pro links stay for anyone who wants to read first.
- No Gmail tab? The extension opens one for you. Run Cleaner, every scan, purge, bulk apply and Restore used to stop with "open Gmail first". They now open Gmail in a background tab, wait for it to load, and carry on by themselves. If Gmail asks you to sign in, the tab is brought forward and the popup says so instead of guessing.
- The popup opens calm. On a fresh install the Clean tab now fits the Run button on screen without scrolling: the "How it works" reassurance collapses to a single quiet line (its content stays one click away), the Monthly Light Clean preset joins the target chips as one quiet "pick what to clean" family, and the shouting all-caps section labels are now small sentence-case lines. Run Cleaner is the only saturated control on the tab. The version badge moved from the header to the footer, so the header is just the title and the theme switcher.
- The light theme has real surfaces. The page behind the card is a step darker, the card is solid white with a visible border, and sections, preset buttons, chips and rows carry their own borders instead of dissolving into the background. Both themes still meet WCAG AA (4.5:1) for text.
- Pro is now $9.99, still one payment for life. Existing keys are untouched and everything free stays free. Pro now has four pillars: bulk unsubscribe, Storage X-ray purge, the full Smart Suggestions list with bulk apply, and Auto-Pilot.
7.8.1 - Light theme contrast
Fixed
- Light theme text is readable everywhere. Every page was audited for WCAG AA contrast (4.5:1) in both themes. In light mode, several Options labels rendered near-white on white, the explainer note was a gray-on-gray box, and rule pills, code chips, keyboard hints and the snooze button kept colors tuned for the dark theme. All of them now use dark, legible colors when the light theme is active.
- Dim helper text got darker in both themes. Secondary labels (section eyebrows, table headers, empty states, "Or target one thing", toggle hints) sat just below the readability threshold and now clear it in light and dark mode alike.
- Progress page in light mode. Run-phase tags, the version pill, summary chips and keyboard shortcut keys no longer use neon dark-theme colors on light backgrounds, and log timestamps in the terminal view are brighter.
- Version badges in the popup and diagnostics pages and the red "Clear Log" button on the stats page also meet contrast now.
7.8.0 - Smart Suggestions
Added
- The extension now recommends what to clean instead of making you configure it. A new collapsible "Suggested" section at the top of the Clean tab runs one free, read-only scan that finds the senders worth cleaning and says why, in plain English ("142 emails, 96% unread, mostly older than 6 months"). Each card carries one primary action (delete old mail, archive all, or purge large mail) and a Dismiss control.
- Hard vetoes before anything is suggested. A sender is never recommended when they match your whitelist or protected keywords, when any of their mail is starred, or when your Sent folder shows you actually write to them. Vetoes beat every score, and the scan spends at most about 15 correspondence checks per pass.
- Applying a suggestion is an ordinary cleanup run. The suggestion only supplies the search query; tag-before-delete, dry run, the undo log, stats and the post-run recap all apply unchanged. Nothing new can touch mail.
- A local feedback loop ranks future suggestions. Dismissed senders stay silent for 90 days; an applied suggestion slightly boosts other senders from the same domain. The map lives in local storage, bounded, and never leaves the device.
- Pro: the full ranked suggestion list (the top 3 stay free) and bulk apply of checked suggestions in one run. Existing Pro keys unlock both automatically.
Internal
- New read-only engine run kind
smartScan, modeled on the subscription and storage scans; sender addresses pass the same strict email check before entering any query. Results persist undersmartScan(union-merged across rescans), feedback undersmartFeedback, and apply confirmation follows the same pending marker pattern the storage purge uses.
7.7.0 - Popup redesign
Changed
- The popup was rebuilt around one rule: fixed chrome stays small so the content gets the room. The header is a single compact row (the theme switcher moved up into it), the footer is one row instead of a wrapping two, the always-on Pro pitch shrank to a slim strip, and the tab bar slimmed down. On a fresh install the whole Clean tab now fits the 600px popup without scrolling; before, the panel clipped mid-chip behind a native scrollbar.
- One clear hierarchy per tab. Run Cleaner is the only saturated button on the Clean tab. Monthly Light Clean and the one-category targets now read as a single "pick what to clean" preset group, with the targets on a steady 2x2 grid instead of a ragged pill row that wrapped and clipped.
- Calmer visual language. The always-running border glows and button pulses are gone (the amber pulse stays, but only while a run is live), along with the header grid overlay and the gradient title. Scrollable areas use slim themed scrollbars instead of the native arrows, and the popup honors the OS reduced-motion setting.
- Nothing functional changed: every control, id and keyboard shortcut from 7.6 is still in place, and both themes were retuned to match.
7.6.0 - Restore runs
Added
- Every logged run now has a one-click Restore. Tag-before-delete has always labeled a run's mail before moving it, and Gmail keeps Trash for 30 days, so putting a run back was mechanically possible but tedious by hand. The Recovery Log on the Stats page now offers a Restore button on every eligible entry: it searches the run's label in a Gmail tab (Trash for delete runs, outside the Inbox for archive runs), selects everything the way cleanups do, including the "select all conversations that match" banner and its confirmation dialog, and clicks Gmail's own Move to Inbox control. Progress streams onto the page, the run can be cancelled mid-flight, and a finished run reports exactly what happened ("N conversations moved back to Inbox") and marks the entry Restored. Restore is part of the free safety net, not a Pro feature.
- The restore engine is built to fail toward safety. Its only mutating click is the verified move-back control: it never deletes, archives, or marks anything. The Trash toolbar also holds "Delete forever", so the restore finders carry a localized deny-list for it (the same seventeen-language coverage as the other token tables, every string verified against Google's localized help pages) and refuse a deny-listed control no matter how well it otherwise matches, on any of its labels, tooltips or text. A toolbar the engine cannot recognize does nothing: the mail stays in Trash, still recoverable by hand, and the run says so instead of pretending. An empty label search is reported as a finished restore ("nothing left"), because already-restored and already-emptied runs are normal outcomes, not errors.
- Eligibility is honest about what can come back. Restore only offers itself when the run verifiably applied its label; runs whose tagging failed never offer it, because without the label the only alternative is guessing by sender, which could drag unrelated trashed mail back to the Inbox. Delete-mode runs age out with Gmail's ~30-day Trash retention and say so in plain words; archive runs have no deadline. Entries older than the feature simply keep their "Find in Gmail" link.
7.5.0 - Locale support
Fixed
- Bulk unsubscribe now works on non-English Gmail. The engine used to demand the literal English word "Unsubscribe" before it would touch Gmail's header unsubscribe control, so the paid feature silently failed on every other UI language. The control is now trusted by its structure (the class Gmail renders on it in every locale), and the confirmation dialog's buttons are recognized through per-language tables verified against Google's own localized help pages (Spanish "Darse de baja", German "Abbestellen", Japanese "登録解除", and fourteen more). Matching is exact whole text only: an "Unsubscribe and block" style button never passes as a plain confirm, an unrecognized dialog is closed without clicking anything, and unsubscribe links inside message bodies stay off-limits exactly as before.
- Throttling is now recognized in the major locales. Gmail's "try again later" style banners were only detected in English, so a throttled non-English run read as a timeout instead of engaging the adaptive backoff. The detector now carries the equivalent phrases for the same languages the rest of the engine speaks.
Changed
- Archive and label buttons are found in the same languages as delete. Those two token tables covered six and eight languages against delete's seventeen; they now match delete's locale set, so archive-mode cleanups and tag-before-delete work wherever deletes already did.
- The subscription scan searches in your Gmail language. The scan's body-text discovery query used the English word "unsubscribe", which non-English newsletters rarely contain. It now picks the term that fits the mailbox's UI language (one term per run, English fallback) and keeps the two category searches unchanged.
Added
- Diagnostics now shows the last layout-change stop. 7.4 taught the cleaner to stop and say so when Gmail changes its layout, and the popup pointed at Diagnostics, but Diagnostics had nothing to show. The extension now keeps a small local record of the most recent layout-change stop and Diagnostics renders it as a card: how long ago it happened, what the run reported, and the reminder that nothing beyond the already-reported work was touched.
7.4.0 - Ratings and trust
Added
- Your last cleanup greets you on the next open. The popup closes itself when a run starts, so the 7.3 result screen almost never had an audience. Now, if a real (never dry-run) cleanup finished while the popup was closed, the next open replays it through the same result view, marked with a small "Recap" note and how long ago it finished. Each run shows once; the back button returns to the form as usual, and an in-flight run always takes priority over a recap. The earned rating ask (200+ emails or 100+ MB) applies to recaps exactly as it does to live results, so it finally has a chance to fire.
- The cleaner now says so when Gmail changes its layout. Gmail DOM churn is this extension's recurring failure mode. Two hard signals (search results on screen but no select-all checkbox anywhere, and tag-before-delete with no way into the label controls) now stop the run with a plain-words explanation: Gmail changed its layout, nothing was touched beyond what already completed, and an update usually follows within days. Before, the first read as a wrong-looking zero count and the second silently deleted without the promised tag safety net. Finding zero matches for a rule stays perfectly normal and never trips this. The popup points these errors at Diagnostics.
- Gmail locale audit. Every selector and text match the engine uses is now classified in
docs/gmail-locale-audit.md: the destructive path (find, select, delete/archive) is structure-first and works off English, and the genuinely English-only spots (unsubscribe control text, rate-limit phrases, archive button tokens) are documented as 7.5 work. New fixture tests pin the language-independent paths so they stay that way.
7.3.0 - Tabbed popup
Changed
- The popup is now three tabs: Clean, Unsubscribe, Storage. The old single scroll column had grown past a dozen stacked sections; each feature now owns a panel under a fixed-height card (600px, the most Chrome allows a popup), so the header, tab bar and footer stay put and only the active panel scrolls. The tab bar is keyboard-first: arrow keys move between tabs, Home/End jump, and screen readers get real tab semantics.
- Cleanup Strategy and Safety moved into one Advanced disclosure. The three strategy dropdowns and the safety toggles now live in a collapsed "Advanced" section on the Clean tab, and it remembers whether you left it open. Defaults are unchanged; most runs never need to open it.
- The result screen replaces the form. When a run finishes with the popup open, the summary, the share/rate buttons and the rating ask take over the Clean tab instead of piling up underneath it, with a clear "Back to the cleaner" button.
- One banner at a time. If several notices are eligible, only the most important shows: Gmail access first, then the schedule snooze notice, then the pin hint.
- "How it works" folds itself away. The safety explainer starts open for new installs and collapses once your first cleanup is recorded; it stays a click away.
- Upsells now lead with your own numbers. After a scan, the Unsubscribe pitch opens with how many mailing lists were found and the Storage pitch with how many senders hold how many MB (always the scan's floor estimates). Before any scan, a short static line shows instead.
- The rating ask is earned, not scheduled. The star prompt now appears only right after a real (non dry-run) cleanup that removed at least 200 emails or freed an estimated 100 MB and up. "Maybe later" still dismisses it for good.
7.2.0 - Storage X-ray
Added
- Storage X-ray. A new popup section that answers "what is eating my Gmail storage" by sender. The free scan is read-only: it walks Gmail's own size searches in tiers (25 MB, 10 MB, 5 MB), credits each large email its tier floor, and reports a total reclaimable estimate plus your top three space hogs. Every figure is a floor, never a guess upward.
- Pro: full ranked list and one-click purge. Pick the senders worth evicting and purge their large mail in one run. The purge is a standard cleanup under the hood (a
from:(...) larger:5Mrule), so tag-before-delete, Trash's 30-day window, the whitelist, protected keywords, dry run and the recovery log all apply unchanged. An age filter (default 6 months) protects recent mail. Purged senders keep a badge across rescans. - The Pro pitch now writes itself: $5 once versus about $20 every year for more Google One storage.
Changed
- Existing Pro keys unlock Storage X-ray automatically; one license covers both Pro features.
7.1.0 - Firefox and Edge support
Added
- Firefox support. The extension now ships a dedicated Firefox build: event-page background instead of a service worker, a stable AMO add-on ID, options opening in a tab, and a declared no-data-collection policy (everything still runs locally).
npm run build:firefoxproduces it;npm run zip:allproduces both store zips. Verified clean by addons-linter, the same validator Firefox Add-ons runs on submission. - Edge support, documented. Edge is Chromium, so the Chrome build installs there as-is; the README now says how.
- Gmail access banner. If the browser reports no permission for mail.google.com (Firefox lets users revoke it per extension), the popup shows an amber banner with a one-click Allow button instead of failing with a cryptic injection error.
- Rating and share links now open the store matching your browser: Firefox users land on Firefox Add-ons, everyone else on the Chrome Web Store.
Changed
- Toolbar icon is finally legible. The 16px and 32px icons are re-cut from the source art with the envelope filling the frame (previously the 32px kept the whole tile, leaving the glyph tiny in the toolbar) and brightened for dark toolbars.
- Deep-intensity cleanup now confirms inline: the Run button arms and asks for a second click instead of popping a system dialog. Firefox silently swallows dialogs in popups, which would have made deep cleans unstartable there; the two-click flow behaves the same everywhere.
- Desktop notifications no longer pass the priority flag, which Firefox rejects outright.
7.0.2 - Neon icon artwork
Changed
- Final icon artwork. The interim vector icon from 7.0.1 is replaced with the finished brand image: a neon cyan envelope with sweep lines glowing on a dark tile. The 16px toolbar size crops in on the envelope so it stays readable; corners are masked transparent at every size. Full-resolution source lives in
assets/icon-source.png. - The popup header mark now shows the icon tile edge-to-edge instead of floating a small copy inside a second tile.
- Highlight cyan (
--primary-strongand its hardcoded echoes) nudged from #67e8f9 to #7bf1fd to match the icon's neon core, dark theme only; the light theme keeps its deeper teal for legibility. - The buy and activation pages at gmail-cleaner-pro.netlify.app now carry the icon as their favicon (redeployed).
7.0.1 - New brand icon
Changed
- New icon set. Replaced the old icon (a Gmail logo with a broom pasted on top) with an original mark: a cyan envelope sweeping clean on a dark tile, matching the extension's own design system. Original artwork also removes any trademark ambiguity with Google's Gmail branding. The SVG sources live in
icons/next to the PNGs; each size (16, 32, 48) is tuned by hand so the toolbar icon stays legible. - Icon PNGs now carry an alpha channel, so the rounded tile sits cleanly on both light and dark browser toolbars.
Fixed
- The build no longer copies the SVG icon sources into
dist/or the store zip; Chrome only loads the PNGs. - Cleared 3 npm audit advisories in dev tooling (Babel, form-data, js-yaml). Nothing that ships in the extension was affected.
7.0.0 - Subscription scan + bulk unsubscribe (Pro)
Deleting hides old mail; unsubscribing stops new mail. This release adds a way to see every mailing list that emails you and unsubscribe from the ones you never read, in one pass, plus a one-time $5 Pro unlock to run it. Everything that was free stays free forever. No existing feature moved behind the paywall.
Added
- Subscription scan (free). A new "Unsubscribe from mailing lists" section in the popup. The scan runs a few read-only discovery searches and samples the senders behind your subscription-style mail, then lists them ranked by how much they send. It changes nothing: no mail is moved, deleted, or altered. It is a plain inventory of who fills your inbox.
- Bulk unsubscribe (Pro). Select the senders you never read and unsubscribe from all of them in a single pass. For each sender the engine opens one of their messages and clicks Gmail's own built-in Unsubscribe control (the header "Unsubscribe" link and its confirmation dialog), which is backed by the sender's List-Unsubscribe header. It never touches unsubscribe links inside message bodies, which can point anywhere. Senders with no one-click option are flagged "manual step needed" rather than guessed at. Capped at 25 senders per run; re-run for more. Sender addresses are validated to a strict email shape before going into a
from:(...)search, so a crafted address can never break out of the query. - Pro license. A one-time $5 lifetime purchase unlocks bulk unsubscribe. Keys are verified entirely on your device with a public key built into the extension (ECDSA P-256 via WebCrypto); the extension never contacts a server to check a license, not even once. A valid key works fully offline. Activate it from the popup's Pro link or the Options page's new Pro License section. The key is a signed token with no personal data, stored in Chrome sync so Pro follows you to your other signed-in browsers.
Changed
- The popup and progress page now promote Pro instead of tips and affiliate links. The Buy-Me-a-Coffee / Cash App tip links and the Amazon affiliate product section have been removed from the popup, the progress dashboard, and the Options page. In their place is a single, honest Pro upsell (hidden entirely once a license is active). One product to support the extension, not a wall of outbound links.
- Store listing title and description now mention unsubscribe so the feature is discoverable by people searching for it.
Security / privacy
- No new permissions. Bulk unsubscribe reuses the existing
https://mail.google.com/*host access and the same pointer/mouse-driven clicking the cleanup engine already uses. - The "runs locally, nothing phones home" promise is preserved for the extension itself. The only network calls in the whole flow are ones you start: opening the Stripe checkout page, and the post-checkout activation page fetching your key. Both are part of the purchase flow, not the extension, and neither involves any Gmail data. See SECURITY.md for the full breakdown.
- The license-issuing service (a tiny Netlify function that verifies your Stripe checkout session and returns a signed key) lives in
netlify/in this repo. It is not part of the shipped extension and is excluded from the build.
6.1.0 - Protected keywords (subject shield)
A content-based safety net to sit alongside the sender Whitelist. The hardcoded Safe-Mode subject guard (receipts, invoices, shipping) is now joined by a list you control.
Added
- Protected keywords. A new "Protected Keywords (Never Delete)" section on the Options page. Any word or phrase you list there protects every message whose subject contains it from every rule, by appending a single
-subject:(kw1 OR "two words" OR ...)clause to each search. Where the Whitelist protects by sender, this protects by subject content (e.g.tax,invoice,"flight confirmation",lease). It applies to manual and scheduled runs, in both live and dry-run mode, and it coexists with Safe Mode's built-in subject guard as a separate clause (both only ever narrow what a rule matches). - Keywords ride along in config Export/Import (backup format bumped to v3; older v1/v2 backups import cleanly and never wipe existing keywords).
Safety / internals
- Keywords are sanitized at three layers (options page, popup, and a defence-in-depth copy at the engine boundary): quoting, grouping, and boolean operators are stripped so a keyword can never break out of the
subject:( ... )group it is injected into; the list is trimmed, deduped case-insensitively, and capped (25 keywords, 50 chars each). The only failure mode is "protect more mail," which is the safe direction. No new permissions.
6.0.0 - Recovery overflow-menu fix, focused targets, accurate counts
The big one. Restores the recovery-by-label safety net, makes large cleanups actually clean past the first screen, fixes affected counts, and adds one-click category targeting.
Fixed
- Deletion actually deletes on current Gmail. Two compounding bugs are fixed. (1) The toolbar Delete / Archive are Closure buttons that only react to a real pointer/mouse press, so the engine's plain
element.click()was a silent no-op: rows looked selected but nothing reached Trash. A fullpointerdown/mousedown/mouseup/clicksequence (fireMouseSequence) now drives the action buttons, the bulk-confirm dialog, the "select all matching" link, and the overflow menu. Row and master checkboxes keep their plainclick(); they respond to the click event and amousedownthere can double-toggle the selection. (2)openSearchaccepted the page as loaded the instant the grid had any row, which during Gmail's in-place hash transition was the previous query's leftover rows, so the engine acted on a stale page and raced through every query in seconds selecting nothing. It now waits for the result list to turn over to the new query (or settle empty). Verified live: a deep run moved 179 conversations to Trash. - Tag-before-delete no longer stalls the run. The recovery-label step used to wait up to five seconds on every delete pass for a label input that never appeared: Gmail's "Label as" is now a hover submenu inside the "More email options" overflow (not a dialog), and the old code grabbed the first (hidden) role=menu and looked for the input only under role=dialog. It now opens the overflow with the pointer/mouse sequence, resolves the menu that is actually on screen, hovers the "Label as" submenu, and searches menu-scoped selectors for the input, with the wait capped near a second so a miss skips fast. Deletion never blocks on tagging.
- Tag-before-delete works on current Gmail again. Gmail moved the "Label as" control into the toolbar's "More email options" overflow menu, so the old toolbar-only finder never found it and recovery-by-label silently never happened. The engine now opens the overflow menu (with a keyboard-shortcut fallback) to reach it, and the undo log's
taggingFailedflag is honest instead of alwaysfalse. - Accurate affected counts. A confirmed "all N conversations selected" bulk delete uses the match total; a per-page delete uses the visible selection it actually acted on. Fixes the over-counting that inflated freed-MB and category stats on chunked runs.
- Popup completion UI is wired to the real messages. The popup was listening for done/cancelled/error message types the engine never sends; it now reads the actual progress contract, so the result summary, success actions, and recovery toast fire correctly.
- No more lost stats / undo / sender data. The service worker's read-modify-write storage handlers are serialized, so the rapid per-pass messages no longer clobber one another.
- Scheduled cleanups stop drifting. Alarms are anchored to the last run plus the interval instead of resetting on every browser restart.
- Review mode can't hang forever. If the progress tab is closed without a response, the run skips that rule after a timeout.
- Diagnostics "content script attached" check reads the correct flag, so it reflects reality during a live run.
Added
- Focused targets. One-click chips in the popup (Promotions, Big attachments, Social & updates, No-reply) run a small, age-guarded rule set for just that category instead of the full intensity sweep. All global safety guards still apply.
- Layout-change telemetry. If Gmail reshuffles its selection classes, the engine warns instead of silently deleting nothing.
Removed
- Dead Pro-tier lifetime-stats writer (the paid tier was dropped).
5.0.7 - Per-row selection fallback (real fix for the silent-no-delete bug)
Diagnosed by inspecting the live Gmail DOM against mail.google.com. The "selecting it then just not deleting anything" report turned out to be a far deeper Gmail behavior than the v5.0.6 verification fix addressed:
- A programmatic
.click()on the master checkbox toggles the master's ownaria-checkedto"true"and Gmail applies a CSS rule that fills in blue checkmarks on every visible row. BUT the row-level selection (tr.x7class,[role="checkbox"][aria-checked="true"]) never gets populated. - Gmail's delete handler reads from the real selection model. With it empty, the click on Delete is a no-op. We then reported "0 affected" for runs where nothing got deleted because nothing was actually selected.
- Verified: clicking each row's checkbox individually DOES populate the real selection model (row gains
x7class, checkboxaria-checkedflips to"true").
Also discovered the same way:
- Gmail no longer surfaces "N selected" text anywhere inside
div[role="main"]in the current UI, that's whyextractSelectedCount()always returnednullon real runs. - The Labels button has moved entirely into the "More email options" overflow menu (the toolbar never has a direct Labels button now).
Fixes:
extractSelectedCount()now countstr[role="row"].x7inside the result grid as the primary selection signal. Legacy text scrape retained as fallback for older Gmail layouts.clickMasterCheckbox()keeps clicking the master first (cheap; works when Gmail's master is in a layout that does cascade), but if the resulting selection count is 0, it falls through toselectAllVisibleRowsIndividually()which iterates every visible row's checkbox and clicks each. That populates Gmail's real selection model, so the subsequent Delete click actually deletes.
Tag-before-delete (the "Label button not found" warning) still goes through the old finder; that path is queued for a follow-up patch that opens the "More email options" menu first. Deletions now work correctly without the tag step, the undo log still records the metadata, just without the searchable label.
5.0.6 - Delete verification + accurate affected counts
Diagnosed from a user report: "it's selecting it then just not deleting anything." Two compounding bugs:
extractSelectedCount()returnsnullwhen Gmail's "N selected" text drifts to a layout the function doesn't recognise.waitForActionProcessing()treatednullas success, so the engine reported0 affectedand moved on, regardless of whether the delete actually fired. Silent false-positive.
Fixes:
waitForActionProcessing()now requires positive evidence that the action happened: selection count dropped from a known-positive start, grid row count decreased,hasNoResults()settled, or Gmail's "Undo" toast appeared. Returns{ ok, signal, startRowCount, endRowCount }so callers know which signal fired and can derive the affected count from row delta.- The affected count is now derived from the strongest available signal: declared selection > row-count delta >
rowsBeforewhen page settled empty > 0. No more silent "0 affected" when rows actually disappeared. tryDeleteAction/tryArchiveActionlog the button's aria-label / tooltip / title when clicked, so the progress log shows exactly which control was activated. IffindButtonByTokensever scores the wrong element, the next log will say so.- New helpers:
getGridRowCount()andfindUndoToast().
If Gmail genuinely refuses the click (UI state, focus, etc.), the engine now throws TimeoutError and the retry loop re-attempts: better to fail loudly than silently lie about success.
5.0.5 - Empty-search fast path + still-waiting beats
Diagnosed from another stuck-run log (query 1: larger:20M taking ~2 minutes before any retry, then retrying 6 times). openSearch()'s wait condition only returned true when the result grid contained at least one row, so any query that legitimately matched zero mail (very common once global guards strip starred / important / unread / user-labeled threads) sat for the full 20s wait, threw a TimeoutError, and retried 6 times before either skipping (5.0.2) or killing the run (≤5.0.1).
openSearch()now also accepts Gmail's empty-state container (td.TC) as a valid "search settled" signal. Zero-match queries now resolve in well under a second;hasNoResults()downstream classifies them withcount=0cleanly.waitFor()accepts an optionalonTickcallback;openSearchuses it to surface "Still waiting for search results (Ns)..." beats every ~5s so the user has evidence the engine isn't dead while Gmail is slow to render a heavy search.
5.0.4 - Spinner stays animated under reduced motion
The blanket prefers-reduced-motion: reduce rule in shared.css killed every animation on the page via animation-iteration-count: 1 !important, including the loading spinner. The spinner is a state indicator ("system is busy"), not decoration, so reduced motion shouldn't freeze it (WCAG carves out essential animation explicitly).
Added a follow-up rule inside the same media query that re-enables the spin animation for .spinner (0.6s) and the primary-button busy spinner (.primary.loading::after, 0.8s). Higher specificity beats the universal selector under equal !important, so the override wins reliably.
5.0.3 - CSP data: fix for inline SVG chevrons
The meta CSP on every extension page declared img-src 'self', which blocks data: URLs. The select-dropdown chevron (an inline url("data:image/svg+xml,...") background image in popup.html and options.html) tripped this on every render, producing a console error and dropping the down-arrow glyph on the rule-intensity / age selects.
Added data: to img-src on all five extension pages. No new external origins; the directive still rejects any non-data: / non-self image source.
5.0.2 - Per-query failure isolation
Caught from another real-world log: in v5.0.0 / v5.0.1, when a single query exhausted its 6 retries, processQuery() re-threw the TimeoutError, which propagated up to main() and aborted the entire run on the first stubborn rule. A user with one slow search (has:attachment larger:10M older_than:6m matching too many results for Gmail's UI to render in time) lost all 11 queries.
- After retries exhausted, the engine now classifies the failure as per-query (not run-wide) for known-transient errors (RateLimit / Timeout). The query is recorded as failed, a warning is emitted to the progress log, and the next rule starts. Cancellation and unexpected errors still abort the run.
- The 5.0.1 wall-time budget still fires for slow retries; the new exhausted-retries branch fires for fast retries that simply keep failing.
5.0.1 - Engine resilience
Diagnosed from a real-world stuck-run progress log: a single Gmail search (has:attachment larger:10M older_than:6m) hit the action- processing timeout, the engine entered exponential backoff, and the log just said "Backoff 1758ms (timeout)" with no indication what was actually waiting or how many retries were left.
- Descriptive backoff messages. The retry catch path now passes the underlying error message into
backoff(), so the log reads "Backoff 3339ms (timeout: Action processing timed out (Gmail did not refresh selection/results))" instead of bare "timeout". - Per-query wall-time budget. New
GUARDRAILS.QUERY_WALL_TIME_BUDGET_MS(5 minutes). If a single query has been retrying for that long it gets abandoned with a clear warning and the run moves to the next rule, so one bad query can't pin the whole run for 10+ minutes. - Retry-counter progress. Each retry now logs "<label>: retry N/6 after timeout" so the user can see structured progress through the retry budget instead of watching opaque backoffs.
5.0.0 - Extended Upgrade
A major release closing every open GitHub issue, adding ten substantial new features, and shipping a deep deglitch + test pass across the codebase.
New features
- Light / dark / system theme. Every extension page (popup, options, stats, progress, diagnostics) honours
prefers-color-schemeautomatically, with a manual switcher pill in each header. Choice persists across sessions. - First-run onboarding wizard. A two-step popup explains the safe-by-default flow and points new users at Dry Run, custom rules, and the
?keyboard shortcut. Skippable; shown once per install. - Custom rule template library. Options page now has a chip row of curated safe queries (old promotions, large attachments, GitHub digests, Slack, LinkedIn, etc.) that add a custom rule with one click. Each template still passes through the same validator before persisting.
- Drag-and-drop rule reordering. Custom rules can be reordered with a drag handle in the options page; order is preserved in sync storage.
- Snooze / vacation mode. Pause all scheduled cleanups for N days from the options page. The popup surfaces a banner whenever snooze is active. Manual runs still work; only schedules are suppressed.
- Top senders dashboard. The stats page now ranks the senders that showed up most often in your cleanups, with Search-in-Gmail and one-click "Protect" (add-to-whitelist) buttons per row. Sender samples are collected by the content script before each delete batch and aggregated by the service worker.
- Desktop completion notifications. Optional opt-in toggle in the options page; when enabled, Chrome surfaces a system notification when a cleanup finishes so you don't have to keep the progress tab visible. New
notificationspermission, used only when the user enables it. - Keyboard shortcut overlay. Press
?in the popup for a modal listing every shortcut. Esc closes any open modal first, then the popup. - Auto-pause warning for large batches. When a single delete batch exceeds 2,000 conversations, the engine emits a warning to the progress page before acting so the user can review.
- Sender + thread-id sampling for the undo log. Each undo entry now carries a sample of message thread IDs and a sender count taken from the Gmail list view before deletion. Tag-label search is still the primary recovery path, but it is no longer the only one.
Issue fixes
- #22 - Popup intensity restore now persists the user's raw UI selection (preserves "Monthly") instead of round-tripping through a dead
=== "monthly"branch. A legacy-format migration handles existing storage entries. - #20 -
runCleanupnow uses an atomic-style "claim + verify" pattern (randomrunId, re-read after a micro-pause) before touching the Gmail tab, so two popups opened in parallel cannot both inject. - #19 -
tabsSendMessagefailures are now classified (tab_closedvspermissionvsother) and the cancel handler surfaces a specific message instead of always saying "tab unreachable". Reuses the newGCC.classifyChromeErrorhelper. - #17 - The stats page poller pauses on
visibilitychangewhen the tab is hidden, resuming with an immediate refresh when the user returns. GenericGCC.pollingIntervalhelper is reusable for any future visibility-aware loop. - #16 -
web_accessible_resourcesremoved from the manifest.shared.css,shared.js, andbrowser-polyfill.jswere only ever needed by extension pages (which have direct access), so exposing them tomail.google.comwas a fingerprinting vector with no upside. - #10 - Schedule writes from the service worker now go through a quota-aware
safeSyncSet. Oversized payloads throw a clear error and the save handler relays it back to the options page rather than silently truncating. - #9 - Undo log entries now carry sampled message thread IDs and a sender count from the Gmail list view, recorded before each delete batch.
- #8 - Custom rule queries are now validated at two layers: the options-page editor refuses (and the engine quietly skips) any query that targets protected mail (
is:starred,is:important,in:sent,in:drafts, etc.) without negation. Soft warning whenin:inbox/in:allis used without an age qualifier. - #7 -
confirm()and end-of-runalert()are now skipped whenCONFIG.scheduledis true. Scheduled runs that hit the soft cap or huge-run threshold decline cleanly and report via the progress log instead of hanging on a modal dialog. - #6 -
runScheduledCleanupchecks theACTIVE_RUNmarker before injecting and claims its own marker for the duration. A manual cleanup in flight blocks the schedule rather than getting itswindow.GMAIL_CLEANER_CONFIGclobbered.
Internal / DX
- New
GCC.theme,GCC.pollingInterval,GCC.safeSyncSet,GCC.validateGmailQuery,GCC.classifyChromeError,GCC.notify,GCC.downloadFileutilities inshared.js. sanitizeConfigpropagatesscheduled,runId, andscheduleIdso the engine can identify itself in undo log entries and confirmation guards.- Background SW gained
gmailCleanerGetSnooze,gmailCleanerSetSnooze,gmailCleanerAddToWhitelist, andgmailCleanerRecordSendersmessage handlers. Unknown message types now always respond instead of leaving the port open. - Test coverage extended (issue #14, partial): new pure-function tests for
validateGmailQuery,classifyChromeError,safeSyncSet,pollingInterval, and the content script'squeryHasDangerousTokendefense-in-depth filter.
Folded-in 4.3.x cleanup (previously listed as Unreleased)
- Defer-loaded the three script tags on every extension page so module-scope DOM reads always fire post-parse.
GCC.sendMessageresolves to{ error, code }on failure (codes:no_chrome,send_failed,threw).- Whitelist sanitizer in
contentScript.jsaligned withoptions.js; hand-written values like"user+tag@domain"(no TLD) drop cleanly.
4.3.1
- Removed dead
broadcastToExtensionPages()helper from the service worker. It was defined but never called; extension pages already receive progress messages directly viachrome.runtime.sendMessage. No behavior change. - Fixed the stale
v4.0.0version badge in the popup header. The badge now reads its label fromchrome.runtime.getManifest()at init, so future version bumps cannot leave the visible chrome out of sync with the manifest. - Added the missing
aria-controlslink between the Safety & Guardrails<summary>and its content panel in the popup. The other collapsible sections (Reassurance, Affiliate) already had it; this brings Safety inline for screen readers that surface the relationship. - Added a
tests/version.test.jssuite that assertsmanifest.json,package.json, every*_VERSIONscript constant, and the visible HTML version badges all agree. Catches drift in CI before it ships. - Pinned the extension-page Content Security Policy explicitly in the manifest (
script-src 'self'; object-src 'none'). MV3's default already enforces it, but writing it down keeps the policy reviewable. - Removed the deprecated
document.execCommand("copy")clipboard fallback in the diagnostics and progress views. Both pages now rely on the async Clipboard API and surface a "failed to copy" toast on error. - Replaced the duplicated
formatNumberinprogress.jswith the shared helper fromshared.js. LocalformatDurationandformatMBstay because they intentionally render compact values for the chip layout. - Harmonized the "Find in Gmail" link in the stats undo log to
rel="noopener noreferrer"so every external/new-tab anchor in the extension matches.
4.0.0
Background Service Worker
- Added persistent background service worker for messaging coordination, scheduling, and stats persistence.
- Extension no longer relies solely on popup staying open for script injection.
Undo / Recovery System
- Tracks all cleanup operations with query, label, count, and action type.
- Recovery log accessible from the new Statistics page with direct Gmail search links.
- Tagged emails can be found via Gmail label search for easy recovery within 30-day Trash window.
Scheduled / Automatic Cleanups
- Create daily, weekly, or monthly cleanup schedules via the Options page.
- Uses chrome.alarms API for reliable recurring execution.
- Schedules can be enabled/disabled or deleted individually.
- Requires Gmail to be open in at least one tab.
Custom Rules Editor
- Build your own Gmail search queries with per-rule action (delete, archive, label only).
- Custom rules run alongside built-in intensity presets.
- Manage up to 20 custom rules from the Options page.
Multi-Account Support
- Detects multiple Gmail tabs (different Google accounts).
- Account selector pills appear in the popup when multiple accounts are open.
- Choose which account to clean before starting.
Statistics Dashboard
- New dedicated stats page with overview cards (total runs, emails cleaned, space freed).
- 30-day daily activity bar chart.
- Category breakdown showing which rule categories cleaned the most.
- Full run history table with intensity, duration, and action type.
- Auto-refreshes every 30 seconds.
Shared CSS & Build Pipeline
- Extracted common design tokens and base styles into shared.css.
- Added package.json with build scripts (esbuild minification, zip packaging).
- Reduced CSS duplication across all extension pages.
Smart Whitelist Suggestions
- Tracks sender interactions (opens, replies) to suggest senders you engage with.
- Suggestion chips appear in the popup for one-click whitelist additions.
- Protects senders you actually read from being cleaned.
Firefox & Edge Support
- Added browser-polyfill.js shim for WebExtensions API compatibility.
- Promisifies Chrome callback APIs and creates browser.* namespace.
- Extension now works across Chrome, Edge, and Firefox with the same codebase.
Build & Development Tooling
- Added build.js script for dist packaging and optional JS minification.
- Added zip creation for Chrome Web Store submissions.
- Added package.json with lint and build scripts.
3.5.0
Bug Fixes & UX Improvements
- Fixed invalid escape sequences in content script selectors.
- Improved error handling for edge cases during Gmail DOM automation.
- Refined rate-limit backoff and recovery logic.
- Minor UI polish across popup, progress, and options pages.
3.4.0
Safe Mode Subject Guard
- Added subject-line protection for receipts, invoices, order confirmations, shipping notices, and refund emails when Safe Mode is enabled.
Adaptive Throttling Improvements
- Tuned rate-limit backoff parameters for more reliable long runs.
- Added de-escalation logic to recover faster after temporary Gmail errors.
3.3.0
Popup UX overhaul (clearer + safer starts)
- Added a real button state machine (starting, running, success) with better status copy.
- Added toast notifications for key actions and failures.
- Added best-effort popup progress bar (so users get feedback before the popup auto-closes).
- Added "open gmail" helper when no Gmail tab is detected.
- Persisted last-used config more reliably (session + local fallback) so runs feel consistent.
Active run detection + quick actions
- Popup detects an already-running cleanup via an
activeRunmarker (with a best-effort TTL). - Quick actions to Cancel or Open Progress when a run is active.
- Popup detects an already-running cleanup via an
Progress dashboard v2 (major UI + usability upgrade)
New glass-style Progress page with:
- Live phase tag + percent bar
- Activity log with timestamps + log levels
- Copy logs / Clear logs controls
- Per-query summary table with counts + duration
- Cleaner "done / cancelled / error" end states
Added keyboard shortcuts:
Esccancels run (or skips review when a review modal is open)Enterproceeds in review modalCtrl/Cmd + Ccopies logs (when no text is selected)
Review Mode upgrades
- Added a proper modal-based review prompt (Proceed / Skip per rule) from the Progress page.
- Progress page sends explicit signals back to the Gmail tab (
resume/skip) for the current rule.
Recovery tools (when Gmail reloads mid-run)
- Reconnect button: pings the Gmail content script with a timeout and reports success/failure.
- Re-inject button: re-injects last config (if available) + content script to resume progress messaging.
Share + support polish
- Added "Share" flow (copy Web Store link to clipboard, fallback to opening the link).
- Tip intent tracking stored locally (user-initiated link clicks only).
Internal hardening
- More defensive Chrome API checks (tabs/storage/scripting availability).
- Better URL param parsing for
gmailTabId. - Log caps and DOM caps to prevent runaway memory usage in long runs.
3.2.0
New Preset: Monthly Light Clean
- Added a "Recommended" quick-action button in the popup.
- Automatically configures the cleaner to Safe Mode, Trash action, and a 3-month age limit.
- Designed for safe, repeated maintenance of old promotions and junk.
Storage Freed Calculation
- The cleaner now estimates the storage space released (in MB) during the run based on attachment flags and message types.
- The final result summary now displays: "Deleted X emails / freed Y MB".
Smart UI & Onboarding Improvements
- Pin Hint: Added a dismissible banner encouraging users to pin the extension for easy access.
- Mini FAQ: Added reassurance text in the popup explaining that items go to Trash (30-day safety net) and are not permanently deleted immediately.
- Success Actions: New completion screen with buttons to "Rate on Chrome Web Store" and "Share extension".
- Soft Rating Prompt: A gentle request for a 5-star rating appears after 2-3 successful runs.
Affiliate & Support
- Added "Jude's cheap storage & setup picks" section in the Popup and Progress window to recommend physical storage solutions for users running out of digital space.
3.0.0
Major Feature: Review Mode
- Added a "Review matches before action" toggle. When enabled, the cleaner pauses after finding results for a rule, allowing you to see exactly what will be deleted and choose to Proceed or Skip that specific query before any action is taken.
Major Feature: Global Whitelist
- Introduced a global exclusion list. You can now specify email addresses (e.g., family or work VIPs) that are automatically excluded from all rules, ensuring they are never archived or deleted.
Cleanup History
- The Diagnostics page now tracks your last 10 runs locally. You can review past performance, including the date, mode (Dry Run vs Live), Archive vs Delete setting, and total conversations affected.
Core Improvements
- Updated the automation engine to support interactive "Pause/Resume" signals for Review Mode.
- Migrated run stats storage to
chrome.storage.localto support history tracking without hitting sync limits.
2.10.5
Stability + clarity patch focused on safer runs and more honest feedback:
- Added a soft cap on how many conversations a single run will act on, with a confirmation step before continuing on very large inboxes.
- Improved handling of empty or failed Gmail searches so runs end with clear "nothing matched" or "search failed" messages instead of looking like a silent success.
More accurate progress and end-of-run reporting:
- Progress bar now reflects the number of conversations matched at the start of the run, not just rough batches.
- Tracked counts for "checked", "labeled / archived", and "skipped" threads and surfaced them in the end-of-run summary.
- Dry Run now ends with a "would have affected" summary so you can see what a real run would do without touching your inbox.
Better safety and recovery behavior:
- Hardened the content script boot sequence to avoid duplicate injection and to fail visibly if Gmail isn't ready.
- Ensured runs cannot stay stuck in a "Running" state after errors, and that cancel / stop exits cleanly.
Optional Debug mode for advanced users:
- New toggle in settings that logs key events (start, batches, errors) with a consistent prefix in the browser console.
- Designed for bug reports and troubleshooting without changing how the cleaner itself behaves.
> Note: 2.10.1-2.10.4 were internal / pre-release iterations. Their changes are folded into the 2.10.5 notes above.
2.10.0
Added new safety guardrails and a non-destructive mode option:
- You can now choose to archive matching conversations instead of deleting them for extra-safe first runs.
- New global guardrail can skip starred and Important threads so they're never touched by bulk cleanups.
- Added a "minimum age" dropdown so rule sets only act on mail older than 3, 6, or 12 months, even if a rule is looser.
Improved rule editing and testing on the Options page:
- Each rule set now includes a quick "open in Gmail" test action so you can preview what a query will match before running a cleanup.
- Clarified copy around what Light / Normal / Deep target and how Safe Mode further narrows the rules.
Internal configuration cleanup:
- Plumbed the new guardrail settings through popup → Gmail tab → content script so everything stays in sync.
- Kept all behavior local-only with no external servers required for these new features.
2.9.8
Fixed issues when running in Brave and multi-Gmail setups:
- Improved detection of the "active" Gmail tab so cleanup runs against the right account.
- Reduced dependence on the extension docs / options tab being in focus.
- Hardened content script messaging and reconnection behavior when Gmail reloads mid-run.
- Small polish to the Progress window layout and copy.
- Internal refactors to keep progress logic, rule sets, and UI wiring in sync.
2.9.7
Added a richer Progress window:
- Live percent complete and current phase text.
- A summary table with per-query counts and durations.
- "Tags" area for showing current rule labels / hints.
Added Reconnect and Re-inject buttons to recover from:
- Gmail reloads
- Lost content script connections
Improved Cancel behavior:
- Cancels the current phase cleanly.
- Closes the progress session without leaving partial state.
2.9.6
Introduced the Tip / Support panel in the Progress window:
- Optional section explaining how to support the project (e.g. small tips).
- Does not affect privacy or Gmail behavior.
Tuned the Progress UI styling:
- Darker background, softer card edges, and more readable text.
- Better spacing on small windows.
2.9.5
Added optional "tag before trash" behavior in the cleanup flow:
- Before deleting, messages can be tagged with a dedicated Gmail label.
- This makes it easier to search the Trash by that label and verify results.
- Internal changes to how rule metadata is passed from options → progress page.
- Minor logging clean-up and more defensive checks for missing DOM elements.
2.9.4
Expanded the cleanup rule system:
- Introduced three intensities: Light, Normal, Aggressive.
- Each intensity uses its own array of safe Gmail queries (large attachments, promos, social, newsletters, etc.).
- Synced default rules between the options page and the run logic using a shared
DEFAULT_RULESobject. Adjusted some default queries to be safer:
- Slightly older date thresholds for aggressive modes.
- Clearer focus on bulk, low-value categories.
2.9.3
New Progress window UI (HTML/CSS refresh):
- Card-based layout with a single clear progress bar.
- Status line, details text, and compact controls.
Better error reporting when:
- No Gmail tab is found.
- The content script fails to attach.
- Slight performance improvements in how the extension advances between queries.
2.9.2
Improved options page:
- Cleaner descriptions of each rule set.
- Safer defaults for new users.
More robust handling of local storage:
- Defaults are applied if settings are missing or invalid.
- Reduced redundant messages between popup → background → content scripts.
2.9.1
Added Safe Mode toggle:
- Runs only the safest, least risky rule subset.
- Skips any "heavier" queries that might get too close to long-term history.
Improved Dry Run behavior:
- Ensures no destructive actions are taken when Dry Run is on.
- Still drives the UI and progress screen so users can see what would happen.
2.9.0
Major internal refactor of the run logic:
- Centralized state management for phases, counts, and errors.
- Clear separation between "rules" and "execution engine".
Better handling of Gmail rate limits and slower accounts:
- Slight randomized delays between operations.
- Reduced chance of hitting hard limits during long runs.
---
2.8.x
- Added support for more Gmail categories (Updates, Forums) in some rule sets.
- Tuned large-attachment filters (e.g.
larger:20M,has:attachment larger:10M older_than:6m). - Fixed occasional issues where "Select all conversations" was not clicked properly on some layouts.
- First iteration of the dark theme for the progress window.
---
2.7.x
Introduced Dry Run mode for the first time:
- Simulates the run without deleting messages.
- Helpful for sanity-checking rules on big, old inboxes.
- Added basic error banners when Gmail layout does not match expected selectors.
- Minor UI cleanup on popup text and buttons.
---
2.6.x
- Improved handling when multiple Gmail accounts are open in the same browser session.
- Early support for non-Chrome Chromium browsers (Brave, Edge, etc.).
- Small optimizations to reduce flicker when switching between search queries.
---
2.5.x
- More robust detection of key Gmail buttons (search results, select-all, delete).
- Reduced chances of running with Gmail still loading or partially rendered.
- Light performance tweaks and code organization.
---
2.0.0 - MV3 Rewrite
- Migrated the extension to Manifest V3.
Re-architected the extension around:
- A service worker background script.
chrome.scriptingfor injecting the Gmail automation.- A dedicated Progress page to show run status.
- Added configurable options for future rule tuning.
---
1.x - Initial Releases
- First public release of Gmail One-Click Cleaner.
Core feature:
Run a sequence of Gmail searches targeting bulk clutter:
- Promotions
- Social
- Newsletters / marketing
- Large attachments
- Select all results and delete in bulk.
- Basic popup UI with a single Run cleanup button.
- Simple, local-only behavior with no external servers.