TechMoon 科技月球
WordPress、SEO 與 AI 工具實測指南
TechMoon 科技月球
WordPress、SEO 與 AI 工具實測指南

Gmail Cleaner 是用你自己的 Google OAuth 憑證、在本機批量退訂電子報、按發件人刪信、把大量未讀郵件一次標成已讀的開源工具,申請的授權範圍從原始碼可以逐行查證。
用 AI 摘要這篇文章:
Gmail Cleaner 是一款用你自己的 Google OAuth 憑證、在本機批量退訂電子報、按發件人刪信、把成千上萬封未讀郵件一次標成已讀的開源工具(倉庫 Gururagavendra/gmail-cleaner,MIT 授權)。它跟市面上多數同類服務最大的不同在於:你不是把信箱交給某家雲端公司,而是自己建一個 Google Cloud 專案、自己跑這支程式。這篇文章給的是認識,不是評測。我讀過它的官方說明與原始碼,但沒有實際在本機連上 OAuth 跑完整流程,所以清理速度、在大信箱的穩定度、用起來的手感,你都得自己驗證。

這工具的主要設計選擇只有一句話:它不內建任何預設的 OAuth 憑證,每個使用者都要自己去 Google Cloud Console 建一個專案、啟用 Gmail API、下載自己的 credentials.json 放進專案資料夾。這是它的隱私賣點,也是它實際的使用門檻。雲端服務的方便,來自「廠商先用他們的憑證幫你把門打通」,代價是你得把他們加進你的 Google 帳號授權清單;這工具反過來,要你自己當那個 OAuth 應用程式的擁有者。
官方在 README 把這層講得很直白:因為你存取的是自己的 Gmail,所以用你自己的 OAuth 憑證,你才有完整控制權,不必信任第三方。憑證檔和登入後產生的 token.json 都被列進 .gitignore,不會跟著程式碼一起送上 Git。實際跑起來是兩條路:裝了 Docker 就 docker compose up、瀏覽器打開本機的 8766 連接埠;或用 Python 3.9 以上加 uv 套件管理器,uv run python main.py 同樣開在本機 8766。OAuth 回呼走另一個 8767 連接埠,兩個連接埠各司其職,8766 是你看得到的網頁介面,8767 是 Google 把授權結果送回來的那扇門。
如果你選 Docker,登入成功後產生的 token.json 會被寫進 ./data 這個掛載目錄,下次重開容器會自動讀回,不必每次重新授權。這套持久化是 docker-compose 預設就掛好的,但代價是容器以 root 身份執行,那個 token 檔在主機端會屬於 root,後面要手動改或刪會碰到權限問題。
要把 Gmail 授權交給一支本機程式,背後的取捨其實是同一種:你在自己掌握資料的本地優先工具和「打開網頁就能用」的方便之間,選了前者。Gmail Cleaner 把這個選擇推到底,連 OAuth 應用程式都自己出。那些雲端的開源自架工具多半把「自架」理解成「跑在自己機器上」,這工具連「拿資料的鑰匙」都堅持自己生。
這是讀原始碼最該講清楚的一段。README 在 Security 段寫「Minimal Permissions, Only requests read + modify (for mark as read)」。範圍設定可見於 app/core/config.py:
scopes: list[str] = [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.modify",
]
全倉庫搜不到 https://mail.google.com/ 這個完整存取範圍。也就是說,它確實只申請了唯讀加上 modify 兩個範圍,沒有要求對你整個信箱的完整存取權。這點 README 沒有說謊。
但括號裡那句「for mark as read」是低估的。按照 Google 對 gmail.modify 的定義,這個範圍涵蓋除了立即永久刪除信件以外的所有讀寫動作。對照 Gmail Cleaner 自己的原始碼,刪信(delete.py)、封存、標籤管理、標記為重要,全都在 gmail.modify 這個範圍下完成。所以你給出去的授權,實際上不只「標已讀」,而是「可以讀、可以搬、可以刪到垃圾桶、可以改標籤」。你會不會在意這個差距,取決於你對這支程式的信任程度,但起碼原始碼擺在那裡,你可以自己核對。附帶一個安全性質的事實:因為它只申請到 modify 範圍、沒有 Gmail 的完整存取權,這支程式在技術上呼叫不到永久刪除信件的 API,刪信永遠只是搬到垃圾桶,永久清除得靠你事後再去 Gmail 手動把垃圾桶倒掉。換句話說,就算授權範圍比 README 字面更廣,它也無法在你不知情時把信件徹底銷毀,等於內建一層誤刪保險。
這個「授權範圍從原始碼可核對」的性質,是它相對於閉源雲端服務最實在的優勢。Unroll.me 這類服務在 2017 年被媒體披露把匿名化處理後的郵件資料賣給第三方(後續引發隱私爭議與和解),那條新聞之所以讓人警覺,正是因為使用者無從查證雲端服務到底拿了授權做什麼。Gmail Cleaner 把這層黑箱拿掉了,代價是你得自己架。
還有一個 Google OAuth 的通則行為會影響你,README 沒提但值得知道:你在 Cloud Console 建的是處於「測試中」狀態的應用程式,這類未提交驗證的應用程式依 Google 規定最多只能加 100 個測試使用者,而且核發的更新權杖在測試狀態下 7 天就失效。對單人或小家庭自用毫無影響,但如果你打算給整個團隊共用同一個 OAuth 應用程式,就得走 Google 的正式驗證流程,或讓每個人各自建一個。這是「自有憑證」模式的固有代價,不是這支程式的問題。
想收回授權也很單純。Gmail 介面裡的「第三方存取權」隨時能把這個 OAuth 應用程式撤掉,或直接刪掉主機上的 token.json,程式就再也不能動你的信箱。授權的主動權從頭到尾在你手上,這正是自有憑證相對於雲端服務最實質的差別。
實際清理的機制也值得拆一下,因為它直接決定你誤刪能不能救回來。Gmail Cleaner 的刪信靠的是 Gmail API 的 batchModify,把 TRASH 標籤加到信件上,對應原始碼 delete.py 裡的那段呼叫。信會被搬進垃圾桶,依照 Gmail 自己的規則保留 30 天才真正清除。官方 FAQ 也明講,誤刪可以去 Gmail 的垃圾桶裡救回。
批次處理的數量依操作而定。單一發件人刪信、標已讀、掃描都是 100 封一批,但多發件人批量刪除和標籤批次操作直接用到 Gmail API 的上限 1000 封,CSV 匯出則是 50 封一批。所以「100」不是全域常數,而是作者在單次操作裡選的穩妥值,碰到大批量會直接拉到 API 允許的 1000。實際單次能吞多少、會不會撞到 Google 的配額,仍要你自己跑過才知道。
除了刪信和標已讀,功能清單還包含按發件人封存、建立或刪除標籤、把某個發件人的信標成重要、以及把特定發件人的郵件資料匯出成 CSV。這些動作背後走的都是同一支 Gmail API、同一組 gmail.modify 範圍,機制一致,差別只在於呼叫哪一個端點。
官方提供的展示如下,實跑畫面不在這篇的範圍裡。倉庫根目錄有一支 demo.gif 示範操作流程,另外作者在 GitHub Pages 架了一個 gururagavendra.github.io/gmail-cleaner/ 的頁面,上面放的是功能介紹、平台支援表和範例介面截圖,所有按鈕最後都連回 GitHub 倉庫或 YouTube 教學影片。那是一個宣傳頁,並非能在網頁上直接登入使用的線上版。要真的用它,還是得在本機或自己的伺服器上跑。

這裡有個小地方可以順手核對:那個 GitHub Pages 頁面標題寫 v1.1.0,但倉庫的 pyproject.toml 設的是 1.0.0。兩邊對不上不影響功能,卻是這類個人維護專案常見的版本標記鬆散現象。
把官方資料和原始碼能證明的、跟不能證明的分清楚,對這類工具特別重要。
能證明的是能力存在:它申請哪些 OAuth 範圍、刪信走什麼機制、批次常數多少、用什麼授權、在哪個連接埠跑。這些都能在原始碼裡逐項核對。不能證明的是效果和穩定度。至於這工具在你那個有幾萬封信的信箱裡跑起來多快、會不會在某個發件人身上卡住、大批量刪除時穩不穩,我一律不替它背書,你得自己試。
幾個會影響判斷的誠實缺口也要先說。README 反覆強調「100% 本地、資料完全不離開你的機器」,這句話在退訂功能上其實不夠精確。退訂的實作是對寄件人提供的 List-Unsubscribe 網址發出對外的 HTTP 請求,也就是說這個動作本身會離開你的機器、連到寄件人的伺服器,只是不經過 Gmail Cleaner 自己的伺服器(它根本沒有伺服器)。精準的說法是「你的信件內容不會被這工具的作者收集」;字面上的「什麼都不離開機器」並不精確。
另外,整個倉庫和展示頁都找不到正式的服務條款或隱私政策文件。對一支會碰你信箱的工具來說,這代表你和新作者之間沒有一份正式的權利義務文件,只有 README 裡幾句非正式的隱私聲明。對絕大多數自架使用者這也許不構成問題,但如果你需要合規或一份能拿出來講的承諾,這就是個硬缺口。
把 Gmail Cleaner 放回同類工具的版圖裡看,它的位置其實很清楚。Unroll.me、LeaveMeAlone、Clean Email 這一類都是雲端服務,共通點是你要把 Gmail 授權交給它們的伺服器,換取打開網頁就能用的方便,其中 Unroll.me 還出過販售匿名化郵件資料的爭議。Gmail Cleaner 走相反的路:把方便換成隱自主張,授權只在本機之間流動、範圍可在原始碼裡逐行查證。這條路和那些把 API 呼叫包在自己服務裡的自架工具是同一個家族,差別只在 Gmail Cleaner 連外部 API 的鑰匙都堅持你自己拿。要說哪一邊比較好沒有意義,這純粹是「我願不願意花設定時間換授權自控」的個人取捨;但如果你之所以想離開雲端服務,正是因為不信任對方拿授權做什麼,那這工具的價值主張就對得上你的顧慮。
./data 裡的 token.json,這個檔案在主機端會屬於 root,要改或刪得用 sudo,是 Docker 常見現象,但第一次遇到的人會困惑。gmail.modify 不只是標已讀,你要評估的是「願不願意把這支程式當成能讀、能搬、能刪到垃圾桶的等級」。不用架起來也能先判斷值不值得進一步試。你可以打開倉庫,直接看 app/core/config.py 的 scopes 設定,確認它申請的就是 gmail.readonly 加 gmail.modify、沒有夾帶完整存取範圍;再看 delete.py 的 batchModify 呼叫,確認刪信是搬到垃圾桶、不是立即銷毀;順手翻一下根目錄的 LICENSE 確認是 MIT,以及有沒有 CONTRIBUTING 說明投稿流程;最後看 demo.gif 或 YouTube 設定教學,感受一下介面順不順眼。這幾項都查完,你大概就知道自己屬於「願意花一個晚上架來換隱私自控」的人,還是「寧可授權給雲端服務換方便」的人。前者值得繼續,後者也沒有錯,只是這工具本來就不是為你設計的。
GitHub 倉庫:https://github.com/Gururagavendra/gmail-cleaner