GASでスプレッドシートから
差し込み文書を一括生成する方法

請求書・お礼状・契約書を1件ずつ手作業でコピペしていませんか。GASなら、GoogleドキュメントのreplaceText()(文字の置き換えメソッド)でスプレッドシートの各行を1通の文書に変換し、PDF化やメール送付まで自動化できます。

|対象: GAS / Googleドキュメント / 差し込み印刷

Table of Contents

差し込み文書とは何か・準備するもの

差し込み文書とは、1つのひな形に宛名や金額を1件ずつ差し替えて複数の文書を作る仕組みです。Wordの差し込み印刷と同じ考え方で、GASではスプレッドシートの「1行」を「1通の文書」に変換します。

用意するものは次の3つです。

テンプレート文書

宛名や金額の位置に {{名前}} などの目印を書いたGoogleドキュメント

データのシート

1行=1通のデータ。1行目は「名前」「金額」などの見出し

出力先フォルダ

生成した文書やPDFを保存するGoogleドライブのフォルダ

テンプレートのIDと出力先フォルダのIDは、それぞれのURLに含まれる長い英数字の部分です。この2つを控えておけば準備完了です。

テンプレートに置く目印(プレースホルダ)の書き方

テンプレート側では、差し替えたい場所に{{名前}}のように二重波かっこで囲んだ目印(プレースホルダ)を書きます。たとえば「{{名前}} 様」「金額:{{金額}} 円」のように、普通の文章の中に埋め込みます。

二重波かっこを使う理由は、通常の文章には登場しない記号なので、うっかり本文の一部を書き換えてしまう誤置換を防げるからです。ロゴ・印影・表・ヘッダーはテンプレートに貼っておけば、そのまま全文書に反映されます。

1行から1通の文書を作る基本コード

まずは1件分のデータから1通の文書を作る関数です。ポイントはmakeCopy()でテンプレートを複製してから編集すること。元ファイルを直接書き換えないので、テンプレートは何度でも使い回せます。編集後は必ずsaveAndClose()で保存します。

// テンプレートIDと出力先フォルダIDは事前に控えておく
const TEMPLATE_ID = "テンプレートのGoogleドキュメントID";
const OUTPUT_FOLDER_ID = "出力先フォルダのID";

// 1件分のデータから1通のGoogleドキュメントを作る
function createOneDoc(data) {
  const folder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);

  // テンプレートを複製(元ファイルは書き換えない)
  const fileName = data["名前"] + "様_お礼状";
  const copy = DriveApp.getFileById(TEMPLATE_ID).makeCopy(fileName, folder);

  // 複製した文書を開いて本文を取得
  const doc = DocumentApp.openById(copy.getId());
  const body = doc.getBody();

  // {{目印}} を実際の値に置き換える
  body.replaceText("{{名前}}", data["名前"]);
  body.replaceText("{{会社名}}", data["会社名"]);
  body.replaceText("{{金額}}", Number(data["金額"]).toLocaleString());
  body.replaceText("{{発行日}}", formatDate(new Date()));

  doc.saveAndClose(); // 保存して閉じる(重要)
  return copy.getId();
}

function formatDate(d) {
  return Utilities.formatDate(d, "Asia/Tokyo", "yyyy年M月d日");
}

toLocaleString()で金額に3桁区切りのカンマを付け、Utilities.formatDate()で発行日を日本時間で整形しています。数値や日付は文字列に整えてから差し込むのがコツです。

全行をまとめて一括生成する

次に、シート全体をループして全員分の文書を作ります。1行目の見出しをキーにしたオブジェクトに変換しておくと、列の順番が変わってもコードを直す必要がなくなります。

// スプレッドシートの全行をまとめて文書化する
function generateAllDocs() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("差し込みデータ");
  const values = sheet.getDataRange().getValues();
  const header = values[0]; // 1行目は見出し

  for (let r = 1; r < values.length; r++) {
    const row = values[r];

    // 見出しをキーにしたオブジェクトへ変換(列の順番に依存しない)
    const data = {};
    header.forEach((name, c) => {
      data[name] = row[c];
    });

    const docId = createOneDoc(data);
    Logger.log((r) + "件目を生成: " + docId);
  }
}

data["名前"]のように見出し名で値を取り出せるため、「A列の何番目か」を数えなくて済みます。列を1つ増やしても、テンプレートに目印を足すだけで対応できます。

生成した文書をPDF化して保存する

請求書やお礼状は、編集できるドキュメントより固定レイアウトのPDFで渡すのが一般的です。getAs("application/pdf")でPDFのBlob(バイナリデータ)を取り出し、フォルダに保存します。編集用の文書が不要ならsetTrashed(true)でゴミ箱に送り、PDFだけ残します。

// 生成したGoogleドキュメントをPDFに変換して保存し、編集用ファイルは削除
function createPdf(docId, fileName) {
  const folder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);
  const docFile = DriveApp.getFileById(docId);

  // PDFのBlob(バイナリデータ)を取得
  const pdfBlob = docFile.getAs("application/pdf").setName(fileName + ".pdf");
  const pdfFile = folder.createFile(pdfBlob);

  // 編集用のGoogleドキュメントが不要ならゴミ箱へ
  docFile.setTrashed(true);

  return pdfFile;
}

二重生成を防ぎ結果を書き戻す

トリガーで繰り返し動かすと、同じ行から何通も文書を作ってしまう恐れがあります。「生成URL」列を用意し、値が入っている行はスキップします。生成に成功したら、その行に文書URLを書き戻して確定させます。

// 生成済み列を見て未処理行だけ処理し、結果をシートに書き戻す
function generateUnprocessedDocs() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("差し込みデータ");
  const values = sheet.getDataRange().getValues();
  const header = values[0];
  const statusCol = header.indexOf("生成URL"); // 生成URLを書き込む列

  for (let r = 1; r < values.length; r++) {
    const row = values[r];
    if (row[statusCol]) continue; // すでにURLがあればスキップ

    const data = {};
    header.forEach((name, c) => { data[name] = row[c]; });

    const docId = createOneDoc(data);
    const url = "https://docs.google.com/document/d/" + docId;

    // 生成URLと生成日時を書き戻す(1行ずつ確定)
    sheet.getRange(r + 1, statusCol + 1).setValue(url);
    SpreadsheetApp.flush();
  }
}

SpreadsheetApp.flush()は、書き込みを即座にシートへ反映させる命令です。1行ずつ確定させておけば、途中でエラーが出ても、どこまで処理できたかがシート上で分かります。

宛先ごとにメールで自動送付する

生成したPDFを、宛先ごとにメールで送るところまで自動化できます。行から読み取ったメールアドレス宛に、PDFを添付して送信します。誤送信が不安なうちは、sendEmailcreateDraftに変えて、下書きを目視確認してから送るのが安全です。

// 生成したPDFを宛先ごとにメール送付する(差し込みメール)
function sendDocsByEmail() {
  const sheet = SpreadsheetApp.getActive().getSheetByName("差し込みデータ");
  const values = sheet.getDataRange().getValues();
  const header = values[0];
  const sentCol = header.indexOf("送信日時");

  for (let r = 1; r < values.length; r++) {
    const row = values[r];
    if (row[sentCol]) continue; // 送信済みはスキップ

    const data = {};
    header.forEach((name, c) => { data[name] = row[c]; });

    // 文書を生成 → PDF化
    const docId = createOneDoc(data);
    const fileName = data["名前"] + "様_請求書";
    const pdfFile = createPdf(docId, fileName);

    // PDFを添付して送信(誤送信が不安なうちは createDraft に変える)
    GmailApp.sendEmail(data["メール"], "請求書のご送付", data["名前"] + " 様\n\n請求書を添付いたします。", {
      attachments: [pdfFile.getBlob()],
      name: "Lustage",
    });

    sheet.getRange(r + 1, sentCol + 1).setValue(new Date());
    SpreadsheetApp.flush();
  }
}

トリガーで定期実行・実務での注意点

未処理行だけを対象にする関数を時間主導トリガーに登録すれば、決まった時刻に自動で差し込み生成できます。

// 毎朝9時に未処理行だけ自動で差し込み生成する
function createDailyMergeTrigger() {
  ScriptApp.newTrigger("generateUnprocessedDocs")
    .timeBased()
    .everyDays(1)
    .atHour(9)
    .create();
}

1. 大量件数は実行時間制限に注意

1件ごとにテンプレート複製とPDF変換が走るため、数百件を一度に処理するとGASの6分制限に達することがあります。1回あたりの件数を区切り、続きは次回のトリガーで処理する設計にすると安定します。

2. 目印の消し忘れをチェックする

データに無い項目の目印が残ると、文書に「{{金額}}」がそのまま出てしまいます。生成後の本文に二重波かっこが残っていないかを確認する処理を入れておくと、事故を防げます。

3. 最初の数件は必ず目視確認する

置換後の文字数によって改ページ位置がずれる場合があります。本番運用の前に数件を実際に生成し、レイアウトの崩れがないか確かめておきましょう。

まとめ

GASの差し込み文書は、テンプレートの複製・replaceText()による置換・PDF化を組み合わせるだけで実現できます。生成済み列でスキップ制御をし、宛先ごとのメール送付や定期トリガーと組み合わせれば、請求書やお礼状の発行を人手ゼロで回せます。1件でも100件でも手間が変わらないのが最大の利点です。

よくある質問

差し込み文書とは、1つのひな形(テンプレート)に対して宛名や金額などの項目を1件ずつ差し替え、複数の文書をまとめて作る仕組みです。Wordの差し込み印刷と同じ考え方です。GASを使えば、スプレッドシートに並べたデータからGoogleドキュメントを人手を介さず一括生成でき、100件でも200件でも同じ手間で作れます。

Googleドキュメントのテンプレート内に「{{名前}}」「{{金額}}」のように、本文中で使わない記号で囲んだ目印を書いておきます。GAS側でreplaceText()を使い、この目印をスプレッドシートの値に置き換えます。二重波かっこ{{}}は通常の文章に登場しないため、誤置換を防げます。

できます。DocumentApp.openById()で開いた文書をsaveAndClose()した後、DriveApp.getFileById(id).getAs('application/pdf')でPDFのBlob(バイナリデータ)を取得し、フォルダに保存できます。編集用のGoogleドキュメントは不要なら削除し、PDFだけ残す運用がおすすめです。

スプレッドシートに「生成済み」列や「生成した文書のURL」列を用意し、値が入っている行はスキップします。生成に成功したら、その行に生成日時や文書URLを書き込みます。トリガーで繰り返し実行しても、未処理の行だけが対象になります。

できます。行ごとに生成したPDFのBlobを、GmailApp.sendEmail()の添付ファイルに指定して送信します。宛先メールアドレスもスプレッドシートの列から読み取れば、請求書やお礼状を相手ごとに自動送付できます。誤送信を防ぐため、最初は下書き作成(createDraft)で確認する運用が安全です。

replaceText()は文字の置換なので、テンプレートのフォント・表・画像・ヘッダーはそのまま維持されます。ロゴや押印画像はテンプレート側に貼っておけば全文書に反映されます。ただし置換後に文字数が大きく変わると改ページ位置がずれることがあるため、生成後に数件を目視確認しておくと安心です。

帳票・文書の自動発行を
相談する。

請求書・お礼状・契約書の差し込み生成やPDF発行、宛先ごとの自動送付など、文書業務の自動化をGAS開発でご相談いただけます。

GAS Webシステム開発を見る