【n8n 教學】Gmail 附件自動存進 Google Drive,3 個節點搞定(附可匯入範本)
每天收到發票、報價單、合約 PDF,都要手動下載再上傳到雲端資料夾嗎?這篇用 n8n 做一個小流程:Gmail 一收到帶附件的信,就自動把附件存進你指定的 Google Drive 資料夾。
我實測寄了一封帶 4 個附件的信,4 個檔案全部進了資料夾。適合常收文件、想從一個實用流程入門 n8n 的人,不需要會寫程式,唯一一段程式碼直接複製就好。
重點摘要
- 流程只有 3 個節點:Gmail Trigger → Code → Google Drive
- 一封信有多個附件也會全部存(實測 1 封信 4 個附件 → 4 個檔案)
- 最常卡關的兩個設定:Gmail Trigger 的「Simplify」要關掉、「Download Attachments」要打開
- 自架版要先在 Google Cloud 建 OAuth 憑證,這篇照實際畫面寫了步驟
- 後半段有排錯表,文末附複製貼上就能用的 workflow 範本
測試環境
- n8n:自架,Docker 映像檔
docker.n8n.io/n8nio/n8n:2.44.7,跑在 Windows 11 的 Docker Desktop 上 - 測試日期:2026-11-08
- 需要:一個 Google 帳號(Gmail 和 Drive 用同一個)
- 費用:n8n 自架免費。Google Cloud 專案只用來建登入憑證,這次沒開計費也能完成。不想自己架,可以用 n8n Cloud(有試用期,之後的月費到官網確認)
先懂一個觀念:觸發和動作
n8n 的流程都是「某件事發生了(觸發)→ 接著做什麼(動作)」。這篇的觸發是「Gmail 收到新信」,動作是「把附件上傳到 Drive」。中間的 Code 節點只做一件事:把一封信裡的多個附件拆開,一個附件一筆,後面的 Drive 節點才能一個一個上傳。
Step 0|準備:啟動 n8n、連上 Google
用 Docker 啟動 n8n
裝好 Docker Desktop 之後,在終端機執行:
docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n用瀏覽器打開 http://localhost:5678,第一次會要你建一個擁有者帳號(只存在你自己的電腦)。之後跳出的問卷可以略過。
在 Google Cloud 建 OAuth 憑證
自架的 n8n 要連 Gmail 和 Drive,得先在 Google Cloud 建一組「Client ID+Client Secret」。步驟有點多,但只要做一次:
- 到 Google Cloud Console 建一個新專案,例如
n8n-blog-demo。帳號裡有好幾個專案的話,之後每一步都先確認左上角選的是這個專案 - 在「API 程式庫」分別搜尋 Gmail API、Google Drive API,各按一次「Enable」
- 到 Google Auth Platform 設定同意畫面:填應用程式名稱、支援 email,受眾(Audience)選 External,填聯絡 email,同意政策後建立
- 在 Audience 頁的 Test users 把你自己的 Gmail 加進去。沒加的話,等一下登入會被擋
- 到 Clients 建立 OAuth 用戶端:類型選 Web application,「已授權的重新導向 URI」填:
http://localhost:5678/rest/oauth2-credential/callback
(這個網址在 n8n 建憑證的畫面上也看得到,兩邊要一模一樣) - 建好後會顯示 Client ID 和 Client Secret,先複製起來
在 n8n 建兩個憑證
Gmail 和 Google Drive 在 n8n 是兩種不同的憑證,要各建一次,但可以用同一組 Client ID 和 Secret:
- n8n 左側 Overview → Credentials → Create credential,搜尋 Gmail OAuth2 API
- 貼上 Client ID、Client Secret。這篇只需要讀信,所以打開 Custom Scopes,只填
https://www.googleapis.com/auth/gmail.readonly。不填也能用,但 Google 會要求包含寄信、刪信在內的權限 - 按 Sign in with Google。登入時會出現「Google 尚未驗證這個應用程式」,這是因為應用程式是你自己建的,按繼續;權限畫面只會有「查看你的電子郵件和設定」一項,勾選後繼續。我實測過,只給這個權限,收信和下載附件都正常
- 回到 n8n 看到連線成功後按 Save
- 再建一個 Google Drive OAuth2 API,步驟一樣,Custom Scopes 只填
https://www.googleapis.com/auth/drive.file。這個權限只能存取這個流程自己上傳的檔案,碰不到你雲端硬碟裡的其他東西
Step 1|建立 Gmail Trigger
新增一個 workflow,加入 Gmail Trigger 節點,設定如下:
- Credential:選剛才建的 Gmail 憑證
- Poll Times:Every Minute(每分鐘檢查一次新信)
- Event:Message Received
- Simplify:關掉(開著的話不會下載附件)
- Filters → Search:
has:attachment,只抓有附件的信。想更精準可以再加條件,例如has:attachment from:billing@example.com - Options → Attachment Prefix:保留
attachment_ - Options → Download Attachments:打開
關掉 Simplify 時,n8n 會跳出黃色提醒:完整的資料比較大,只有需要附件或信件原文時才關。我們要的就是附件,所以照關。
寄一封帶附件的信給自己,按 Fetch Test Event。右邊輸出切到 Binary 分頁,會看到 attachment_0、attachment_1……每個附件一個欄位。
Step 2|用 Code 節點把附件拆開
加一個 Code 節點,Mode 選 Run Once for All Items,語言選 JavaScript,貼上:
// 把每封信的每個附件拆成獨立的一筆,統一放在 binary 的 data 欄位
const out = [];
for (const item of $input.all()) {
for (const key of Object.keys(item.binary || {})) {
out.push({
json: { fileName: item.binary[key].fileName },
binary: { data: item.binary[key] },
});
}
}
return out;為什麼需要這一步:Gmail Trigger 輸出的是「一封信一筆」,附件全部擠在同一筆裡,名稱是 attachment_0、attachment_1……但 Drive 節點一次只會讀一個欄位名稱。拆成「一個附件一筆」、名稱統一叫 data,Drive 節點就能每個都上傳。
我實測的信有 4 個附件(3 張 PNG、1 個 PDF),輸入 1 筆,輸出 4 筆:
Step 3|上傳到 Google Drive
加一個 Google Drive 節點:
- Credential:選 Google Drive 憑證
- Resource:File
- Operation:Upload
- Input Data Field Name:
data(就是上一步放附件的欄位名稱,直接打字,不要用運算式) - File Name:
{{ $json.fileName }},沿用原本的檔名 - Parent Drive:My Drive
- Parent Folder:改成 By ID,貼上資料夾網址裡
folders/後面那一串。我先在 Drive 建了一個「Gmail 附件」資料夾。Drive 憑證只給 drive.file 時,「From list」會載不出資料夾清單,所以要用 ID
按 Execute workflow 跑一次完整流程。我這次從抓信到 4 個檔案都上傳完,大約 18 秒。打開 Drive 資料夾確認:
Step 4|啟用流程
測試成功後,按右上角的 Publish(我用的 n8n 2.44 是這個按鈕;比較舊的版本是 Active 開關)。之後 n8n 會每分鐘檢查一次新信,有附件就自動存。
注意:自架的 n8n 要一直開著才會檢查新信。電腦關機或 Docker 停掉,這段時間的信就要等 n8n 再開起來才會處理。
排錯表
| 你看到的狀況或錯誤 | 原因 | 修法 |
|---|---|---|
按 Sign in with Google 後出現 Sign-in window was blocked | 瀏覽器擋掉了 Google 登入的彈出視窗(我實際遇到) | 網址列右邊允許 localhost:5678 的彈出式視窗,再按一次;或換一個瀏覽器 |
Google 登入時出現 access_denied | 你的帳號沒有加進 OAuth 同意畫面的 Test users | 回 Google Cloud → Google Auth Platform → Audience → Test users 加上你的 Gmail |
登入時出現 redirect_uri_mismatch | Google Cloud 填的重新導向 URI 跟 n8n 的不一樣 | 從 n8n 憑證畫面複製 OAuth Redirect URL,貼到 Google Cloud 用戶端的「已授權的重新導向 URI」 |
| 啟用 API 或建用戶端時,畫面上的專案不是你剛建的那個 | 帳號裡有多個專案,Console 停在別的專案(我實際遇到) | 先看左上角的專案名稱,切到正確的專案再操作 |
Drive 節點的 Parent Folder 選「From list」,出現 403 - Forbidden、The granted scopes do not give access to all of the requested spaces | Drive 憑證只有 drive.file 權限,不能列出你雲端硬碟裡的資料夾 | Parent Folder 改成 By ID,貼上資料夾網址裡 folders/ 後面那一串;上傳本身不受影響 |
Drive 節點出現 expects the node's input data to contain a binary file | 前面沒有下載到附件,或欄位名稱打錯 | 確認 Gmail Trigger 的 Simplify 已關、Download Attachments 已開;Drive 的欄位名稱填 data |
| Gmail Trigger 輸出沒有 Binary 分頁 | Simplify 還開著 | 關掉 Simplify,重新按 Fetch Test Event |
| 只存了第一個附件 | 少了 Code 節點,Drive 直接讀 attachment_0 | 照 Step 2 加 Code 節點 |
| 測試都正常,但新信沒有自動存 | workflow 還沒 Publish,或 n8n 沒在跑 | 按 Publish;確認 Docker 裡的 n8n 還開著 |
拿這個 Gmail 憑證去寄信,出現 Request had insufficient authentication scopes | 憑證只有唯讀權限(gmail.readonly),不能寄信 | 要寄信的流程另外建一個不開 Custom Scopes 的 Gmail 憑證 |
用了一個星期後,突然出現授權失效或 invalid_grant | 同意畫面是「External+測試中」時,Google 給的授權 7 天就會過期 | 到 n8n 憑證重新按 Sign in with Google;要長期用,就把 Google Auth Platform 的發布狀態改成正式版 |
可以再改進的地方
- 依寄件者存到不同資料夾:在 Code 和 Drive 之間加一個 Switch 節點
- 檔名加上日期,避免同名檔案混在一起:File Name 改成
{{ $now.toFormat('yyyy-MM-dd') }}_{{ $json.fileName }} - 只存 PDF:在 Code 節點的迴圈裡加一行,副檔名不是
.pdf就跳過 - 存完再發一則通知到 LINE 或 Slack
範本:複製貼上就能用
下面是我實測用的 workflow。全選複製,在 n8n 新增一個空白 workflow,點一下畫布再按 Ctrl+V,三個節點會整組出現。
貼上之後還要改兩個地方:三個節點的憑證換成你自己的;Drive 節點的 Parent Folder 換成你的資料夾(我把資料夾 ID 換成了「請換成你的資料夾 ID」)。
{
"name": "Gmail 附件存到 Google Drive",
"nodes": [
{
"id": "g1",
"name": "Gmail Trigger",
"type": "n8n-nodes-base.gmailTrigger",
"typeVersion": 1.3,
"position": [0, 0],
"parameters": {
"pollTimes": { "item": [{ "mode": "everyMinute" }] },
"simple": false,
"filters": { "q": "has:attachment" },
"options": {
"downloadAttachments": true,
"dataPropertyAttachmentsPrefixName": "attachment_"
}
}
},
{
"id": "c1",
"name": "拆開附件",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [240, 0],
"parameters": {
"jsCode": "// 把每封信的每個附件拆成獨立的一筆,統一放在 binary 的 data 欄位\nconst out = [];\nfor (const item of $input.all()) {\n for (const key of Object.keys(item.binary || {})) {\n out.push({\n json: { fileName: item.binary[key].fileName },\n binary: { data: item.binary[key] },\n });\n }\n}\nreturn out;"
}
},
{
"id": "d1",
"name": "上傳到 Drive",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [480, 0],
"parameters": {
"name": "={{ $json.fileName }}",
"driveId": { "__rl": true, "mode": "list", "value": "My Drive" },
"folderId": { "__rl": true, "mode": "id", "value": "請換成你的資料夾 ID" },
"inputDataFieldName": "data",
"options": {}
}
}
],
"connections": {
"Gmail Trigger": { "main": [[{ "node": "拆開附件", "type": "main", "index": 0 }]] },
"拆開附件": { "main": [[{ "node": "上傳到 Drive", "type": "main", "index": 0 }]] }
},
"settings": { "executionOrder": "v1" }
}常見問題
Q:要付費嗎?
照這篇自架的做法,n8n 和 Google Cloud 這兩邊都沒有花錢。代價是 n8n 要一直開在你的電腦上。想要 24 小時運作又不想自己顧,可以考慮 n8n Cloud 或租一台雲端主機。
Q:會不會把所有信的附件都存下來?
只會存符合 Search 條件的信。用 has:attachment 加上寄件者或主旨條件,就能縮小範圍。
Q:信裡的簽名檔圖片也會被存嗎?
如果對方的郵件軟體把簽名檔圖片當成附件寄出,就會一起被存。想排除的話,照上面「只存 PDF」的方式,在 Code 節點依副檔名過濾。
Q:舊信的附件會存嗎?
Publish 之後,n8n 會每分鐘檢查一次新信,更早的舊信不會被處理。不過我實測時,Publish 前幾分鐘才收到、又符合 Search 條件的那封信,在第一次檢查時也被存了一份,所以剛啟用時資料夾裡可能多一個檔案。






留言
張貼留言