Google 表單,提交後系統自動寄送回覆通知 email

Google表單,提交後系統自動寄送回覆通知email
Google表單,提交後系統自動寄送回覆通知email

2020.08.28更新:因為有人問說「有辦法針對問卷的回應答案不同,給予不同的回覆 email 嗎?」今天新增一個大段落 用不同的寄件者信箱寄信

2020.08.27更新:因為留言區中有人提問「可否有方法當資料欄位是空白(非必填的),在回覆時也不出現?」今天補充了當有題目是非必填,而使用者也真的沒有填時,要怎麼寫才能不出現在自動回覆的信件中。

本篇要解決的問題

一個線上報名表,如果能在填完單後就收到回覆通知信,可以讓報名者知道自己的報名結果,這樣子的使用體驗是比較好的,至少客服不會接打來詢問報名成功沒的電話接到手軟。

現在很多線上表單都是用Google表單直接製作,但Google表單在介面上,只能選擇當有新提交時,發 email 給建立表單的人,而無法直接回信給報名者

如果要發送信件給報名者,那就是要每隔一段時間用人工手動發送。

本篇要解決的問題就是:怎麼用 Google 表單既有的功能,在收到新提交時,可以用程式自動寄送回覆通知信給報名者

這邊也建了一個 Demo,可以在這個 Google 表單上填表,送出成功後會收到系統通知信:

https://forms.gle/FLSqPayARHUc7FDq6


Google表單自動發送回覆信件流程圖

Google表單自動發送回覆信件流程圖(點擊看原圖)
Google表單自動發送回覆信件流程圖(點擊看原圖)

整體步驟如下:

  1. 建立 Google 表單,「回覆」選擇建立試算表。在試算表上,點擊「指令碼編輯器」
  2. 指令碼編輯器上,除了預設的「程式碼.gs」,再新增一個 HTML 檔案
  3. 新增的 HTML 貼上我們電子報的程式碼,需要替換的文字寫成變數形式:<?= 變數 =>
  4. 編輯「程式碼.gs」:抓取上一步新增的 HTML 檔案、設定變數、是否要用inline images、是否要夾帶附件、發送電子報
  5. 指令碼編輯器上點擊「現有專案的啟動程序」,在介面中新增觸發條件

1 建立Google表單,回覆的試算表點擊指令碼編輯器

Google表單建立時,一定要有一題是請使用者填寫 email,不然會不知道該寄給誰。

回覆用的試算表建立後,點擊上排的「工具」 > 「指令碼編輯器」:

點擊「工具」 > 「指令碼編輯器」
點擊「工具」 > 「指令碼編輯器」

接著會進到寫程式碼的介面,其實就是到了一個 Google Apps Script 的檔案上,可以在這寫程式碼,看到介面後第一步就完成了。

要注意的是,這份 Google 表單擁有者的帳號,就會是寄件者的帳號。

比方王小明看完了這篇,就用自己的 Google 帳號:[email protected] 來新增了一份表單,那當他照著本篇作完(或是複製貼上完 XD~),當有路人真的來填表了,收到的系統回覆信,寄件者就會寫 [email protected]

因此王小明也可以從 Gmail 的寄件備份中去查看到底寄了多少信出去。

如果想要用不同的信箱寄信,可看本筆記文的最後一段:用不同的寄件者信箱寄信


2 指令碼編輯器,新增HTML檔案

新增的 HTML 檔案就是我們電子報的檔案,要讓 Google Apps Script 抓到 HTML 的檔案,就得新增在這。

滑鼠移到左上角的「檔案」 > 「新增」,點選「HTML 檔案」:

「檔案」 > 「新增」,點選「HTML 檔案」
「檔案」 > 「新增」,點選「HTML 檔案」

接著取一個檔案名稱後按下確定,就新增完成。

新增完 HTML 檔案,會看到介面上一共有二個檔:程式碼.gs、xxx.html

新增 HTML 成功,會看見有程式碼.gs、xxx.html 二個檔案
新增 HTML 成功,會看見有程式碼.gs、xxx.html 二個檔案

程式碼.gs 就是寫收到提交後要自動回信的 JavaScript 部份。

XXX.html 就是寫我們回信用的電子報部份。

下一步我們先來處理電子報的內容。


3 電子報的 .html,要替換的文字寫成變數

一般用系統自動回信,為了讓使用者感到親切,大部份都會加上對方的名字,比方:「王小明 您好,很高興您這次參與本次調查」……之類的。

一般發報系統都可以加上一個變數,讓系統去自動替換,像是上面的例子就可能會寫成:「%name% 您好,很高興您這次參與本次調查 」,用的變數符號不一定,就看發報系統的規則。

Google Apps Script 在 HTML 檔案上也有自己的變數規則,就是:<?= 變數 =>

第一眼看的時候還以為是 PHP。

另外還有一個變數,但不一定要使用,就是如果想把圖片直接寫進電子報裡,而不是外部引用時,電子報上叫「inline images」,inline images的寫法就是:

<img src="cid:變數名稱">

這個在寫發送的程式碼那段會有補充。

本篇實作的 Demo 為了能反映變數這項功能,所以把 Google 表單上的每一題都設成變數寫進 HTML 裡,完整的 HTML 程式碼如下:

91-94 行就是寫入變數,之後會從程式碼.gs 中抓到使用者提交的資料後做替換。

這邊寫成以下:

填答時間:<?= data.時間戳記 ?>
暱稱:<?= data.暱稱 ?>
喜好:<?= data.喜好 ?>
程度:<?= data.程度 ?>

可以看到變數都帶有 data,這樣我們只需要命 data 這個變數 = 使用者提交的資料,一行就可以替換了。

使用者沒有填寫時,不會出現在信件中

看了一下官方文件,寫在 Google Apps Script 裡的 HTML 檔案,可以加入 ifelse 的判斷,上面的原始碼範例中已加入了「喜好」、「程度」這二題不為空值時,才載入 <p> 的判斷。

在 HTML 裡寫 ifelse 的範例如下:


4 程式碼部份

電子報的 HTML 完成後,下一步就是編輯 程式碼.gs 這個檔案,要做的事情有:

  • 抓取上一步新增的HTML檔案
  • 設定變數
  • 是否要用inline images
  • 是否要夾帶附件
  • 發送電子報

抓 HTML 檔案

var edmHTML = HtmlService.createTemplateFromFile('HTML的檔案名稱');

比方 August 的 HTML 叫 edm-demo.html,那就寫成以下:

var edmHTML = HtmlService.createTemplateFromFile('edm-demo');

設定變數

我們的 function 會帶一個 datas 的參數進來,像這樣:

function onSubmit(datas) {
  // ……
}

在上一篇 Telegram Bot:Google表單提交時收到通知 中有說,當有使用者提交表單時,我們可以收到的訊息主要都在「namedValues」這段,因此我們只要取出 namedValues 就可以知道新的提交有哪些資料。

function onSubmit(datas) {
  // 取得提交的值
  var data = datas.namedValues;
  var replyEmail = data['email'][0];

  // 設定HTML裡的變數
  var edmHTML = HtmlService.createTemplateFromFile('edm-demo');
  edmHTML.data = data;
}

取得 email 欄位,是為了讓程式知道自動回覆信要回覆到哪個 email。

上一段的 HTML 程式碼,把變數都設成了 <?= data.暱稱 => 這種前面加個 data 的,因此這邊我們直接把從提交中取得的值命成 HTML 的 data 就完成了變數的替換,就是這行:edmHTML.data = data;

inline images

inline images 是把圖片直接用 base64 寫進 HTML 中,不一定要用,用了有一個好處,就是我們一般用 outlook 收信時,圖片都會要按允許下載才會載入,用 inline images 的話就會直接顯示。

// 將 Telegram 圖轉為 inline image
var telegram = 'https://imgur.com/RvgV92X.png';
var telegramBlob = UrlFetchApp.fetch(telegram).getBlob().setName("telegram");

// ……

inlineImages: {
  telegram: telegramBlob
},

夾帶附件

夾帶附件很方便,可以直接抓 Google 雲端硬碟裡的檔案,只要知道檔案的 id 就行了。

取得檔案 id 的方法,就是對雲端硬碟中要夾帶成附件的檔案點一下,然後點選右上角表示連結的 icon,就會出現一個提示框裡帶有網址:

取得檔案的網址
取得檔案的網址

取得的網址會長這樣:

https://drive.google.com/open?id=xxxxxxxxxxxx

id 後面的 xxxxx 就是這個檔案的 id,有了 id 就可以夾帶成附件,如下:

var file1 = DriveApp.getFileById('xxxxxxxxxxx');
var file2 = DriveApp.getFileById('yyyyyyyyyyy');

// ……

attachments: [file1.getAs(MimeType.PNG), file2.getAs(MimeType.PNG)] // 附件

附件可以多個,包在陣列裡就行。

MimeType 可參考說明文件

發送電子報

本篇實作的 Demo,包含上述步驟的程式碼如下:


5 設定觸發條件

有了電子報的 HTML,也有了執行自動發送電子報的 function,最後一步就是要設定「當使用者提交時,執行寄送回覆電子報」的觸發條件。

一樣在 Google Apps Script 的介面上,點上面那排的「編輯」 > 「現有專案的啟動程序」:

點擊「編輯」 > 「現有專案的啟動程序」
點擊「編輯」 > 「現有專案的啟動程序」

畫面會進入到設定觸發條件的頁面上,點擊右下角的「新增觸發條件」:

設定觸發條件的頁面
設定觸發條件的頁面

觸發條件的新增,只要確定好二個選項--選擇要執行的功能、活動類型:

確定好二個選項:選擇要執行的功能、活動類型
確定好二個選項:選擇要執行的功能、活動類型

選擇要執行的功能,因為我們在上一步寫程式碼時,把處理的動作都寫在 onSubmit 這個 function 中,因此這邊就選 onSubmit。

活動類型指的就是什麼時候要觸發,這邊選「提交表單時」,意思就是當有人提交表單,就會執行 onSubmitonSubmit 裡就是做取資料、取電子報、取附件、發送……等這一系列我們前幾步寫入的動作。

按下儲存後,Google 會跟你要權限的確認,因為是我們自己寫的程式,就一律允許就行。

就這樣,當使用者提交了 Google 表單,系統就會自動寄發回覆信件給填單者。

最後這邊再提供一次本篇實作出的 Demo:

https://forms.gle/FLSqPayARHUc7FDq6

自動回覆的信件中,August 還放上了最近新開的 Telegram 頻道連結,如果想收到 Let’s Write 新文章通知的朋友,歡迎加入~


用不同的寄件者信箱寄信

要用不同的信箱來做自動回覆信件是可以的,但有額外的設定要做,依序為:

  1. 在 Gmail 新增其他的寄件地址
  2. Google Apps Script 要關閉 Chrome V8 功能
  3. 發送 email 換成 GmailApp.sendEmail

新增其他寄件地址

在開 Google Apps Script 的檔案時,檔案擁有者就會是預設的寄件者,而在 Gmail 裡,我們可以用額外的信箱來寄信,稱為「別名 Aliases」,我們的帳號新增完別名,就可以用這些別名來當作寄件者。

進到 Gmail 的頁面後,點選右上角的齒輪,再點「查看所有設定」:

點齒輪、點查看所有設定
點齒輪、點查看所有設定

進到設定頁,上面的頁籤點「帳戶和匯入」,下面會有一項是「選擇寄件地址」,再點擊「新增另一個電子郵件地址」,新增完後就會出現在列表中:

新增別名
新增別名

上圖是已經新增成功的,August 額外新增了 2 個信箱,再加上原本的,列表上會呈現出 3 個。

新增完其他寄件地址後,我們就可以用這些信箱來讓系統自動寄信。

關閉 Chrome V8 功能

進到 Google Apps Script,需要先關掉 Chrome V8 的功能,這樣在抓別名進來時才不會報權限不足的錯誤而卡住。

Google Apps Script 的頁面上點上排的「執行」,接著點「停用……」的那排(字太長懶得打,直接看下面截圖 XD):

停用 Chrome V8 功能
停用 Chrome V8 功能

停用後,最後就是改我們的程式碼。

GmailApp.sendEmail

文件:getAliases()sendEmail(recipient, subject, body, options)

在發送信件的函式,原本我們是用 MailApp.sendEmail,但為了能用不同的寄件信箱,我們得改用 GmailApp.sendEmail

以下的程式碼,會示範:判斷第三題「喜好」的答案,因答案不同,而使用不同的寄件信箱,以及不同的寄件者名稱。

取得所有寄件地址

在第一步中我們建立了 Gmail 上的「其他寄信地址」,這一段程式碼是取得主帳號的信箱 + 其他寄件地址:

我們可以包成一個 function,然後用 Logger.log(aliases) 去看 aliases 的陣列順序。

寄送信件

寄送信件的 function 如下:

完整的範例程式碼


參考資源

Class MailApp
How to send HTML email in Google Apps Script

Summary
Google表單,提交後系統自動寄送回覆通知email
Article Name
Google表單,提交後系統自動寄送回覆通知email
Description
本篇大綱:本篇要解決的問題。Google表單自動發送回覆信件流程圖。1 建立Google表單,回覆的試算表點擊指令碼編輯器。2 指令碼編輯器,新增HTML檔案。3 電子報的 .html,要替換的文字寫成變數。4 程式碼部份。5 設定觸發條件。用不同的寄件者信箱寄信。
Augustus
Let's Write
Let's Write
https://letswrite.tw/wp-content/uploads/2020/08/logo_512.jpg
訂閱
通知
guest

25 Comments
最舊
最新
Inline Feedbacks
看所有留言
poweryll
poweryll
3 年 之前

很棒的說明及示範。請問可否有方法當資料欄位是空白(非必填的),在回覆時也不出現?不然會出現一個有表頭無內容的顯示。在美觀上及個人覺得不太優。

poweryll
poweryll
回覆給  August
3 年 之前

這也是個方法。

poweryll
poweryll
回覆給  poweryll
3 年 之前

在網路上有看見 deleteRow 的做法,改天來試試再來說試做心得。

poweryll
poweryll
回覆給  August
3 年 之前

令人驚訝的超快速反饋,敬佩!

poweryll
poweryll
回覆給  August
3 年 之前

用不同的寄件者信箱寄信,這個方式不太了解用途,比較少用到的功能吧!?是要讓使用者再回覆去做其他動作嗎?再讓使用者去回覆信件,在行銷上不太合消費者行為的方式。
以使用者經驗來說應該是在不同答案(需求),通知不同單位的負責窗口,例如選貓通知貓店,選狗通知狗店,讓負責單位去主動解決使用者的需求,比較符合消費者行為。
以上拙見。

poweryll
poweryll
回覆給  August
3 年 之前

上次提及
以使用者經驗來說應該是在不同答案(需求),通知不同單位的負責窗口,例如選貓通知貓店,選狗通知狗店,讓負責單位去主動解決使用者的需求,比較符合消費者行為。

利用  if、else 自己做了測試結果可行
來分享一下
過程如下

 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var sheet = SpreadsheetApp.getActiveSheet();    
 var lastRow = sheet.getLastRow();
 var range = sheet.getRange(lastRow,2); //location 的位置
 var location = range.getValue(); //取得數值
 if (location === ‘cat’){
  adminEmail = ‘[email protected]’ //自訂email
 }
 else if (location === ‘dog’){
  adminEmail = ‘[email protected]//自訂email
 } 
 else if (location === ‘mouse’) {
  adminEmail = ‘[email protected]//自訂email
 }

Last edited 3 年 之前 by poweryll
huaaaaa
huaaaaa
3 年 之前

謝謝大大提供這麼實用的說明與示範

想請教一個問題是,我在練習的時候,跑到var data = datas.namedValues;
會顯示Cannot read property ‘namedValues’ of undefined是為什麼呢?

grownup
grownup
3 年 之前

我刪改成我要運行的程式碼,
跑起來結果SyntaxError: Unexpected token ‘;’ at onSubmit
問題可能出在哪邊呢?
如果表單標頭要用到1.這類的,我可以怎麼改程式呢

Adrian
Adrian
2 年 之前

請問一下function onSubmit(datas) 當中偵錯出現 var data = datas.namedValues; var replyEmail = data[‘電子郵件Email’][0];都出錯是甚麼問題?

蕭小姐
蕭小姐
回覆給  August
2 年 之前

我是出現var data = datas.namedValues;這一行的錯誤,請問是為什麼呢?

Brian
Brian
2 年 之前

您好,感謝用心分享!
不好意思,另想請教一下,在啟動完現有專案後,會一直出現SyntaxError: Unexpected number at onSubmit,不曉得該如何克服呢,謝謝!

cocowow
cocowow
2 年 之前

想詢問如果有些資料是在excel進行運算而非使用者留的資料,那要怎麼嵌入到html裡面?

June
June
2 年 之前

你好,我想碰到一直跳出 Exception 的問題
Exception: You do not have permission to call SpreadsheetApp.getActiveRange.
請問可以怎麼解決?我的表單設計填答的時候有收集使用者信箱

jeff chan
jeff chan
2 年 之前

您好,請教一下:可能是我自己太笨拙了,一直無法完成html。
因為我只想在google表單提交時,填表者可以收到一封回信,內文想帶圖片(可以有連結網站)
另外附加檔案讓填表者收到。
請問~一定要用html才能完成嗎?我看到有簡易版,只有在程式碼填下面語法, 我試過可以簡單回信,但無法附加檔案。是否可以完成想要樣式,卻只要用程式碼即可?
不好意思,麻煩了。謝謝

function sendMails(e) {
var timestamp = e.values[0];
var name = e.values[1];
var mail = e.values[2];
MailApp.sendEmail
(mail,”您好!”+name,
name+”您好!此封為回覆信測試。”);
}

Vic
Vic
2 年 之前

您好, 關於夾帶附件可以直接用雲端硬碟檔案的id這部分, 我點了連結icon出現的不是像範例
open?id=xxxxx
而是/document/d/…/edit?usp=sharing&ouid=…&resourcekey=….=true&sd=true這樣的 請問該怎麼解決呢? 謝謝您