Gmail:刪除草稿 deleteDraft()

 


Gmail 草稿夾,常常像抽屜裡那疊便條紙:寫到一半、改了又改,最後誰也不敢動。久了,收件框乾淨,草稿卻越堆越多。

這篇文章專講 deleteDraft()——怎麼安全刪、怎麼批次刪、刪之前要不要先「試跑」、刪錯了能不能救。我會用白話把重點講清楚:什麼情境該刪、有哪些權限和限制、常見誤會(例如把草稿當郵件在搜)、以及實務上可直接上線的流程。

你會看到可複製的範例、可避免的地雷、與好維護的策略。讀完,你能把草稿夾整理成「看得懂、留得住、刪得掉」的狀態,不再怕按下刪除鍵。希望本篇文章能夠幫助到需要的您。


目錄

{tocify} $title={目錄} 


什麼是 deleteDraft()?會發生什麼事?

對象:deleteDraft() 針對的是「草稿」(GmailDraft),不是一般已送出或收件匣裡的郵件。

效果:呼叫後,該草稿即不存在;如果你再呼叫 draft.getMessage() 會丟出例外(因為草稿已刪)。

跟「寄出草稿」的關係:當你把草稿寄出時,草稿會自動被刪除、並產生一封帶有 SENT 系統標籤的新郵件;因此「寄出後又手動刪草稿」通常是多此一舉。

權限需求:使用 Apps Script 內建 Gmail 服務操作草稿,需要 https://mail.google.com/ 這類高權限 scope。第一次執行會跳權限同意畫面。

小提醒:Gmail API 的 users.drafts.delete 明確寫著「立即且永久刪除」,不是移到垃圾桶;這也是為什麼本文後面會教你「乾跑(dry-run)」保護機制。


什麼情境該用 deleteDraft()?

行銷寄信前的多版本草稿累積、要清掉過期版本

自動化流程(例如:表單填寫 → 先產草稿 → 審核不通過則刪掉)

內容模板管理:先用 createDraft() 產生模板草稿、每次寄出後改版就刪舊留新(或改用 update() 直接覆寫)。


權限與執行限制

Simple Trigger 不能碰 Gmail

        onOpen(e) / onEdit(e) 這類簡單觸發器無法存取需要授權的服務(包含 Gmail)。要用請改成「安裝式觸發器」或手動執行。

公司/學校可能封鎖 Apps Script

        若你的 Workspace 管理員把 Apps Script 關閉,所有腳本與觸發器都會被擋下。

配額(Quotas)別忽略

        像「Email 讀/寫(不含發送)」有每日上限、UrlFetch 也有每日次數上限;批次處理時要分批、加上延遲與重試。


快速開始:刪除第一封草稿(Apps Script 內建 Gmail 服務)

function deleteFirstDraft() {
  const drafts = GmailApp.getDrafts();
  if (!drafts.length) {
    console.log('沒有草稿可刪');
    return;
  }
  const draft = drafts[0];
  const subject = draft.getMessage().getSubject(); // 先記下供日誌
  draft.deleteDraft(); // 直接刪除
  console.log(`已刪除草稿:${subject}`);
}


這正是官方文件示範的精神:GmailApp.getDrafts()[0] → draft.deleteDraft(),刪後再取 getMessage() 會丟例外。


依 ID 精準刪除(適合流程串接)

function deleteDraftById(draftId) {
  const draft = GmailApp.getDraft(draftId);
  const subject = draft.getMessage().getSubject();
  draft.deleteDraft();
  console.log(`已刪除 ID=${draftId} 的草稿:${subject}`);
}


getId() 可把 ID 存進資料表或屬性,後續用 getDraft(id) 取回再刪;這個做法在長流程最穩。


批次刪除:以條件過濾草稿

GmailApp 沒有提供「查詢草稿」的搜尋字串 API(search() 是找 Thread,不是 Draft);實務上改為拉出全部草稿,再用 GmailMessage 的欄位自行過濾,例如主旨、收件者、建立時間等。

依主旨關鍵字

function deleteDraftsBySubjectKeyword(keyword, { dryRun = true } = {}) {
  const drafts = GmailApp.getDrafts();
  let hit = 0;
  for (const d of drafts) {
    const msg = d.getMessage();
    if (msg.getSubject().includes(keyword)) {
      hit++;
      if (dryRun) {
        console.log(`[試運轉] 將刪:${msg.getSubject()}`);
      } else {
        d.deleteDraft();
        console.log(`[已刪除] ${msg.getSubject()}`);
      }
    }
  }
  console.log(`符合 ${hit} 封;dryRun=${dryRun}`);
}


依收件者網域

function deleteDraftsByRecipientDomain(domain, { dryRun = true } = {}) {
  const drafts = GmailApp.getDrafts();
  for (const d of drafts) {
    const to = d.getMessage().getTo() || '';
    const cc = d.getMessage().getCc() || '';
    const bcc = d.getMessage().getBcc() || '';
    const buckets = [to, cc, bcc].join(',').toLowerCase();
    if (buckets.includes(`@${domain.toLowerCase()}`)) {
      if (dryRun) {
        console.log(`[試運轉] 將刪(${domain}):${d.getMessage().getSubject()}`);
      } else {
        d.deleteDraft();
        console.log(`[已刪除] ${d.getMessage().getSubject()}`);
      }
    }
  }
}


依建立時間(早於 N 天)

function deleteDraftsOlderThan(days, { dryRun = true } = {}) {
  const limit = Date.now() - days * 24 * 60 * 60 * 1000;
  const drafts = GmailApp.getDrafts();
  for (const d of drafts) {
    const msg = d.getMessage();
    if (msg.getDate().getTime() < limit) {
      if (dryRun) {
        console.log(`[試運轉] 將刪(${days} 天前):${msg.getSubject()} / ${msg.getDate()}`);
      } else {
        d.deleteDraft();
        console.log(`[已刪除] ${msg.getSubject()} / ${msg.getDate()}`);
      }
    }
  }
}


錯誤處理:常見例外與解法

情況 現象 可能原因 建議處置
draft.getMessage()deleteDraft() 之後呼叫 例外 草稿已刪除,物件失效 刪前記錄必要欄位(主旨、ID),刪後不要再取內容。
定時觸發器找不到草稿 「Oops – can’t find Gmail draft」 草稿在排程間被人工刪或寄出;ID 失效 捕捉例外、略過不存在的草稿並記錄 ID。
onEdit 等 simple trigger 執行 Gmail 無權限、動作被擋 Simple trigger 不可使用需要授權的服務 改用安裝式觸發器;首次授權後再跑。
API 呼叫回 403 policyEnforced 組織政策擋下 管理員或帳戶防護策略限制 與 Workspace 管理員確認政策或改用核准的流程。
大量刪除時出現限速/配額錯誤 rateLimitExceeded 連續呼叫過快或超出上限 分批與延遲、自動重試、拉長排程。


常見問題及雷點

1.    把「草稿」當「郵件」:

        GmailApp.search() 搜的是 Thread,不保證涵蓋草稿;請用 getDrafts() 再自行過濾。

2.    以為「刪草稿=丟垃圾桶」:

        API 的 users.drafts.delete 是永久刪;內建服務刪除亦不可逆,務必先 Dry-run。

3.    寄出後又手動刪草稿:寄出草稿會自動移除草稿實體,沒必要再刪一次。

4.    用 Simple Trigger 操作 Gmail:一定失敗。改安裝式觸發器。

5.    忽略組織政策:公司可能禁用 Apps Script 或 API,導致腳本完全不跑。

6.    批次沒節流:高頻呼叫易撞配額;要分批 + Sleep + 重試。


實務範例集

A. 清掉「測試用」草稿(主旨含 [TEST])

function purgeTestDrafts() {
  deleteDraftsBySubjectKeyword('[TEST]', { dryRun: false });
}


B. 清除對特定網域的未送出草稿(例如合作已結束)

function purgePartnerDrafts() {
  deleteDraftsByRecipientDomain('old-partner.com', { dryRun: false });
}


C. 定期清理 30 天前的草稿(安裝式觸發器每日執行)

function dailyPurgeOldDrafts() {
  deleteDraftsOlderThan(30, { dryRun: false });
}


觸發器請用「安裝式觸發器」,Simple Trigger 無法動到 Gmail。


D. 先列清單給主管確認

function reviewPurgeTargets() {
  deleteDraftsBySubjectKeyword('舊合約', { dryRun: true });
  deleteDraftsOlderThan(60, { dryRun: true });
}


E. API 精準刪(已知 Draft ID)

function removeByApi() {
  const ids = ['r-123abc', 'r-456xyz']; // 例
  ids.forEach(apiDeleteDraft);
}


問題集

Q1:我能幫草稿加標籤再用標籤刪嗎?

        不行。草稿訊息只能有 DRAFT 系統標籤;要分群,請用主旨前綴或收件者條件。

Q2:有「回收桶」可以救回誤刪草稿嗎?

        Gmail API 的草稿刪除是永久的;內建服務刪除後也不可復原。上線前務必先全量乾跑。

Q3:為什麼排程偶爾說找不到草稿?

        通常是草稿在排程間被人工刪掉或被寄出(寄出會自刪)。請在程式中接受「ID 不存在」這種例外。

張貼留言 (0)
較新的 較舊