# **【APP Script 自動化處理腳本/信件發送】** ```= - 讀取sheet資料再寫入 - 寄送email通知 - 帶入信件.doc檔 - 帶入PDF檔 - 設置觸發器 ``` 最近發現簡單資料計算用 APP Script 蠻方便的,用 ipad 就能操作,即時寫入雲端sheet,團隊成員可以馬上查看 也可以連接 google表單,寄送電子報,語法跟 javascript 很像 雲端sheet擴充功能 -> APP Script ![截圖 2025-06-13 20.44.38](https://hackmd.io/_uploads/S15Up9Kmle.png) 會自動打開專案頁面 ![截圖 2025-06-13 20.49.09](https://hackmd.io/_uploads/B1vLR9K7gl.png) <br/> ### 讀取sheet資料再寫入 ```= function calculateSumByName() { // 1. 目前的 Google Sheet const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // 2. 原始頁面和目標頁面 const sourceSheet = spreadsheet.getSheetByName("ori_cost"); const targetSheet = spreadsheet.getSheetByName("sum_cost"); if (!sourceSheet) { Logger.log("找不到原始頁面 'ori_cost'"); return; } if (!targetSheet) { Logger.log("找不到目標頁面 'sum_cost'"); return; } // 3. 讀取數據 const lastRow = sourceSheet.getLastRow(); if (lastRow < 2) { // 如果只有標題行或沒有數據 Logger.log("原始頁面 'ori_cost' 沒有數據"); return; } const dataRange = sourceSheet.getRange(2, 1, lastRow - 1, 2); // (開始行,列,結束行,列)從第2行第1列開始,讀取到最後一行,共2列 const values = dataRange.getValues(); // 二維陣列 Logger.log("從 'ori_cost' 讀取的原始數據:"); Logger.log(values); // 4. 計算 const sumByName = {}; for (let i = 0; i < values.length; i++) { const row = values[i]; const name = row[0]; // 第一列是 name const price = parseFloat(row[1]); // 第二列是 price,轉換為數字 // 如果 price 是數字 if (!isNaN(price)) { if (sumByName[name]) { // 如果 name 已經存在,則累加 price sumByName[name] += price; } else { // 如果 name 第一次出現,則初始化其 price 總和 sumByName[name] = price; } } else { Logger.log(`警告:在 'ori_cost' 的 A${i + 2} 行發現無效的 price 值 '${row[1]}'。已跳過。`); } } Logger.log("計算出的每個名稱總和:"); Logger.log(sumByName); // 5. 寫入 const results = []; results.push(["姓名", "總金額"]); for (const name in sumByName) { if (sumByName.hasOwnProperty(name)) { results.push([name, sumByName[name]]); } } // 6. 清除 targetSheet.clear(); // 清除所有內容 .clearContents // 將結果寫入目標頁面,從 A1 開始 // getRange(row, column, numRows, numColumns) const targetRange = targetSheet.getRange(1, 1, results.length, results[0].length); targetRange.setValues(results); const successMsg = `每個名稱的總金額已成功寫入 'sum_cost' 工作表。總計 ${results.length - 1} 個項目。`; Logger.log(successMsg); } ``` ![截圖 2025-06-13 21.47.43](https://hackmd.io/_uploads/rJ442oFQgx.png) ![截圖 2025-06-13 21.47.48](https://hackmd.io/_uploads/rJ8fhjK7ee.png) <br/> ### 寄送email通知 如果想要寄送email通知,加入這段 ```= const notificationEmail = "catalinakuowork@gmail.com"; const subjectPrefix = "[Google Sheet 通知]"; // 主旨 try { const subject = `${subjectPrefix} 腳本執行成功 - ${spreadsheet.getName()}`; let body = `你好,\n\n你的 Google Sheet 腳本「calculateSumByName」已成功執行。\n\n`; body += `試算表名稱:${spreadsheet.getName()}\n`; body += `工作表「ori_cost」的數據已處理,並將結果寫入「sum_cost」。\n`; body += `成功寫入 ${results.length - 1} 個不同的名稱總金額。\n\n`; // -1 因為結果包含標題行 body += `腳本執行時間:${new Date().toLocaleString('zh-TW')}\n\n`; // 台灣當地時間格式 body += `請檢查 Google Sheet: ${spreadsheet.getUrl()}\n\n`; body += `此為系統自動發送,請勿直接回覆。\n`; GmailApp.sendEmail(notificationEmail, subject, body); Logger.log("成功寄送郵件通知。"); } catch (emailError) { Logger.log(`寄送郵件通知失敗:${emailError.message}`); } ``` ![截圖 2025-06-13 21.58.25](https://hackmd.io/_uploads/H1-9RiFXll.png) <br/> ### 帶入信件.doc檔 假設今天要附上一段內容,可以另外設一個.doc檔,抓取文字內容帶入信件 文件先上傳雲端取得網址,d/<截取中間這段id>/edit https://docs.google.com/document/d/1Nbmbt7N4-YFWJkOyt3CJJE3N2NO7hFdrwwB3jgPvrQ4/edit?tab=t.0 ![截圖 2025-06-13 22.12.29](https://hackmd.io/_uploads/S1Cez2Y7xe.png) ```= # 在GmailApp.sendEmail()前加入這段 const docId = "1Nbmbt7N4-YFWJkOyt3CJJE3N2NO7hFdrwwB3jgPvrQ4"; const doc = DocumentApp.openById(docId); docContent = doc.getBody().getText(); if (docContent) { // 如果有讀取到文件內容才加入 body += `${docContent}\n\n`; } else { body += `(未能載入 Google Doc 內容,請檢查 Doc ID 或權限。)\n\n`; } ``` <br/> ### 帶入PDF檔 pdf先上傳雲端取得網址,,d/<截取中間這段id>/view https://drive.google.com/file/d/1egAPDcK3T9qLLYCUlsF8TeyblGKqqJle/view?usp=drive_link ```= # 在GmailApp.sendEmail()前加入這段 const attachmentFileId = "1egAPDcK3T9qLLYCUlsF8TeyblGKqqJle"; const file = DriveApp.getFileById(attachmentFileId); const file_pdf = file.getBlob(); # 在GmailApp.sendEmail() 加入 attachments # GmailApp.sendEmail(notificationEmail, subject, body, {attachments:[file_pdf]}); ``` ![截圖 2025-06-13 22.48.07](https://hackmd.io/_uploads/Hy9N5hY7ee.png) <br/> ### 設置觸發器 點選觸發條件 -> 新增觸發條件(右下角) ![截圖 2025-06-13 22.05.19](https://hackmd.io/_uploads/BkgdlnK7xg.png) ![截圖 2025-06-13 23.03.26](https://hackmd.io/_uploads/BkSeChY7ee.png) 我選了剛才寫的function 設置時間驅動,每分鐘執行測試 ![截圖 2025-06-13 23.05.07](https://hackmd.io/_uploads/BJ_SRnKmlg.png) ![截圖 2025-06-13 23.09.43](https://hackmd.io/_uploads/rynH1TKmel.png) ![截圖 2025-06-13 23.13.33](https://hackmd.io/_uploads/S1_UgTYmlx.png) 觸發有條件限制,如果到達額度就不會再觸發 觸發器總運行時間 (Triggers total runtime): 每天 90 分鐘 單次執行最大運行時間 (Script runtime): 每次執行最長 6 分鐘 假設腳本每次執行需要 30 秒: 90 分鐘 = 5400 秒 5400 秒 / 30 秒/次 = 180 次/天 如果是連接 google 表單,可以設置為有人提交表單就自動觸發寄送信件、電子報 ![截圖 2025-06-13 23.16.15](https://hackmd.io/_uploads/r1JRl6KQgx.png)