GAS×Googleドキュメント連携|文書作成を自動化する完全ガイド
毎月同じフォーマットの書類を作成する。宛名を変えるだけの文書を何十通も作る。スプレッドシートのデータを文書にひとつずつ転記する。どれも手作業でやると時間がかかる割に、頭を使う作業ではない。
GASを使えば、Googleドキュメントの作成・編集・変換を自動化できる。テンプレートから請求書を自動生成したり、差し込み印刷のように大量の文書を一括作成したり、面倒な繰り返し作業をコードに任せられる。
目次
GAS×Googleドキュメント連携のメリット
なぜGASでドキュメントを操作するのか
| メリット | 説明 |
|---|---|
| 繰り返し作業の自動化 | 同じフォーマットの文書を何度も作る必要がなくなる |
| データ連携 | スプレッドシートのデータを自動で文書に反映 |
| 一括処理 | 100件の請求書も1クリックで生成 |
| ヒューマンエラー防止 | 手入力によるミスがゼロに |
| 時間短縮 | 数時間の作業が数分で完了 |
自動化できる業務の例
- 請求書・見積書の作成
- 契約書のテンプレート生成
- 議事録・報告書の雛形作成
- 社内通達・お知らせ文書の作成
- 差し込み印刷(宛名だけ変えた文書の大量作成)
- 定期レポートの自動生成
- ドキュメントのPDF化・配布
DocumentAppの基本メソッド一覧
GASでGoogleドキュメントを操作するには、DocumentAppクラスを使う。
ドキュメントの作成・取得
// 新規ドキュメントを作成
const doc = DocumentApp.create('ドキュメント名');
// IDでドキュメントを取得
const doc = DocumentApp.openById('ドキュメントID');
// URLでドキュメントを取得
const doc = DocumentApp.openByUrl('https://docs.google.com/document/d/...');
// アクティブなドキュメントを取得(ドキュメントにバインドされたスクリプト用)
const doc = DocumentApp.getActiveDocument();
ドキュメントの基本情報
const doc = DocumentApp.openById('ドキュメントID');
// ドキュメント名を取得
const name = doc.getName();
// ドキュメントIDを取得
const id = doc.getId();
// ドキュメントURLを取得
const url = doc.getUrl();
// ドキュメントを保存して閉じる
doc.saveAndClose();
本文(Body)の操作
const doc = DocumentApp.openById('ドキュメントID');
const body = doc.getBody();
// テキストを追加
body.appendParagraph('新しい段落を追加');
// 見出しを追加
body.appendParagraph('見出し1')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
// リストを追加
body.appendListItem('リストアイテム1');
body.appendListItem('リストアイテム2');
// 水平線を追加
body.appendHorizontalRule();
// 画像を追加
const imageBlob = UrlFetchApp.fetch('画像URL').getBlob();
body.appendImage(imageBlob);
// テーブルを追加
const table = body.appendTable([
['列1', '列2', '列3'],
['データ1', 'データ2', 'データ3']
]);
テキストの検索・置換
const body = doc.getBody();
// テキストを検索
const searchResult = body.findText('検索文字列');
// テキストを置換(全置換)
body.replaceText('検索文字列', '置換文字列');
// 正規表現で置換
body.replaceText('\\{\\{NAME\\}\\}', '山田太郎');
書式設定
const paragraph = body.appendParagraph('テキスト');
// フォントサイズ
paragraph.setFontSize(14);
// 太字
paragraph.setBold(true);
// 文字色
paragraph.setForegroundColor('#FF0000');
// 配置(中央揃え)
paragraph.setAlignment(DocumentApp.HorizontalAlignment.CENTER);
実践例1: スプレッドシートから請求書を自動生成
概要
スプレッドシートに入力された請求データから、請求書ドキュメントを自動生成する。
スプレッドシートの構成
| A列 | B列 | C列 | D列 | E列 |
|---|---|---|---|---|
| 請求番号 | 顧客名 | 品目 | 数量 | 単価 |
| INV-001 | 株式会社ABC | Webサイト制作 | 1 | 500000 |
コード
/**
* スプレッドシートのデータから請求書を自動生成
*/
function generateInvoice() {
// スプレッドシートからデータ取得
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('請求データ');
const data = sheet.getDataRange().getValues();
// ヘッダー行をスキップしてデータを処理
for (let i = 1; i < data.length; i++) {
const row = data[i];
const invoiceNumber = row[0];
const customerName = row[1];
const item = row[2];
const quantity = row[3];
const unitPrice = row[4];
const total = quantity * unitPrice;
// 請求書ドキュメントを作成
createInvoiceDocument(invoiceNumber, customerName, item, quantity, unitPrice, total);
}
SpreadsheetApp.getUi().alert('請求書の生成が完了しました');
}
/**
* 請求書ドキュメントを作成
*/
function createInvoiceDocument(invoiceNumber, customerName, item, quantity, unitPrice, total) {
// 新規ドキュメント作成
const doc = DocumentApp.create(`請求書_${invoiceNumber}_${customerName}`);
const body = doc.getBody();
// タイトル
body.appendParagraph('請求書')
.setHeading(DocumentApp.ParagraphHeading.TITLE)
.setAlignment(DocumentApp.HorizontalAlignment.CENTER);
// 請求番号・日付
body.appendParagraph(`請求番号: ${invoiceNumber}`);
body.appendParagraph(`発行日: ${Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy年MM月dd日')}`);
body.appendHorizontalRule();
// 宛先
body.appendParagraph(`${customerName} 御中`)
.setFontSize(14)
.setBold(true);
body.appendParagraph('');
// 請求金額
body.appendParagraph(`ご請求金額: ¥${total.toLocaleString()}(税込)`)
.setFontSize(18)
.setBold(true);
body.appendParagraph('');
// 明細テーブル
const table = body.appendTable([
['品目', '数量', '単価', '金額'],
[item, String(quantity), `¥${unitPrice.toLocaleString()}`, `¥${total.toLocaleString()}`]
]);
// テーブルのスタイル設定
const headerRow = table.getRow(0);
for (let i = 0; i < headerRow.getNumCells(); i++) {
headerRow.getCell(i).setBackgroundColor('#f0f0f0');
}
body.appendParagraph('');
// 振込先情報
body.appendParagraph('【お振込先】')
.setBold(true);
body.appendParagraph('○○銀行 △△支店 普通 1234567');
body.appendParagraph('口座名義: カ)サンプル');
body.appendParagraph('');
body.appendParagraph('お支払期限: 発行日より30日以内');
doc.saveAndClose();
console.log(`請求書作成完了: ${doc.getUrl()}`);
}
実行方法
- スプレッドシートの「拡張機能」→「Apps Script」
- 上記コードを貼り付け
generateInvoice関数を実行
実践例2: テンプレートから差し込み文書作成
概要
テンプレートドキュメントのプレースホルダー({{NAME}}など)を、スプレッドシートのデータで置換し、大量の文書を一括作成する。
テンプレートの例
{{COMPANY_NAME}} 御中
拝啓 時下ますますご清祥のこととお慶び申し上げます。
{{NAME}} 様
この度は弊社サービスにお申し込みいただき、誠にありがとうございます。
お申し込み内容: {{PLAN_NAME}}
ご利用開始日: {{START_DATE}}
ご不明点がございましたら、お気軽にお問い合わせください。
敬具
コード
/**
* テンプレートから差し込み文書を一括作成
*/
function createMailMergeDocuments() {
const TEMPLATE_ID = 'テンプレートドキュメントのID';
const OUTPUT_FOLDER_ID = '出力先フォルダのID';
// スプレッドシートからデータ取得
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('顧客データ');
const data = sheet.getDataRange().getValues();
const headers = data[0];
// 出力フォルダ
const outputFolder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);
// 各行のデータで文書を作成
for (let i = 1; i < data.length; i++) {
const row = data[i];
// テンプレートをコピー
const templateFile = DriveApp.getFileById(TEMPLATE_ID);
const newFile = templateFile.makeCopy(`文書_${row[0]}_${row[1]}`, outputFolder);
// ドキュメントを開く
const doc = DocumentApp.openById(newFile.getId());
const body = doc.getBody();
// 各列のデータでプレースホルダーを置換
headers.forEach((header, index) => {
const placeholder = `{{${header}}}`;
const value = row[index] || '';
body.replaceText(placeholder, String(value));
});
doc.saveAndClose();
console.log(`作成完了: ${newFile.getName()}`);
}
SpreadsheetApp.getUi().alert(`${data.length - 1}件の文書を作成しました`);
}
スプレッドシートの構成
| COMPANY_NAME | NAME | PLAN_NAME | START_DATE |
|---|---|---|---|
| 株式会社ABC | 田中太郎 | スタンダードプラン | 2026/04/01 |
| 有限会社XYZ | 鈴木花子 | プレミアムプラン | 2026/04/15 |
ポイント
- ヘッダー行の列名がそのままプレースホルダー名になる
{{COMPANY_NAME}}は「COMPANY_NAME」列の値で置換される- 大量のデータでも1クリックで全文書を生成できる
実践例3: 議事録テンプレートの自動生成
概要
会議情報を入力すると、議事録の雛形ドキュメントを自動生成する。
コード
/**
* 議事録テンプレートを自動生成
*/
function createMeetingMinutesTemplate() {
// 入力ダイアログ
const ui = SpreadsheetApp.getUi();
const meetingNameResponse = ui.prompt('会議名を入力してください');
if (meetingNameResponse.getSelectedButton() !== ui.Button.OK) return;
const meetingName = meetingNameResponse.getResponseText();
const participantsResponse = ui.prompt('参加者を入力してください(カンマ区切り)');
if (participantsResponse.getSelectedButton() !== ui.Button.OK) return;
const participants = participantsResponse.getResponseText();
// ドキュメント作成
const today = Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy-MM-dd');
const doc = DocumentApp.create(`議事録_${meetingName}_${today}`);
const body = doc.getBody();
// タイトル
body.appendParagraph('議事録')
.setHeading(DocumentApp.ParagraphHeading.TITLE)
.setAlignment(DocumentApp.HorizontalAlignment.CENTER);
// 会議情報
body.appendParagraph('会議情報')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
const infoTable = body.appendTable([
['会議名', meetingName],
['日時', Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy年MM月dd日 HH:mm')],
['場所', '(記入してください)'],
['参加者', participants],
['議事録作成者', '(記入してください)']
]);
body.appendParagraph('');
// 議題
body.appendParagraph('議題')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
body.appendListItem('議題1: (記入してください)');
body.appendListItem('議題2: (記入してください)');
body.appendListItem('議題3: (記入してください)');
body.appendParagraph('');
// 議論内容
body.appendParagraph('議論内容')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
body.appendParagraph('【議題1について】');
body.appendParagraph('(議論内容を記入)');
body.appendParagraph('');
// 決定事項
body.appendParagraph('決定事項')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
body.appendListItem('決定事項1: ');
body.appendListItem('決定事項2: ');
body.appendParagraph('');
// アクションアイテム
body.appendParagraph('アクションアイテム')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
const actionTable = body.appendTable([
['No', 'タスク', '担当者', '期限'],
['1', '', '', ''],
['2', '', '', ''],
['3', '', '', '']
]);
// ヘッダー行のスタイル
const headerRow = actionTable.getRow(0);
for (let i = 0; i < headerRow.getNumCells(); i++) {
headerRow.getCell(i).setBackgroundColor('#4285f4');
headerRow.getCell(i).editAsText().setForegroundColor('#ffffff').setBold(true);
}
body.appendParagraph('');
// 次回予定
body.appendParagraph('次回予定')
.setHeading(DocumentApp.ParagraphHeading.HEADING1);
body.appendParagraph('日時: ');
body.appendParagraph('場所: ');
body.appendParagraph('議題: ');
doc.saveAndClose();
ui.alert(`議事録テンプレートを作成しました\n\n${doc.getUrl()}`);
}
実践例4: ドキュメントの一括PDF変換
概要
指定フォルダ内のGoogleドキュメントを一括でPDFに変換し、別フォルダに保存する。
コード
/**
* フォルダ内のドキュメントを一括PDF変換
*/
function convertDocsToPdf() {
const SOURCE_FOLDER_ID = '変換元フォルダのID';
const OUTPUT_FOLDER_ID = '出力先フォルダのID';
const sourceFolder = DriveApp.getFolderById(SOURCE_FOLDER_ID);
const outputFolder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);
// Googleドキュメントを取得
const docs = sourceFolder.getFilesByType(MimeType.GOOGLE_DOCS);
let count = 0;
while (docs.hasNext()) {
const file = docs.next();
const docId = file.getId();
const docName = file.getName();
// PDFとしてエクスポート
const pdfBlob = DriveApp.getFileById(docId).getAs('application/pdf');
pdfBlob.setName(`${docName}.pdf`);
// 出力フォルダに保存
outputFolder.createFile(pdfBlob);
console.log(`PDF変換完了: ${docName}`);
count++;
}
SpreadsheetApp.getUi().alert(`${count}件のドキュメントをPDFに変換しました`);
}
/**
* 単一ドキュメントをPDF変換してメール送信
*/
function convertAndEmailPdf(docId, recipientEmail, subject) {
const doc = DriveApp.getFileById(docId);
const pdfBlob = doc.getAs('application/pdf');
pdfBlob.setName(`${doc.getName()}.pdf`);
GmailApp.sendEmail(
recipientEmail,
subject,
`添付ファイルをご確認ください。\n\n${doc.getName()}`,
{
attachments: [pdfBlob]
}
);
console.log(`PDF送信完了: ${recipientEmail}`);
}
ChatGPT連携: 文書内容も自動生成
ChatGPT APIと連携すれば、文書の内容自体もプログラムで生成できる。
コード
/**
* ChatGPTで文書内容を生成してGoogleドキュメントに出力
*/
function createDocumentWithChatGPT() {
const apiKey = PropertiesService.getScriptProperties().getProperty('OPENAI_API_KEY');
// プロンプト
const prompt = `以下のテーマで、ビジネス文書を作成してください。
テーマ: 新サービス「AI業務アシスタント」の社内向け案内文
要件:
- 簡潔で分かりやすい文章
- サービスの概要、メリット、利用開始方法を含める
- 箇条書きを活用
- 500文字程度`;
// ChatGPT API呼び出し
const content = callChatGPT(apiKey, prompt);
// ドキュメント作成
const doc = DocumentApp.create('AI業務アシスタント_社内案内');
const body = doc.getBody();
body.appendParagraph('社内案内')
.setHeading(DocumentApp.ParagraphHeading.TITLE);
body.appendParagraph(`作成日: ${new Date().toLocaleDateString('ja-JP')}`);
body.appendHorizontalRule();
body.appendParagraph(content);
doc.saveAndClose();
SpreadsheetApp.getUi().alert(`ドキュメントを作成しました\n\n${doc.getUrl()}`);
}
/**
* ChatGPT API呼び出し
*/
function callChatGPT(apiKey, prompt) {
const payload = {
model: 'gpt-3.5-turbo',
messages: [
{ role: 'user', content: prompt }
],
max_tokens: 1000,
temperature: 0.7
};
const options = {
method: 'post',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + apiKey
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
const response = UrlFetchApp.fetch('https://api.openai.com/v1/chat/completions', options);
const json = JSON.parse(response.getContentText());
return json.choices[0].message.content;
}
トラブルシューティング
エラー1: 「Document not found」
原因: ドキュメントIDが間違っている、またはアクセス権がない
解決法:
- ドキュメントURLからIDを再確認
- ドキュメントの共有設定を確認
エラー2: 「You do not have permission」
原因: スクリプトにドキュメントへのアクセス権がない
解決法:
- 初回実行時に権限を承認
- ドキュメントの共有設定で「編集者」権限を付与
エラー3: テキスト置換が動作しない
原因: プレースホルダーの書式が一致していない
解決法:
- プレースホルダー内にスペースや改行がないか確認
- 正規表現のエスケープを確認(
{{は\\{\\{)
まとめ
GASでGoogleドキュメントを操作する4つの実践例を紹介した。
今回のコード一覧
| 実践例 | 用途 | 削減効果 |
|---|---|---|
| 請求書自動生成 | スプレッドシート→請求書 | 1件5分→10秒 |
| 差し込み文書 | テンプレート→大量文書 | 100件5時間→3分 |
| 議事録テンプレート | 会議情報→雛形作成 | 10分→1分 |
| 一括PDF変換 | ドキュメント→PDF | 10件30分→1分 |
次のステップ
- 今日: サンプルコードをコピーして動かしてみる
- 明日: テスト用のスプレッドシート・テンプレートを作成する
- 今週中: 実際の業務に適用して効果を確認
コメント