HTMLメール用のソースコード生成を自動化したい

ECサイト制作をやっていると、販促用のメールマガジンを作ることがよくあります。HTMLメール自体はテンプレート化されていて、変更するのは商品情報だけ。その場合、毎回ソースコードを変更するのは大変だし、何よりHTMLがわからないと変更できないのもメンテナンス性悪いなと思ってスプレッドシートの値を変更するだけで、HTMLメールを生成して指定したディレクトリにドキュメントとして保存するようにしようと思ってまとめました。

スプレッドシートの準備

以下のようなデータを準備しました。

HTMLに出力するデータ

このデータをHTMLテンプレートに流し込む処理を書いていきます。

HTMLテンプレートの準備

「ツール」→「スクリプトエディタ」からスクリプトエディタを起動して、「ファイル」→「新規作成」からHTMLファイルを選択して名前をつけます。「index.html」とつけました。
とりあえずHTMLの枠組みだけ組みます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="UTF-8">
  <title>メールマガジン</title>
</head>
<body>
  <ul>
  </ul>
</body>
</html>

ul要素の中にli要素を商品点数分ループさせて出力というものを作ってみます。スタイルなどは割愛します。

スプレッドシートのデータ取得とHTMLテンプレートとの連携

スプレッドシートの商品データの取得とテンプレートへデータを渡すところまでGASファイルに記述します。

function exportHTML() {
 var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("商品データ");

  // 最終行を取得して商品点数を計算(-1は見出し行)
  var count = sheet.getLastRow() - 1;
  
  // HTMLテンプレートファイル指定(index)
  var html = HtmlService.createTemplateFromFile("index");
  
  // 商品データをHTMLテンプレートファイルに
  html.productData = sheet.getRange(2, 1, count, 4).getValues();
  Logger.log(html.productData);
}
  1. 2行目 – シート名:商品データのオブジェクトを取得。
  2. 5行目 – 商品データの数を取得。最終行から見出しの1行分を引いて算出。
  3. 8行目 – HtmlServiceクラスのcreateTemplateFromFileメソッドでテンプレートを指定。
  4. 11行目 – テンプレートにproductDataという変数名でスプレッドシートの値を渡す。

スプレッドシートの値が取得できているかは、Logger.log(html.productData);で確認します。

スプレッドシートデータのログを確認

うん、ちゃんと取得できている。準備ができたらHTMLファイル側に処理を書きます。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="UTF-8">
  <title>メールマガジン</title>
</head>
<body>
  <ul>
  <? productData.forEach(function(option) { ?>
    <li>
    <a href="<?= option[2] ?>"><img src="<?= option[1] ?>"></a>
    <span><?= option[0] ?></span>
    <span>¥<?= option[3].toString().replace(/(\d)(?=(\d{3})+$)/g , '$1,'); ?></span>
    </li>
  <? }); ?>
  </ul>
</body>
</html>

9〜15行目を追加しました。productData配列をforEachで繰り返します。option配列にデータを1件ずつ取得して該当の情報をもとにHTMLを構成します。

指定したフォルダに保存する準備

あとは保存先を指定します。exportHTML関数に以下のコードを追加します。

function exportHTML() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("商品データ");

  // 最終行を取得して商品点数を計算(-1は見出し行)
  var count = sheet.getLastRow() - 1;
  
  // HTMLテンプレートファイル指定(index)
  var html = HtmlService.createTemplateFromFile('index');
  
  // 商品データをHTMLテンプレートファイルに
  html.productData = sheet.getRange(2, 1, count, 4).getValues();
  
  var outputFolder = DriveApp.getFolderById("xxxxxフォルダIDを入力してくださいxxxxx");
  var date = new Date();
  outputFolder.createFile("mailMag_" + Utilities.formatDate(date, "Asia/Tokyo", "yyyyMMddhhmmss"), html.evaluate().getContent(), MimeType.HTML);
}

13行目でファイルを保存するフォルダを取得します。getFolderById関数の引数「xxxxxフォルダIDを入力してくださいxxxxx」にはフォルダIDを設定してください。フォルダIDはURLの末尾部分になります。

GoogleDriveのフォルダIDを確認

最後にフォルダに出力するファイルを設定します。createFile関数の第一引数で保存するファイルの名前を指定。今回はタイムスタンプをファイル名の末尾につけるようにしました。
第二引数でHTMLファイルの内容を取得して書き出し。これで準備OKです。

スプレッドシートにカスタム(独自)メニューを追加

準備ができたら今度は、スプレッドシートからHTML出力関数を実行できるようにカスタム(独自)メニューを追加します。

function onOpen() {
  var
    sheet = SpreadsheetApp.getActiveSpreadsheet(),
    entries = [
      {
        name : "実行",
        functionName : "exportHTML"
      }
    ];
  sheet.addMenu("HTMLファイル出力", entries);
}

10行目のsheet.addMenu()関数でメインメニューを追加します。サブメニューは配列(JSON形式)で引数として渡してあげます。(サブメニューを増やす時はJSONデータを増やしてあげましょう)
exportHTMLは先程作成したフックになる関数です。functionNameに指定してあげます。

スプレッドシートの画面をリロードするとメニューが表示されます。

スプレッドシートに独自メニューを追加

それでは実行してみましょう。

実行して確認してみる

それでは実行メニューをクリックしてみましょう。いざ実行!

ドキュメントが保存された状態

\(^o^)/できた!

保存したドキュメントを展開

\(^o^)/保存できて中身もできあがってる〜!これでスプレッドシートを更新すれば動的に出力できるな。シートを追加してフォルダIDや行列数などリテラル値になるようなものもシートに記入して変更できるようにしておくとますます便利ですなぁ。