GoogleフォームでGoogle Apps Scriptを使って回答内容を自動送信する

残しておきたいので久々にブログ書く。

Googleフォームに回答を送信すると、フォームのオーナーが回答のスプレッドシートを公開していない限り何送信したか確認できない。
というわけでスクリプトで回答者に送信するようにしました。


この記事・プログラムはこちらのブログを参考にしました。

www.narugaro.com


function submitForm(e){
  /*エラーしたとき用のまるごとtry*/
  try{
    var itemResponses = e.response.getItemResponses(); 
    var editurl = e.response.getEditResponseUrl();
    var message = '';
    
    for(var i = 0; i < itemResponses.length; i++) { 
      var itemResponse = itemResponses[i]; 
      var type = itemResponse.getItem().getType();
      var question = itemResponse.getItem().getTitle(); 
      var answer = itemResponse.getResponse(); 
      
      /*質問タイトルが「名前」のやつを名前として取得*/
      if(question == '名前'){
        var username = answer;
      }
      /*質問タイトルが「メールアドレス」のやつをメールアドレスとして取得*/
      if(question == 'メールアドレス'){
        var usermail = answer;
      }
      
      /*質問番号と質問タイトルをくっつける*/
      message += (i + 1).toString() + '. ' + question + ': ' + '\n';
      /*GRIDタイプなら1行ずつテキスト化*/
      if(type == 'GRID'){
        var rows = itemResponse.getItem().asGridItem().getRows();
        for(var j = 0; j < rows.length; j++){
          var rowname = rows[j];
          var answercol = answer[j];
          message += rowname + ' : ' + answercol + '\n';
        }
      /*それ以外の形式はそのままくっつける*/
      }else{
        message += answer + '\n'; 
      }
    } 
    
    /* 管理者宛メール送信設定 */
    var address = '管理者のアドレス'; 
    var title = '[回答を受け取りました]'; 
    var content = '下記の内容で、回答を受信しました。\n\n'
    + message
    + '\n\n'
    + '※このメールはGoogleフォームからの自動送信メールです。'; 
    var options = {from: 'FROMのアドレス', name: '参加フォーム', replyTo: usermail};
    
    GmailApp.sendEmail(address, title, content, options);
    
    /*メールアドレスを入力していた場合のみ*/
    if(usermail){
      /* ユーザー宛メール送信設定 */
      var title2 = '[回答を受け付けました]'; 
      var content2 = username 
      + ' さん\n\n'
      + '回答ありがとうございます。\n'
      + '下記の内容で、受け付けました。\n'
      + '内容を変更したい場合は、もう一回フォームを送ってください。\n\n'
      + message 
      + '\n\n'
      + '回答を編集する場合このアドレスをつかってください\n'
      + editurl
      + '\n'
      + '\n'
      + '~~署名~~\n'
      + '\n\n※このメールはGoogleフォームからの自動送信メールです。'; 
      var options2 = {from: 'FROMのアドレス', name: '参加フォーム'};
      
      GmailApp.sendEmail(usermail, title2, content2, options2); 
    }
  }catch(err){
    var error = err;
    Logger.log("message:" + error.message + "\nlineNumber:" + error.lineNumber + "\nstack:" + error.stack);
  }
}


使い方
フォームの作成段階で「名前」の回答欄と、「メールアドレス」の回答欄を作ります。
フォーム編集画面の上の方の縦の…(その他)からスクリプトエディタを立ち上げる。
↑のプログラムを突っ込む。
「フォーム送信時」のトリガーを設定する。

HTML/PHP-ヘッダー上部の隙間が埋まらない!→includeの文字挿入だった

前の記事で、タイトルヘッダーの上の隙間が
CSSでmargin:0にしても埋まらないことで悩んでいたのですが、
これはPHPでincludeしたときにBOMと呼ばれる16ビットの値が入ることが原因でした。

これをなおすには「UTF-8N」形式で保存(呼び出し側も呼び出される側も)しなくてはいけないようです。
TeraPadなどでできる)


参考:
http://www.barnetshenkinbridge.com/other/1538/#?1#?1#WebrootPlugIn#?1#?1#PhreshPhish#?1#?1#agtpwd

HTML/CSS-margin:0にしても上の隙間が消えない!

しょうもないことで長時間悩んでしまったので、同じことで悩む人を出さないためにまとめときます。

サイトの上部に表示するタイトルヘッダーって、画面の上に隙間なく置きたいですよね。

なんですが、


このサイトのタイトルだよ!
中の文章~~~
~~~~~~~

<div id="body1">
  <div id="title1">このサイトのタイトルだよ!</div>
  <div id="text1">中の文章~~~<br>~~~~~~~</div>
</div>
<style type="text/css">
#body1{
  background-color:#333;
  height:200px;
  margin:0;
}
#title1{
  background-color:#fff;
}
#text1{
  color:#fff;
}
</style>

(body1のdivはbody要素と思っておらって大丈夫です)
こんな風にかくと見ての通りタイトルの上に隙間が開いています。

これを一番上にもってきたい!と思って、調べてみると「勝手に入れられているmarginが悪いから、margin:0;を入れればいい」と出てくるのですが、それをやっても直らない!!!


でも、よくよく考えると、

divはブロック要素
ブロック要素は前後に改行が挿入される

・・・あ、divにしてたら前に改行入っちゃうじゃん・・・



というわけで、これを改善するには

1.divタグで囲まない


このサイトのタイトルだよ!
中の文章~~~
~~~~~~~

<div id="body2">
  このサイトのタイトルだよ!
  <div id="text2">中の文章~~~<br>~~~~~~~</div>
</div>
<style type="text/css">
#body2{
  background-color:#333;
  height:200px;
}
#text2{
  color:#fff;
}
</style>

2.divタグをインライン要素にする


このサイトのタイトルだよ!
中の文章~~~
~~~~~~~

<div id="body3">
  <div id="title3">このサイトのタイトルだよ!</div>
  <div id="text3">中の文章~~~<br>~~~~~~~</div>
</div>
<style type="text/css">
#body3{
  background-color:#993;
  height:200px;
}
#title3{
  display:inline;
  background-color:#fff;
}
#text3{
  color:#fff;
}
</style>


このどちらかで解決できます。
どうしてもdivで囲いたいけど、前後の改行は無くしたいときはインライン要素にしましょう


追記

この後いろいろ試してたら原因は別だったみたいで。

サイトをDeveloper Toolで見てみたら(F12を押すと出ます)、

f:id:kagan:20140810021724p:plain

_人人人人人人人人人人_
>  謎の空白文字  <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

_人人人人人人人人人人人人人人人人人人人人人_
> しかもheadに書いてるものがbodyにいる  <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

謎でしかない。

Deveoper Tool上でこれを直接消したところ上の隙間が消えたのでこれが原因だったみたい

ソースコードの片っ端から空白や改行を消すしかないんだろうか

更に追記

実は、私は複数のページで使うような内容をHTMLファイルとして、それぞれのページでは

<?php
  include'xxx.html';
?>

として読み込んでいるんですが、

どうやらそのときに文頭に謎の文字が挿入されるようで。

それが改行となっていたようです。

このやり方にする限り直らないのかな

さらにさらに追記

この謎の文字、BOMというらしく、ちゃんと解決法が乗ってました。

http://www.barnetshenkinbridge.com/other/1538/#?1#?1#WebrootPlugIn#?1#?1#PhreshPhish#?1#?1#agtpwd


追記が多くなってしまったので、別記事にまとめようと思います。

HTML/CSSヘッダー固定のスクロールテーブル

ヘッダーを固定させたままデータ部だけスクロールさせる方法はいろいろありますが、一番簡単と思われる方法を紹介します。


↓HTML

<table>
  <thead class="scrollHead">
    <tr><th class="no">番号</th><th class="name">お名前</th><th class="address">連絡先</th></tr>
  </thead>
  <tbody class="scrollBody">
    <tr><td class="no">1</td><td class="name">半田</td><td class="address">handa@xxx.com<td></tr>
    <tr><td class="no">2</td><td class="name">野崎くん</td><td class="address">nozaki@xxx.com<td></tr>
    <tr><td class="no">3</td><td class="name">なにゃこ</td><td class="address">nagarekawa@xxx.com<td></tr>
    <tr><td class="no">4</td><td class="name">ゆりか</td><td class="address">rainbow@xxx.com<td></tr>
    <tr><td class="no">5</td><td class="name">るるも</td><td class="address">majimoji@xxx.com<td></tr>
    <tr><td class="no">6</td><td class="name">ヒメくん</td><td class="address">hime@xxx.com<td></tr>
  </tbody>
<table>

CSS

/*スクロール用*/
thead.scrollHead,tbody.scrollBody{
  display:block;
}
tbody.scrollBody{
  overflow-y:scroll;
  height:100px;
}

/*幅調整*/
td,th{
  table-layout:fixed;
}
.no{
  width:30px;
}
.name{
  width:50px;
}
.address{
  width:200px;
}


↓実際の表示

番号お名前連絡先
1半田handa@xxx.com
2野崎くんnozaki@xxx.com
3なにゃこnagarekawa@xxx.com
4ゆりかrainbow@xxx.com
5るるもmajimoji@xxx.com
6ヒメくんhime@xxx.com
theadとtbodyにちゃんと分けて、それぞれをブロック要素にしてtbodyにはスクロールバーをつけるということです。 (ブロック要素じゃないとスクロールバーが付けられない) ただし、このようにクラスでしている通り、colgroupによるwidth設定はできませんのでご注意。

Google Apps ScriptでCron実行→メールでアウトプット(スレッド化)

これまで未来サーバーを使ってPHPプログラムのCron実行を行っていたのですが、Google Apps ScriptからCron実行みたいなことができるということでこっちを使ってみました。

今回はこちらのブログを参考にさせていただきました↓

無料でお手軽Cron!Google Apps Scriptを使ってみる。 - きじとら

<トリガーの時間に関して>

トリガーを5分間隔にしたところ、04,09,14,...(分)と00,05,と5の倍数にはならないみたい?
5の倍数の分数にピッタリあった時間で何かしたい場合はトリガーを1分間隔にしてプログラム上で5分間隔に何かするのがいいみたいです。

<メールで出力>

また、この記事では僕がこれまで未来サーバーの"Cron Output"で見ていたような、echoやvar_dumpの結果をメール送信で見る方法が紹介されているのですが、これをそのまま実行すると、スレッド化されずバラバラの判定になりました。

せっかくGmailを使っているので、スレッド化させたいと思い、スレッド化されるようにしました。

ついでに日付・時刻もつけるなどいじってみました。

function myFunction() {
  var date = new Date();
  var Now = Utilities.formatDate(date, "JST", "yyyy-MM-dd HH:mm:ss");

  var response = UrlFetchApp.fetch("http://example/cron.php");
  var title = "Cronの実行結果"
  var text = "Run at "+Now+"\n\n"+response.getContentText();
  var threads = GmailApp.search("subject:"+title);

  if(!threads.length){
    GmailApp.sendEmail("example@gmail.com", title, text);
  }else{
    threads[0].reply(text);
  }
}

色々つけて煩雑になってしまいましたが、

スレッド化のポイントは、目的のスレッドをsearchによって探し、それに対して返信する、ということです。

ここでは、スレッドにするメールのタイトルを予め決めておき、そのタイトルのスレッドがあるか検索、無ければメールを新規作成、あるならそれに対して送信します。