今日はGoogleフォームの自動返信の文面をプログラミングを知らない人にも簡単に書き換えられるようにする方法を考えます
背景
Google Docs (最近はDriveになっちゃいました)を使うとお手軽にウェブフォームなどを作れるので,すでに使われている方も多いと思います.低予算で済ませたいプロジェクトなんかの場合,大学の職員さんにも利用をおすすめしています.
デフォルトの状態では少し使いづらくて,例えば確認メールを自動返信する機能がないとか,普通のサイトにはあるよねって思うことがなかったりして,不便に感じることが多々あります.しかし,Googleさんはさすがに偉大でして,ほとんどの問題には解決策があります.例えば,自動返信メールの場合,Google Apps Script を使えば実現することができます.
基本的には,送信というイベントをトリガーにして情報を取得します.以下2つは参考サイトです.データの取得の考え方が少し違いますがやっていることは同じです.
問題点
で,これらの解法が気に食わなかった点が何かというとJavaScript の基本的な書き方が分からない人は,返信文面の編集すらできないということです.「こういうスクリプトを書けばできますよー」とJSを書けない誰かに説明して,「やっぱりメールの文面をかえたいです!」って言われたときにJSの分かる人が書き換えてあげなければなりません.だって,行末のセミコロンの意味とか,\n が改行文字だということを知らない人にとっては,ソースを直接書き換えるのは恐怖でしょう.エラーが起きたらお手上げでしょう.そういう状況を作ってしまうのはよくありませんね.
というわけで,一度設定してあげればそれ以降は(基本的には)誰にも聞かずに文面やCC,ReplyTo アドレスを編集できるのが理想的です.
解法
ソースコードの中に文面情報を持ってしまうと,どうしてもJavaScript (Google Apps Script)のルールで書かなければならないので,外側に出します.ここでは,Google Docs のドキュメントにテンプレート情報を保存する方法を採用します.ドキュメントファイルは,Document Class として簡単に読み込むことができます.
まずは,下のキャプチャのようなウェブフォームを作ります.今回はデモなので名前とメールアドレスだけを聞く単純なフォームにします.もっと実用的なフォームでも考え方は同じです.

次に,下のキャプチャのようなGoogleドキュメントを書きます(枠と枠内右上のキャプションは説明のために付加してます).

このテンプレートは,ヘッダ・ボディ・メモの3つのエリアに分けられていて,それぞれのエリアは === (3つ以上連続するイコール)で区切られています.
- 赤枠で囲まれたヘッダ部分に,送信時の『subject (題名)』『name (送信者名)』『cc』『bcc』『replyTo』を設定します.題名についても,フォームの入力情報を反映させることができますが,今回はやりません.
- 青枠で囲まれた部分が,メールの本文に当たる部分です.{{Name}} および{{E-mail}} と2重の波括弧で囲まれた部分を,フォームの対応するテキストボックスに入力された情報で置き換え,それを本文として自動返信します.(Timestamp も入れてしまっていますが,これはDocsの言語設定によって名前が変わるので注意してください)
- メモ部(2つ目の === 以降)は完全に無視しますので,何を書いても大丈夫だと思います(たぶん)
このようにテンプレートを記述しておけば,JavaScript のルールを意識しなくてもメールの文面を編集することができますよね?どうでしょう?
ソース
じゃあテンプレートの適用はどうするのということで,とりあえず次のようにやりました.もっとうまい方法があれば教えてください
2行目に指定しているGoogleドキュメントのIDはドキュメントを開いたときのURLを見れば分かります.メールアドレスが格納される列の名前だけは特別扱いで,3行目にグローバル変数として指定しています.
42行目以降の loadTemplate() 関数は,テンプレートファイルを取得して,ヘッダ部分とボディー部分を取り出します.
取り出した情報を使って,35行目のMailApp.sendEmail()に必要な情報を作っています.コア部分は,22,23行目の2重波括弧で囲まれたキーワードを置き換えるところです
// Doc ID of the template file
var id = "koko_ni_id_wo_iretekudasai";
var mailCol = "E-mail";
function onFormSubmit(e){
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var r = ss.getLastRow();
var c = ss.getLastColumn();
var rg = ss.getDataRange();
// Processing the body part
var t = loadTemplate(id);
var body = t.body;
var v = {};
for ( var j = 1; j <= c; j++ ){
// Replacing the template keyword into the input value
var cname = rg.getCell(1, j).getValue();
var entry = rg.getCell(r, j).getValue();
v[cname] = entry;
var re = new RegExp("{{"+cname+"}}", "g");
body = body.replace(re, entry);
}
// Processing the header part
var mail = v[mailCol];
var subject = t.head.subject;
var opt = { cc: t.head.cc,
bcc: t.head.bcc,
replyTo: t.head.replyTo,
name: t.head.name };
// Sending the message
MailApp.sendEmail( mail, subject, body, opt );
} catch (e) {
// When exception raised
MailApp.sendEmail(Session.getActiveUser().getEmail(), "Error report", e.message);
}
}
function loadTemplate(docId){
// Load your template doc file
// docId = Google Docs Document ID
// Find it from doc's URI
var t = DocumentApp.openById(docId).getText();
// Comment out strings after double slashes
t = t.replace(new RegExp("//.*\n", 'g'), "");
// Body part is placed between a pair of lines with more than 3 consecutive ='s
var tsplit = t.split(/===+.*\W+/);
// Retrieving the header part
// that should be placed before the first ===
var head = {};
var lines = tsplit[0].split(/\n+/);
for ( var i in lines ){
var line = lines[i];
if ( null != line.match(/(\w+)\s*=\s*(.+)$/)) {
head[RegExp.$1] = (RegExp.$2).trim();
}
}
// Retrieving the body part
// that should be place between the firs and last ==='s
var body = tsplit[1];
return { head: head, body: body};
}
結果
こんな感じになります.うまく行ってそうですね
