來到了第四天,我們可以進入比較複雜一點點的操作。但一樣先講結論,如果你很急著用,可以直接使用這份 Add-On: Merge Mail,其好處是還會告訴你使用者有沒有開啟 Email,但免費版好像一天一個帳號只能寄給 50 人。自己寫的好處是,如果你一天突然要寄很多封(20,000封 and 100人以內)且還有個五分鐘,那可以持續閱讀。對於想知道怎麼做的人,讓我們開始吧!
答案會在今天的文章中!
現在幾乎每天都會打開 Gmail,但有時就是會需要寄一些客製化的 Email 給客戶。此時就會遇到個問題。
特別提醒,這邊的「客製化」Email,因為會限定是要 Google 產品,一般人會是 Gmail,或是企業與組織的 Google Workspace(簡單來說你的學校、組織的基本上是用 Google Drive 傳檔案的話,基本上就是)。那我們就開始吧!
在寄客製化 Email 時通常都要有個清單,這邊就來綁定一個 Google Sheet,所以第一步是打開一份 Google Sheet。
一樣提醒要按下「允許授權」。
在寄送 Email 上,我們透過的是 MailApp.sendEmail()
的功能。寫上收信人、主旨與內文,按下執行就可以了(就是這麼簡單)。
function sendEmails() {
let emailAddress = "test@gmail.com";
let subject = "Sending emails from a Spreadsheet";
let message = "This is a test for sending email";
MailApp.sendEmail(emailAddress, subject, message);
}
另外也有「回覆」可以使用:sendEmail(to, replyTo, subject, body)
首先先創造一系列要寄出的內容,這邊我就大概創了一個表單。
接著我們要在 GAS 中讀取這表單的內容。完整的程式碼在這,待會我們會一段段分段來理解。
function sendEmails() {
// 讀取連結的 Google Sheet 中的 Tab
let sheet = SpreadsheetApp.getActiveSheet();
let startRow = 2;
let numRows = 5;
let startCol = 2;
let numCols = 4;
let dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
let data = dataRange.getValues();
for (let i in data) {
let row = data[i];
let receiver = row[0]
let emailAddress = row[1];
let subject = row[2] + ' '+ receiver;
let message = row[3];
MailApp.sendEmail(emailAddress, subject, message);
}
}
執行以後,你就會在「寄件備份」中看到五個已經寄出的信件。因為是假的 email address,所以你也會馬上收到一份「寄件錯誤」的通知。
接下來我們一條條看。
Spreadsheet
vs Sheet
首先是第一段:「讀取工作表」let sheet = SpreadsheetApp.getActiveSheet();
回到最一開始的測驗,要怎麼分試算表與工作表呢?用英文來理解會比較有幫助,Spread
有「擴大、蔓延之意」,sheet
則是「一片、單張」。進而可以推測說,sheet
是指單張的「工作表」,spreadsheet
指的是全部的工作表,也就是中文的「試算表」。
getRange()
的 Row(列) 和 col(行)再來第二段:「選定要讀取的資料範圍」
let startRow = 2;
let numRows = 5;
let startCol = 2;
let numCols = 4;
let dataRange = sheet.getRange(startRow, startCol, numRows, numCols);
再來是也是重要觀念,到了指定的 Sheet 後,要怎麼用 getRange()
抓行(Col)與列(Row)呢?這邊的關鍵是「 用SpreadSheet 原本的 Index 」,或是我們會稱為 根據 R1C1 位置參照樣式(R1C1 notation),可以理解成 Row(列) 和 col(行)都以 1 為開始,且以最左上角起始點為「R=1,C=1」。
那我們這邊是直接設定好要抓的行數與列數,如果想要比較彈性地去抓,可以將 numRows 設定為 numRows = sheet.getLastRow() - startRow
,這個公式會幫我們 getLastRow()
抓出表單中最下面有數值的「那一列」。直的欄也同理可用 getLastColumn()
,想看使用範例可以參考 D11。
getValues()
時抓下來的是 Array of Array再來第三段:「從選定的範圍中取得資料」
let data = dataRange.getValues();
這個也是超重要觀念之一,在我們用 getValues
抓下來的數值會是 Array in Array,或是說 2 dimentional array,長起來的樣子會是這樣。
所以,如果我今天要抓值 Dave
的話,我需要輸入的會是 data[3][0]
;要抓 Amy
那列的 Hellow World
的話,就要用 data[0][3]
。因為這邊不再是 Sheet 內的資料了,而是回到資料結構;因此不再遵循 R1C1,而是回到程式最原本的第一項 index 是 0。
在給予客製化的內容部分有兩種做法,第ㄧ種是用程式,另一是直接在表單中先搞定。以下先示範第一種。
for (let i in data) {
let row = data[i];
let receiver = row[0]
let emailAddress = row[1];
let subject = row[2] + ' '+ receiver;
let message = row[3];
MailApp.sendEmail(emailAddress, subject, message);
}
這種很單純就是藉由 let subject = row[2] + ' '+ receiver;
在 subject 的部分加上直接加上收件者的名字。這種是在開發時寫得快,但對於不熟悉的人來說,這種方式很容易會出現資料結構上的警示(像是數字沒有轉成字串等等),所以個人會建議先在 Google Sheet 先把內容確認。
先新增一欄,放要寄出的 Subject。這時我們就可以用 concatenate
來把字串做合併,用法是像這樣 CONCATENATE("歡迎", "使用", "試算表!")
,調整內文也是同樣的道理。
並在這時回到表單中,因為新增了一欄,所以記得調整參數也要調整(numsCol
要 +1,for 迴圈內要調整成如下面這樣)。
for (let i in data) {
let row = data[i];
let receiver = row[0]
let emailAddress = row[1];
let subject = row[3];
let message = row[4];
MailApp.sendEmail(emailAddress, subject, message);
}
好,那基本上這樣做完,就已經完成了「客製化寄信」的第一堂了,功能性基本上都有。但要怎麼樣跟 Google 表單結合呢?
因為 Google Sheet 的結合在 Q1 已經解釋了,這邊就針對說明怎麼樣讓「Google 表單」串接客製化 Email。其實也沒有什麼特殊功能,就是讓 讓 Google 表單連到一個 Google Sheet,再用 Google Sheet 寄出(重複 Q1)。大致的作法可以參閱這一份,當然程式碼要調整一下就是。
Tutorial: Sending emails from a Spreadsheet
一樣提醒,寄信有 Quota 限制——每天不超過20,000封,也不超過100人。這也是為何 D1 會提說未必適合開發大系統。好,那今天就是我們的 D4,今天完整的程式碼在 Step 3。明天 D5 會繼續介紹結合 Email 中寄出 HTML 的使用方式,如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。我們明天見。