• APP Script 自動化處理腳本/信件發送

APP Script

最近發現簡單資料計算用 APP Script 蠻方便的,用 ipad 就能操作,即時寫入雲端sheet,團隊成員可以馬上查看,也可以連接 google表單,寄送電子報,語法跟 javascript 很像

雲端sheet擴充功能 -> APP Script

截圖 2025-06-13 20.44.38

會自動打開專案頁面
截圖 2025-06-13 20.49.09

讀取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

截圖 2025-06-13 21.47.48

寄送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

帶入信件.doc檔

假設今天要附上一段內容,可以另外設一個.doc檔,抓取文字內容帶入信件

文件先上傳雲端取得網址,d/<截取中間這段id>/edit
https://docs.google.com/document/d/1Nbmbt7N4-YFWJkOyt3CJJE3N2NO7hFdrwwB3jgPvrQ4/edit?tab=t.0
截圖 2025-06-13 22.12.29

# 在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`;
  }

帶入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

設置觸發器

點選觸發條件 -> 新增觸發條件(右下角)

截圖 2025-06-13 22.05.19

截圖 2025-06-13 23.03.26

我選了剛才寫的function
設置時間驅動,每分鐘執行測試
截圖 2025-06-13 23.05.07

截圖 2025-06-13 23.09.43

截圖 2025-06-13 23.13.33

觸發有條件限制,如果到達額度就不會再觸發

觸發器總運行時間 (Triggers total runtime): 每天 90 分鐘
單次執行最大運行時間 (Script runtime): 每次執行最長 6 分鐘

假設腳本每次執行需要 30 秒:
90 分鐘 = 5400 秒
5400 秒 / 30 秒/次 = 180 次/天

如果是連接 google 表單,可以設置為有人提交表單就自動觸發寄送信件、電子報
截圖 2025-06-13 23.16.15

Catalina
Catalina

Hi, I’m Catalina!
原本在西語市場做開發業務,2023 年正式轉職資料領域。
目前努力補齊計算機組織、微積分、線性代數與機率論,忙碌中做點筆記提醒自己 🤲

文章: 43

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *