0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Googleクラウドサービスを利用して時間指定メール送信システムを作る(その8)

Last updated at Posted at 2017-10-25

前へ> <次へ
 メール送信順のため,フォーム入力内容が蓄積されたスプレッドシートから必要データを切り出し,別のスプレッドシートとして,mailフォルダに格納する作業を行います。


1. 送信準備のためフォームに入力されたデータをmailフォルダに保存

画像2.png

  • 時間指定メール送信フォームが完成し,入力した内容を修正用URLを入力した人に返信できるようになった。フォームに入力した内容は一つのスプレッドシートに蓄積されるので,送信準備のため,入力した内容を切り出して,mailフォルダに格納する。ソフトウェア構成図の④,⑤,⑥を行う。
  1. フォームで送信が行われた段階で,二重起動を防ぐためのロック等の処理をした後,フォームで作成されたSpreadsheetの最下行のデータを取得する。
  2. 取得したデータを専用フォルダ「mail」内に用意した新規Spreadsheetに書き込む。
  3. 一定時間(たとえば1分)ごとに実行するGASプログラムで,現在日時を取得し,保存されたメールファイルの中から,送信日時が現在時刻より古いものを抽出し送信する。
  4. 送信したファイルは削除する。

 今日は,2までを行う。

2.フォーム入力データが格納されたGoogle Spreadsheetの作成

  • 時間指定メール送信システムフォームに,データを5件程度入力せよ。過去と未来の両方の送信日時を含むものとする。送信メール内容は適当で構わないが,メールの宛先は必ず自分の公式メールアドレスにすること。
  • フォーム編集画面から「回答」をクリック。

画像38.png

  • スプレッドシートの作成,をクリック。新しいスプレッドシートを作成する。

画像39.png


画像40.png

  • 新しいSpreadsheetが作成され,自動で開かれる。

画像41.png

  • Google Driveを見るとSpreadsheetが確認できる。

画像42.png

  • 新規にフォルダ「mail」を作成する。

画像47.png

  • **SpreadsheetとmailフォルダのIDを確認しておく。**mailフォルダのIDは,そのフォルダに入ってURLで確認する。folders/の後ろの部分がID。
  • Spreadsheetのツールメニューからスクリプトエディタを起動し,プロジェクト名を変更。

画像43.png


画像44.png


画像45.png


  • デバッグやエラーを出力するファイルを作成。新規,から,Googleドキュメント,を選択し,「log2」というドキュメントを作成する。

画像19.png


  • 名前を「log2」に変更する。勝手に保存される。

100.png


  • log2に実行ログを書き込んだり,エラーを書き込んだりするので,開発中はlog2を開いたままにしておく。
  • log2のファイルIDをコピーし,あとで使用するため,エディターに貼り付けておく

画像22.png


  • スクリプトエディタで,最初から書かれているGASプログラム,「コード.gs」の4行は全削除する。
  • 次の内容をコピーペーストする。「**********」の部分は,エディタに貼り付けたIDに置き換える。
テンプレート
var logID    = "**********";//手動でDocument,「log2」を新規作成しIDを調べておく
var ssID1    = "**********";//フォーム入力で作成されたSpreadsheetのID
var ssID2    = "";                                            //mailフォルダに作成されたSpreadsheetのID
var folderID = "**********";                //mailフォルダのID

function submitForm(){//フォームが送信されたら呼び出される関数,重複処理を避ける
  log = new Doc(logID);
  log.print('\n'+getDateAndTime(0)+" スクリプト開始\n");
  var lock = LockService.getScriptLock();//ロックサービスのオブジェクトを生成
  try{
    lock.waitLock(30000);//複数のフォーム送信がほぼ同時にあった時,遅い方に最大30秒待ってもらう
    log.print("他のスクリプト実行要求をロック完了,最大60秒\n");
    main(log);
  }catch(err){
    log.print("発生したエラー:"+err+'\n');
  }finally{
    lock.releaseLock();//次の送信のためにロック解除
    log.print(getDateAndTime(0)+" ロック解除,次のスクリプト要求を受け付け開始\n");
  } 
}

function main(log){
  var ssSrc = new Ssheet(ssID1);//フォーム入力されたデータが入っているSpreadsheet
  var todayNow =getDateAndTime(0);//現在日時の取得

  var ssID2 = createSpreadsheetInFolder(folderID, "temp");//新規作成,ファイル名はとりあえずtemp,後で送信日時に変更する
  var ssDst = new Ssheet(ssID2); //最後にフォーム入力されたデータだけを記録するSpreadsheet

  var maxRow = ssSrc.getLastRow(0);
  var maxColumn = ssSrc.getLastColumn(0);
  log.print("最後の行"+maxRow+" 最後の列"+maxColumn+"\n");

  for(var i=1;i<=maxColumn;i++){
    var index = ssSrc.getValue(0, 1, i);
    ssDst.setValue(0, 1, i, index);
    var data = ssSrc.getValue(0, maxRow, i);
    if(index == "date"){
      var dateTmp = data;
      var date = getDateAndTime(dateTmp).split('_')[0];
      log.print(date+"\n");
      ssDst.setValue(0, 2, i, date);    
    }
    if(index == "time"){
      var timeTmp = data;
      var time = getDateAndTime(timeTmp).split('_')[1];
      log.print(time+"\n");
      ssDst.setValue(0, 2, i, time);
    }else{
      ssDst.setValue(0, 2, i, data);
    }
  }
  var fn = date + "_" + time;
  ssDst.rename(fn);
  log.print("最後に入力されたデータを新規Spreadsheetにコピー終了,ファイル名を送信日時に変更\n");

}

//-----------------------日付や時間のための関数群
function getSerial(date,time){//日付と時間からシリアル値をゲット
  var serial = new Date(date.toString().slice(0,16)+time.toString().slice(16));
  return serial;
}

function getDateAndTime(data){// 引数がゼロなら現在日時そうでなければ指定日時をyyyymmdd_hhmmssで返す
  if(data==0) var now = new Date();
  else        var now = new Date(data);
  var year = now.getYear();
  var month = now.getMonth() + 1;
  var day = now.getDate();
  var hour = now.getHours();
  var min = now.getMinutes();
  var sec = now.getSeconds();
  return (""+year).slice(0,4) + ("0"+month).slice(-2) + ("0"+day).slice(-2) +'_'+ 
    ("0"+hour).slice(-2) + ("0"+min).slice(-2) + ("0"+sec).slice(-2);
}

//-----------------------ファイルの新規作成等の関数群
//フォルダID,ファイルID,ファイル名を受け取り,ファイルIDのコピーをフォルダ内に作成して,ファイルのIDを返す
function copyFileInFolder(folderID, srcID, fileName) {
  var originalFile = DriveApp.getFileById(srcID);
  var folder = DriveApp.getFolderById(folderID);
  var copiedFile = originalFile.makeCopy(fileName, folder);
  copiedFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.EDIT);//リンクからアクセスできる人は編集可能にする
  var copiedFileId = copiedFile.getId();//コピーのファイルIDをゲット
  return copiedFileId;
}
//フォルダID,ファイル名を受け取り,スプレッドシートを指定フォルダ内に新規作成しそのファイルIDを返す
function createSpreadsheetInFolder(folderID, fileName) {
  var folder = DriveApp.getFolderById(folderID);
  var newSS=SpreadsheetApp.create(fileName);
  var originalFile=DriveApp.getFileById(newSS.getId());
  var copiedFile = originalFile.makeCopy(fileName, folder);
  DriveApp.getRootFolder().removeFile(originalFile);
  var copiedFileId = copiedFile.getId();//コピーのファイルIDをゲット
  return copiedFileId;
}

//////////Ssheetクラスの定義開始(コンストラクタとメンバ関数で構成)
//Ssheetクラスのコンストラクタの記述
Ssheet = function(id){
  this.ssFile = SpreadsheetApp.openById(id);
  this.ssFileName = this.ssFile.getName();
  SpreadsheetApp.setActiveSpreadsheet(this.ssFile);//値を返さない
  this.activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
}
//Ssheetクラスのメンバ関数(メソッド)の定義開始
//spreadsheetのファイル名を返すメソッド
Ssheet.prototype.getFileName = function(){
  return this.ssFileName;
}
//spreadsheetのファイル名を変更するメソッド
Ssheet.prototype.rename = function(newName){
  this.ssFile.rename(newName);
}
//spreadsheetのsheetでrow行cal列にデータを入れるメソッド
Ssheet.prototype.setValue = function(sheet,row,col,value){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.setValue(value);
}
//spreadsheetのsheetでrow行cal列をクリアするメソッド
Ssheet.prototype.clear = function(sheet,row,col,value){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.clear(value);
}
//spreadsheetのsheetからrow行のcal列のデータをもらってくるメソッド
Ssheet.prototype.getValue = function(sheet,row,col) {
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var value = this.activeSheet.getRange(row, col).getValue();
  return value;
}
//背景の色を設定するメソッド
Ssheet.prototype.setBackgroundColor = function(sheet,row,col, r,g,b) {
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  var cell = this.activeSheet.getRange(row,col);
  cell.setBackgroundRGB(r,g,b);
}
//spreadsheetのsheet数を指定の数増やすメソッド
Ssheet.prototype.insertSheet = function(num){
  var sheetNum = this.activeSpreadsheet.getNumSheets();
  while(num>sheetNum){
    this.activeSpreadsheet.insertSheet();
    sheetNum++;
  }
}
//spreadsheetの指定sheetを削除
Ssheet.prototype.deleteSheet = function(sheet){
  this.activeSpreadsheet.deleteSheet(this.activeSpreadsheet.getSheets()[sheet])
}
//spreadsheetのsheetの名前をセットするメソッド
Ssheet.prototype.renameSheet = function(sheet,newName){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.setName(newName);
}
//spreadsheetの指定sheetの全データを取得
Ssheet.prototype.getValues = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet.getDataRange().getValues();//シートの全データを取得
}  
//spreadsheetの指定sheetを取得
Ssheet.prototype.getSheet = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet;//シートを返す
}
//spreadsheetの指定sheetの最後の行番号を取得
Ssheet.prototype.getLastRow = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet.getLastRow();//最後の行番号を取得
}
//spreadsheetの指定sheetの最後の列番号を取得
Ssheet.prototype.getLastColumn = function(sheet){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  return this.activeSheet.getLastColumn();//最後の列番号を取得
}
//spreadsheetの指定行rowを削除
Ssheet.prototype.deleteRow = function(sheet,row){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.deleteRow(row);//行を削除
}
//spreadsheetの指定行rowを挿入
Ssheet.prototype.insertRow = function(sheet,row){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.insertRows(row);//行を挿入
}
//spreadsheetの指定列colを削除
Ssheet.prototype.deleteColumn = function(sheet,col){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.deleteColumn(col);//列を削除
}
//spreadsheetの指定列colを挿入
Ssheet.prototype.insertColumn = function(sheet,col){
  this.activeSheet = this.activeSpreadsheet.getSheets()[sheet];
  this.activeSheet.insertColumns(col);//列を挿入
}
//////////Ssheetクラスの定義終了

//////////Docクラスの定義開始(コンストラクタとメンバ関数で構成)
//Docクラスのコンストラクタの記述
Doc = function(id){
  this.ID = id;
  this.doc = DocumentApp.openById(this.ID); 
  this.body = this.doc.getBody();
  this.docText = this.body.editAsText();
}
//Docクラスのメンバ関数の定義開始
//メソッドprintの定義,テキスト追加
Doc.prototype.print = function(str){
  this.docText.appendText(str);
}
//メソッドreplaceの定義,文字列置き換え
Doc.prototype.replace = function(src,dst){
  this.body.replaceText(src,dst);
}
//メソッドclearの定義,全消去
Doc.prototype.clear = function(){
  this.body.clear();
}
//メソッドgetIDの定義,ファイルIDを返す
Doc.prototype.getID = function(){
  return this.ID;
}
//指定秒数のウェイト,表示動作を遅らせたい時などに使用
Doc.prototype.waitSec = function(sec){
  var start = new Date().getSeconds();
  while((new Date().getSeconds()-start) < sec);
}
//指定ミリ秒のウェイト,表示動作を遅らせたい時などに使用
Doc.prototype.waitMiliSec = function(msec){
  var start = new Date(); //new Date()は,「1970年1月1日午前0時」からの通算ミリ秒を返す
  while((new Date()-start) < msec);
}
//今現在の日時を表示
Doc.prototype.printTodayNow = function(){
  var now = new Date();
  var year = now.getYear();
  var month = now.getMonth() + 1;
  var day = now.getDate();
  var hour = now.getHours();
  var min = now.getMinutes();
  var sec = now.getSeconds();
  this.docText.appendText(year +'_'+ ("0"+month).slice(-2) +'_'+ ("0"+day).slice(-2) +' '+ 
    ("0"+hour).slice(-2) +'-'+ ("0"+min).slice(-2) +'-'+ ("0"+sec).slice(-2));
}
/////////Docクラスの定義終了

  • 現在のプロジェクトのトリガーを設定する。

画像28.png


画像29.png


画像30.png


  • 承認の許可を求められるので,内容を確認して許可する。

画像31.png


画像33.png


  • log2を見えるようにした状態で,フォームに入力して送信する。間違っても人に迷惑をかけないため,送信先アドレスは自分のアドレスにする。
  • log2で動作チェックを行う。フォーム入力で作成されたSpreadsheetの最下行に追加されたデータが,mailフォルダに新規作成され,送信日時のファイル名となっているSpreadsheetの内容になっていることを確認する。

 次は,タイムベース実行する関数を作成し,1分ごとに実行し,メール送信時間になったら,メール送信を行います。
前へ> <次へ


0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?