×

[PR]この広告は3ヶ月以上更新がないため表示されています。
ホームページを更新後24時間以内に表示されなくなります。


Googleを追いかけろ!

.

チュートリアル 上級者 3-1: シンプルなメール統合

  • スプレッドシート上のFormを利用した各ユーザーからの情報を集計し、その後個別化されたメールを生成して配信します。 15分程度が目安でしょう。

    getRowsData 関数については 2-1.スプレッドシートの読み取りで扱っています。

    Google Formsについて

§1 スプレッドシートの準備とサンプルの実行

§2 コードを理解する

§3 練習 : Formと個別化されたメールの修正

§4 さらに強力なテンプレート

§5 完成コード

チュートリアル 上級者/目次 参照ページ(Goolge)


WWW を検索 Googleを追いかけろ! を検索


§1スプレッドシートの準備とサンプルの実行

  1. 準備としてここからテンプレートを取得します。 テンプレートの取得
  2. ファイルメニューから自分用のコピーを作成してください。
  1. Form menu から Go to live form を用いて自分のメールアドレスを送信します。
    >> * フォーム - Google ドキュメント ヘルプ
    >> * フォームサンプル・・http://www.radio-oh.com/enq/enq.html
  1. スプレッドシートに戻ると新たな行に自分の送信内容が送信日時とともに追加されています。
  1. 【Script Editor】を開きます。
  2. simple_mail_merge をクリックしてスクリプトを見ましょう。
  3. 【Script Editor】で sendEmails を実行すると行数と同じだけメールが送信されています。
  4. 自分のメールをクリックするとメールが送信されるまで数秒かかります。更新してください。

§2 コードを理解する

理解に必要な部分を取り上げて解説します。スプレッドシート、Mail API、一般的なJavaScriptについて説明しますが、 完成コードはこちらです。§5 コードの完成
  1. sendEmails 関数
var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 4);
この行はスプレッドシート内に含まれるすべてのデータの範囲を取得します。範囲外はサポートされません。 利用されるすべての行番号の範囲を計算します。
 var templateSheet = ss.getSheets()[1];
  var emailTemplate = templateSheet.getRange("A1").getValue();

個別化されたメールを生成するために使われるテンプレートを回収します。これはEmail Templateとう名前の2番目のシートの A1 セルに 定義付けられています。
${"First Name"} といった4種類のマーカーを確認してください。これらはシートのたて列名に対応しています。 与えられた行からのデータを指定して表示します。
  // データ行毎にひとつのJavaScriptオブジェクトを作る
  objects = getRowsData(dataSheet, dataRange);
与えられたセル範囲のすべてのデータを読み取ります。 2-1.スプレッドシートの読み取り
  // 個別化されたメールの生成
  // (例えばrowData.firstName)などの行オブジェクトの値に対応しながらマーカー(例えば${"First Name"})を置き換える
  var emailText = fillInTemplateFromObject(emailTemplate, rowData);
上のコードでテンプレートに文字を与えます。Formを使って送られてきた情報を含むメールのテキストを準備しています。
MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText);
必要なメールを送信します。
  1. fillInTemplateFromObject 関数
 //  置き換えるべきすべての変数を検索(例えば${"Column name"})
  var templateVars = template.match(/\$\{\"[^\"]+\"\}/g);
JavaScriptmatch 関数が与えられたテキスト(Regular Expressions)パターンのインスタンスを探します。
var variableData = data[normalizeHeader(templateVars[i])];
マーカーに対応したデータオブジェクト中の値を回収しようとしています。この作業はマーカー名の正規化と正規化された名前と関連ある値を持つ データオブジェクトのチェックにより終了します。
email = email.replace(templateVars[i], variableData || "");
値と共にマーカーをテンプレート中に置き換えます。また検索中に値のないマーカーは破棄します。

§3 練習 : Formと個別化されたメールの修正

ここで個別化されたメールや Form の修正が可能になります。
  1. Form メニューから 【Edit Form】 を開きます。回収したい部門名にたいする新しい質問事項を付け加えます。
  2. the live form を開きデータを送信します。結果が分かるように自分のアドレスを入れるようにして下さい。
  3. Form の新しい質問に対応した新規のたて列がどのように作られるかを理解してください。
  4. ではメールテンプレート(2番目のシートの A1 セル)を修正して、受信したメール中の新たな部門名を表示するマーカーを付け加えます。 シート上のたて列名とマーカー名が同一であることがポイントです。Script Editor
  5. 【Script Editor】 を開き、新しいたて列の部門が読めるように sendEmails 関数中の dataRange 変数を更新します。
r dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 5);
  1. sendEmailsを実行してメールをチェックしてください。
  2. メール中に新規の部門があるかどうか確かめましょう。もしない場合はテンプレート中のマーカー名を確認してください。

§4 さらに強力なテンプレート

上級者用のテンプレートに興味が湧いてきましたか?コピー&ペーストで簡単に使えるオープンソースなEJS(JavaScriptテンプレートライブラリー)などもチェックすることをお勧めします。 テンプレートをウェブサーバ以外に設置したい場合はGoogleの URLFetchservice を利用したテンプレートがダウンロードできます。

§5 完成コード

function sendEmails() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var dataSheet = ss.getSheets()[0];
  var dataRange = dataSheet.getRange(2, 1, dataSheet.getMaxRows() - 1, 4);

  var templateSheet = ss.getSheets()[1];
  var emailTemplate = templateSheet.getRange("A1").getValue();

  // Create one JavaScript object per row of data.
  objects = getRowsData(dataSheet, dataRange);

  // For every row object, create a personalized email from a template and send
  // it to the appropriate person.
  for (var i = 0; i < objects.length; ++i) {
    // Get a row object
    var rowData = objects[i];

    // Generate a personalized email.
    // Given a template string, replace markers (for instance ${"First Name"}) with
    // the corresponding value in a row object (for instance rowData.firstName).
    var emailText = fillInTemplateFromObject(emailTemplate, rowData);
    var emailSubject = "Tutorial: Simple Mail Merge";

    MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText);
  } 
}


// Replaces markers in a template string with values define in a JavaScript data object.
// Arguments:
//   - template: string containing markers, for instance ${"Column name"}
//   - data: JavaScript object with values to that will replace markers. For instance
//           data.columnName will replace marker ${"Column name"}
// Returns a string without markers. If no data is found to replace a marker, it is
// simply removed.
function fillInTemplateFromObject(template, data) {
  var email = template;
  // Search for all the variables to be replaced, for instance ${"Column name"}
  var templateVars = template.match(/\$\{\"[^\"]+\"\}/g);

  // Replace variables from the template with the actual values from the data object.
  // If no value is available, replace with the empty string.
  for (var i = 0; i < templateVars.length; ++i) {
    // normalizeHeader ignores ${"} so we can call it directly here.
    var variableData = data[normalizeHeader(templateVars[i])];
    email = email.replace(templateVars[i], variableData || "");
  }

  return email;
}





//////////////////////////////////////////////////////////////////////////////////////////
//
// The code below is reused from the 'Reading Spreadsheet data using JavaScript Objects'
// tutorial.
//
//////////////////////////////////////////////////////////////////////////////////////////

// getRowsData iterates row by row in the input range and returns an array of objects.
// Each object contains all the data for a given row, indexed by its normalized column name.
// Arguments:
//   - sheet: the sheet object that contains the data to be processed
//   - range: the exact range of cells where the data is stored
//   - columnHeadersRowIndex: specifies the row number where the column names are stored.
//       This argument is optional and it defaults to the row immediately above range; 
// Returns an Array of objects.
function getRowsData(sheet, range, columnHeadersRowIndex) {
  columnHeadersRowIndex = columnHeadersRowIndex || range.getRowIndex() - 1;
  var numColumns = range.getEndColumn() - range.getColumn() + 1;
  var headersRange = sheet.getRange(columnHeadersRowIndex, range.getColumn(), 1, numColumns);
  var headers = headersRange.getValues()[0];
  return getObjects(range.getValues(), normalizeHeaders(headers));
}

// For every row of data in data, generates an object that contains the data. Names of
// object fields are defined in keys.
// Arguments:
//   - data: JavaScript 2d array
//   - keys: Array of Strings that define the property names for the objects to create
function getObjects(data, keys) {
  var objects = [];
  for (var i = 0; i < data.length; ++i) {
    var object = {};
    var hasData = false;
    for (var j = 0; j < data[i].length; ++j) {
      var cellData = data[i][j];
      if (isCellEmpty(cellData)) {
        continue;
      }
      object[keys[j]] = cellData;
      hasData = true;
    }
    if (hasData) {
      objects.push(object);
    }
  }
  return objects;
}

// Returns an Array of normalized Strings.
// Arguments:
//   - headers: Array of Strings to normalize
function normalizeHeaders(headers) {
  var keys = [];
  for (var i = 0; i < headers.length; ++i) {
    var key = normalizeHeader(headers[i]);
    if (key.length > 0) {
      keys.push(key);
    }
  }
  return keys;
}

// Normalizes a string, by removing all alphanumeric characters and using mixed case
// to separate words. The output will always start with a lower case letter.
// This function is designed to produce JavaScript object property names.
// Arguments:
//   - header: string to normalize
// Examples:
//   "First Name" -> "firstName"
//   "Market Cap (millions) -> "marketCapMillions
//   "1 number at the beginning is ignored" -> "numberAtTheBeginningIsIgnored"
function normalizeHeader(header) {
  var key = "";
  var upperCase = false;
  for (var i = 0; i < header.length; ++i) {
    var letter = header[i];
    if (letter == " " && key.length > 0) {
      upperCase = true;
      continue;
    }
    if (!isAlnum(letter)) {
      continue;
    }
    if (key.length == 0 && isDigit(letter)) {
      continue; // first character must be a letter
    }
    if (upperCase) {
      upperCase = false;
      key += letter.toUpperCase();
    } else {
      key += letter.toLowerCase();
    }
  }
  return key;
}

// Returns true if the cell where cellData was read from is empty.
// Arguments:
//   - cellData: string
function isCellEmpty(cellData) {
  return typeof(cellData) == "string" && cellData == "";
}

// Returns true if the character char is alphabetical, false otherwise.
function isAlnum(char) {
  return char >= 'A' && char <= 'Z' ||
    char >= 'a' && char <= 'z' ||
    isDigit(char);
}

// Returns true if the character char is a digit, false otherwise.
function isDigit(char) {
  return char >= '0' && char <= '9';
}
このコードに修正を付け加えなくても新しい Form と個別化されたメール送信ができます。




    * チュートリアル 上級者/目次
    1. シンプルなメール統合 - フォームやスプレッドシートと特定されたメールの配信を結びつける
    2. 経費報告書の承認 -フォームやスプレッドシートを扱う上での簡単なワークフローアプリケーションの作成
    3. Google App Engine services - Google App Engineで構築されたウェブサービスと連携する
    4. ソープ IP Service に関して - サードパーティーのIP Geocoding service を呼び出すための Soap Service
    5. XML Document の構成要素の分析 - ウェブ上のソースをXML dataとしてパースする
    6. Help Desk Workflow - メール,フォーム,スプレッドシート,カレンダー,サイト等のhelp desk workflow 自動化
    7. Twitter用承認マネージャ - OAuth, MailApp, ScriptProperties, UiAppを利用したTwitter用承認マネージャ
    8. 予約アプリケーションの作成 - Ui Services in Apps Scriptを活用してGoogle Sitesに予約アプリケーションを作成
    --チュートリアル 上級者 3-1. シンプルなメール統合 : end -- 2011/10/30