過去に、Googleフォームの回答内容をGASで取得し、Googleドキュメント内の本文書き換え→PDF化したものをメールで送信するという技をお伝えしたところ、以下のようなお問い合わせを頂きました
出張者が、Googleフォームで氏名・出張日等を入力するとともに、「画像」をアップロードし、それをGoogleドキュメントのフォーマットでメールで送りたいと考えています。参考記事のように、PDF化したものでもよいのですが、出張者が修正できるようにした方が融通が利くと考えられるため、ドキュメントのまま送信したいです。
お問い合わせ内容の要約
まず、GASは画像を扱うことに弱いです
でも、大丈夫
ImgAppライブラリを活用してなんとかします!!!
質問者様から「Googleドキュメント」をメール送信したいとご要望を頂きましたが、Googleドキュメントはあくまでもクラウド上のサービスであるため、ここではWordに変換しましょう!と助言させて頂きました
今回の記事は、Googleフォームの回答(画像含む)をメール送信するというもので、非常に実用的だと思います
お問い合わせ頂いた方から許可を頂いたため、皆様にも「画像」を扱う場合について共有したいと思います!
なんと「有料級の回答」と言って頂きました!
私自身、2024年4月から起業予定なので、業務に役立つ情報が提供できたと自信がつきました!
この記事を読めば、画像を含むGoogleフォームの回答データを取得し、Googleドキュメント内に反映→Word文書化する方法を学ぶことができます!めちゃくちゃ便利なので、是非読んでいってください!
GASを極めたい方や、業務の効率化を図りたい方は、ぜひこの記事を読んください!
難しいことはGASに任せて、我々人間は楽しちゃいましょう!
当ブログでは実際に仕事でGASを扱っている私が、GASの魅力について徹底的に取り上げていきます!
事前準備
本記事は初心者の方向けに丁寧に解説しているので、事前準備を飛ばして先に進みたい!という方はここをクリックして、ジャンプしてください
【事前準備①】Googleフォームを作成する
項目名 | タイプ | 必須 |
---|---|---|
メールアドレス | メール | |
氏名を選択してください | プルダウン | |
欠席日を入力してください | 日付 | |
連日にまたがって欠席する場合は、欠席期間の終了日を入力してください | 日付 | |
届出理由を選択してください | ラジオボタン | |
欠席理由のエビデンスを必要に応じてアップロードしてください | ファイルのアップロード |
参考に私が作成したフォームは以下となります!
1つでも回答がないとエラーになってしまうので、回答しておいてください!
【事前準備②】Googleドキュメントを作成する
それでは、次にGoogleドキュメントで欠席届テンプレートを作成しましょう!
どんな様式でも構いませんが上記フォームの値をマッピングさせるため、それを意識して作成してみて下さい!
今回、こちらの「欠席届(画像ver)」を使って演習します!
必要に応じてコピーして使ってください!
{{}}(可変文字部)について
この{{date}}みたいに波括弧で囲んであるのは何なの?
波括弧の部分は「可変文字部」といって、{{}}内を入力内容に書き換える魔法のような存在なんだ!詳しくは、以前の記事で説明しているよ!
是非読んでみてね!
【事前準備③】コピーしたドキュメントの出力場所の作成
一時的にコピーしたドキュメントを収納するフォルダ(temp)を作りましょう!
// ドキュメント出力先
const DOCX_OUTDIR = DriveApp.getFolderById('〇〇〇〇〇〇(自分のフォルダID)');
あとでフォルダIDを記載する必要があるので、忘れずにメモしておきましょう!
【お題】Googleフォームの回答をGoogleドキュメント内に反映し、Word文書にしてメールを自動送信する
作成したGoogleフォームの「︙」をクリックして「〈〉スクリプトエディタ」から、コンテナバインド型でエディタを開こう!
まずはコード全文を確認
まずはコード全文を確認しよう!
// 欠席届テンプレートファイル
const DOC_TEMPLATE = DriveApp.getFileById('〇〇〇〇〇〇(自分のドキュメントID)');
// ドキュメント出力先
const DOCX_OUTDIR = DriveApp.getFolderById('〇〇〇〇〇〇(自分のフォルダID)');
// 最後の削除用リスト
let delIdLst = new Array();
function gaslog_formSubmit(e) {
let itemResponses;
// フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
if (e !== undefined) {
itemResponses = e.response.getItemResponses();
} else {
const wFormRes = FormApp.getActiveForm().getResponses();
itemResponses = wFormRes[wFormRes.length-1].getItemResponses();
}
// 回答をもとに欠席届を作成する
let wFileRtn = createGDoc(itemResponses);
// DOCX変換してファイルIDを取得する
let wPdfId = createDocx(wFileRtn[0], wFileRtn[1]);
delIdLst.push(wFileRtn[0]);
delIdLst.push(wPdfId);
// 今回はDOCXファイルを添付してメールを送信する
sendEmailEx(
e !== undefined ? e.response.getRespondentEmail() : '(eが未定義の場合に送信されるメールアドレス)'
, wFileRtn[2]
, `受講生より欠席届が送信されました。`
, {attachments: DriveApp.getFileById(wPdfId).getBlob()}
);
// 各種保存したファイルを削除する
delIdLst.forEach(function(delId){
DriveApp.getFileById(delId).setTrashed(true);
});
}
function createGDoc(itemResponses) {
// テンプレートファイルをコピーする
const wCopyFile = DOC_TEMPLATE.makeCopy()
, wCopyFileId = wCopyFile.getId()
, wCopyDoc = DocumentApp.openById(wCopyFileId); // コピーしたファイルをGoogleドキュメントとして開く
let wCopyDocBody = wCopyDoc.getBody() // Googleドキュメント内の本文を取得する
, today = dayjs.dayjs()
, wName
, wAbsentDate;
delIdLst.push(wCopyFileId);
wCopyDocBody = wCopyDocBody.replaceText(`{{date}}`, today.format('YYYY年MM月DD日'));
itemResponses.forEach(function(itemResponse){
switch (itemResponse.getItem().getTitle()) {
case '氏名を選択してください。':
wName = itemResponse.getResponse();
wCopyDocBody = wCopyDocBody.replaceText(`{{name}}`, wName);
break;
case '欠席日を入力してください。':
dateF = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
break;
case '連日にまたがって欠席する場合は、欠席期間の終了日を入力してください。': // 欠席の場合のみ対応
if ( itemResponse.getResponse()!='' ) {
dateT = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
} else {
dateT = dateF;
}
wAbsentDate = dateF;
wCopyDocBody = wCopyDocBody.replaceText(`{{applydatefrom}}`, wAbsentDate);
wCopyDocBody = wCopyDocBody.replaceText(`{{applydateto}}`, dateT);
break;
case '届出理由を選択してください。':
wCopyDocBody = wCopyDocBody.replaceText(`{{reason}}`, itemResponse.getResponse());
break;
case '欠席理由のエビデンスを必要に応じてアップロードしてください。':
// 画像挿入位置を把握
let insertImageIdx;
wCopyDocBody.getParagraphs().some(function(para, pIdx){
if (para.getText().includes(`{{evidence}}`)) {
insertImageIdx = pIdx+1;
wCopyDocBody.replaceText(`{{evidence}}`, '');
return;
}
});
itemResponse.getResponse().forEach(function(item) {
delIdLst.push(item);
// 撮影日時を印字
let shootingTxt = getShootingDate(item);
if (shootingTxt) {
wCopyDocBody.insertParagraph(insertImageIdx, shootingTxt);
insertImageIdx++;
}
// 画像を縮小:150px程度としたうえで配置
let convImage = ImgApp.doResize(item, 150);
wCopyDocBody.insertImage(insertImageIdx, convImage.blob).setWidth(150);
insertImageIdx++;
});
break;
default:
break;
}
});
wCopyDoc.saveAndClose();
// ファイル名を変更する
let fileName = `欠席届_${wName}_${today.format('YYYYMMDD')}`;
wCopyFile.setName(fileName);
// コピーしたファイルIDとファイル名、メール用の件名を返却する(あとでこのIDをもとにDOCXに変換するため)
return [wCopyFileId, fileName, `【自動送信メール】欠席届の送信_${wName}_${wAbsentDate}`];
}
function getShootingDate(id) {
// Drive APIを用いて、Exifデータを取得する
let metaData = DriveV2.Files.get(id).imageMediaMetadata;
if (metaData) {
return metaData.date;
} else {
return null;
}
}
function createDocx(docId, fileName) {
// Word変換するためのベースURLを作成する
let wUrl = `https://docs.google.com/document/d/${docId}/export?format=docx`;
// headersにアクセストークンを格納する
let wOtions = {
headers: {
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
}
};
// Word(*.docx)を作成する
let wBlob = UrlFetchApp.fetch(wUrl, wOtions).getBlob().setName(fileName + '.docx');
// Wordを指定したフォルダに保存する
return DOCX_OUTDIR.createFile(wBlob).getId();
}
function sendEmailEx(_recipient, _subject, _body, _option) {
// 引数の内容でメールを下書き保存する
const mailDraft = GmailApp.createDraft(_recipient, _subject, _body, _option);
// 下書き保存したメールIDから下書きを取得し、メール送信を依頼する
GmailApp.getDraft(mailDraft.getId()).send();
}
1つずつ解説していくよ!
こちらの記事から派生した内容なので、被ってる部分の説明は省略してます!上記記事も併せてお読みください!
【STEP1】ライブラリを追加する
ライブラリは、「Days.js」と「ImgApp」の2つを追加する必要があるよ!
Days.jsライブラリを追加する
ImgAppライブラリを活用して、画像データを圧縮する
このライブラリはGASが苦手とする画像編集を補完するライブラリです
主に、画像のサイズ取得やリサイズ、トリミング等を行うことができます
「Days.jsライブラリ」と同じ要領で、ImgAppをライブラリに追加してみてね!
【STEP2】GASエディタの「サービスを追加」からDrive API を追加する
不正防止の観点から、確実に当日の写真が添付されたかを確認したいので、写真の撮影日時(最終更新日)をドキュメントへ出力したい。
お問い合わせ内容の要約
写真の撮影日時を取得するためには、いわゆる画像のExif情報を取得する必要があります
GASの通常の方式でファイルを取得した場合、DriveApp.getFileById(item)
はExif情報を取得することができません
そのため、「Drive API 」をサービスを追加したうえで、Drive API経由でファイルにアクセスしましょう!
画像のExif情報を取得するために「v2」にする必要がありますが、デフォルトでは、「v3」になっています
「appsscript.jsonマニュフェストファイルをエディタで表示する」にチェック
{
"userSymbol": "DriveV2",
"version": "v2",
"serviceId": "drive"
},
上記のように「version」を「v2」に変更しましょう!
これで、画像に撮影日時の情報が存在する場合、情報を読み取ることができるようになりました
【STEP3】Googleフォームのフォーム項目をGASで取得する
作成したGoogleフォームの「︙」をクリックして「〈〉スクリプトエディタ」から、コンテナバインド型でエディタを開こう!
function gaslog_formSubmit(e) {
let itemResponses;
// フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
if (e !== undefined) {
itemResponses = e.response.getItemResponses();
} else {
const wFormRes = FormApp.getActiveForm().getResponses();
itemResponses = wFormRes[wFormRes.length-1].getItemResponses();
}
console.log(itemResponses);
}
18:50:29 お知らせ 実行開始
18:50:31 情報 [ { toString: [Function],
getItem: [Function],
setFeedback: [Function],
setScore: [Function],
getScore: [Function],
getFeedback: [Function],
getResponse: [Function] },
…
{ toString: [Function],
getItem: [Function],
setFeedback: [Function],
setScore: [Function],
getScore: [Function],
getFeedback: [Function],
getResponse: [Function] } ]
18:50:30 お知らせ 実行完了
オブジェクトがしっかり取得できていることが分かりましたね!
【STEP3】の補足説明
補足説明が不要な方は【STEP4】までジャンプしてください!
if (e !== undefined) {
itemResponses = e.response.getItemResponses();
}
もし 、イベントオブジェクトe
が undefined
でない場合、イベントオブジェクトから回答情報を取得します
e.response
はイベントオブジェクト内のフォームの回答に関するプロパティであり、getItemResponses()
メソッドは回答に含まれる個々の質問と回答のペアを含むオブジェクトの配列を返します
else {
const wFormRes = FormApp.getActiveForm().getResponses();
itemResponses = wFormRes[wFormRes.length-1].getItemResponses();
}
e
が undefined
である場合、このブロックが実行されます
つまり、直接フォームの回答を取得する必要があります
const wFormRes = FormApp.getActiveForm().getResponses();
フォームの全ての回答を取得し、それを wFormRes
という変数に格納しています
itemResponses = wFormRes[wFormRes.length-1].getItemResponses();
wFormRes
配列の最後の要素(最新の回答)を取得し、その回答に含まれる質問と回答のペアを含むオブジェクトの配列を itemResponses
に代入しています
この条件分岐を使用することで、送信イベントが発生した場合と、直接回答を取得する場合の2つのケースに対応できます!
イベントオブジェクトが存在する場合は、それから回答情報を取得し、存在しない場合はフォームの全回答から最新の回答を取得しています
【STEP4】Googleフォームの回答内容を取得し、Googleドキュメントを書き換える
この部分は、フォームの回答を取得し、Googleドキュメント本文を回答内容に書き換えしています!
// 欠席届テンプレートファイル
const DOC_TEMPLATE = DriveApp.getFileById('〇〇〇〇〇〇(自分のドキュメントID)');
// ドキュメント出力先
const DOCX_OUTDIR = DriveApp.getFolderById('〇〇〇〇〇〇(自分のフォルダID)');
function createGDoc(itemResponses) {
// テンプレートファイルをコピーする
const wCopyFile = DOC_TEMPLATE.makeCopy()
, wCopyFileId = wCopyFile.getId()
, wCopyDoc = DocumentApp.openById(wCopyFileId); // コピーしたファイルをGoogleドキュメントとして開く
let wCopyDocBody = wCopyDoc.getBody() // Googleドキュメント内の本文を取得する
, today = dayjs.dayjs()
, wName
, wAbsentDate;
delIdLst.push(wCopyFileId);
wCopyDocBody = wCopyDocBody.replaceText(`{{date}}`, today.format('YYYY年MM月DD日'));
itemResponses.forEach(function(itemResponse){
switch (itemResponse.getItem().getTitle()) {
case '氏名を選択してください。':
wName = itemResponse.getResponse();
wCopyDocBody = wCopyDocBody.replaceText(`{{name}}`, wName);
break;
case '欠席日を入力してください。':
dateF = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
break;
case '連日にまたがって欠席する場合は、欠席期間の終了日を入力してください。': // 欠席の場合のみ対応
if ( itemResponse.getResponse()!='' ) {
dateT = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
} else {
dateT = dateF;
}
wAbsentDate = dateF;
wCopyDocBody = wCopyDocBody.replaceText(`{{applydatefrom}}`, wAbsentDate);
wCopyDocBody = wCopyDocBody.replaceText(`{{applydateto}}`, dateT);
break;
case '届出理由を選択してください。':
wCopyDocBody = wCopyDocBody.replaceText(`{{reason}}`, itemResponse.getResponse());
break;
case '欠席理由のエビデンスを必要に応じてアップロードしてください。':
// 画像挿入位置を把握
let insertImageIdx;
wCopyDocBody.getParagraphs().some(function(para, pIdx){
if (para.getText().includes(`{{evidence}}`)) {
insertImageIdx = pIdx+1;
wCopyDocBody.replaceText(`{{evidence}}`, '');
return;
}
});
itemResponse.getResponse().forEach(function(item) {
delIdLst.push(item);
// 撮影日時を印字
let shootingTxt = getShootingDate(item);
if (shootingTxt) {
wCopyDocBody.insertParagraph(insertImageIdx, shootingTxt);
insertImageIdx++;
}
// 画像を縮小:150px程度としたうえで配置
let convImage = ImgApp.doResize(item, 150);
wCopyDocBody.insertImage(insertImageIdx, convImage.blob).setWidth(150);
insertImageIdx++;
});
break;
default:
break;
}
});
wCopyDoc.saveAndClose();
// ファイル名を変更する
let fileName = `欠席届_${wName}_${today.format('YYYYMMDD')}`;
wCopyFile.setName(fileName);
// コピーしたファイルIDとファイル名、メール用の件名を返却する(あとでこのIDをもとにDOCXに変換するため)
return [wCopyFileId, fileName, `【自動送信メール】欠席届の送信_${wName}_${wAbsentDate}`];
}
ここの部分は、Googleドキュメントであらかじめ作成した「欠席届」をコピーし、回答の情報をテンプレート内の特定の場所に置換します
これにより、「受講者氏名」「理由」「欠席期間」「欠席理由」などが欠席届に反映されます
{{date}}
、{{name}}
等の、「可変文字部」部分をGoogleフォームの回答を反映させることができます
波括弧の部分は「可変文字部」といって、{{}}内を入力内容に書き換える魔法のような存在なんだ!詳しくは、以前の記事で説明しているよ!
是非読んでみてね!
switch文を利用することによって、「〇〇」という質問に対しての回答をGoogleドキュメント本文中の{{可変文字部}}部分に置き換える作業をしているよ!
switch文について詳しく知りたい方は、過去記事で解説しているので、確認してみてください!
【STEP4】の補足説明
補足説明が不要な方は【STEP5】までジャンプしてください!
この部分のコードは、Google ドキュメント内にある特定のテキスト({{evidence}}
)が含まれる段落を見つけて、その次の段落の位置を insertImageIdx
に保存しています
case '欠席理由のエビデンスを必要に応じてアップロードしてください。':
// 画像挿入位置を把握
let insertImageIdx;
wCopyDocBody.getParagraphs().some(function(para, pIdx){
if (para.getText().includes(`{{evidence}}`)) {
insertImageIdx = pIdx+1;
wCopyDocBody.replaceText(`{{evidence}}`, '');
return;
}
.getParagraphs()
メソッドでGoogle ドキュメント内の全ての段落を取得.some()
メソッドにて、配列内の各要素について指定された条件を満たすかどうかを確認
(条件を満たす最初の要素が見つかった時点でループを終了)- ループの中で、各段落のテキストに
{{evidence}}
が含まれているかどうかをチェック - Googleドキュメント本文中に
{{evidence}}
が含まれていれば、その段落のインデックスpIdx
に1を加えた値(次の段落の位置)をinsertImageIdx
に保存し、{{evidence}}
を空文字列に置換える
つまり、この部分のコードは、{{evidence}}
というテキストが含まれる段落の次の段落の位置を insertImageIdx
という変数に保存しています
この処理によって、画像情報に撮影日時が含まれていた場合、撮影日時を{{evidence}}
の次の段落に挿入する準備が整えられます
itemResponse.getResponse().forEach(function(item) {
delIdLst.push(item);
// 撮影日時を印字
let shootingTxt = getShootingDate(item);
if (shootingTxt) {
wCopyDocBody.insertParagraph(insertImageIdx, shootingTxt);
insertImageIdx++;
}
もし、画像情報の中に撮影日時があれば、画像の後ろに撮影日時がテキストで挿入されます
【STEP5】Drive APIを用いて、Exifデータを取得する
「【STEP2】Drive API を追加する」を実行していないとエラーになるので気を付けてくださいね!
function getShootingDate(id) {
// Drive APIを用いて、Exifデータを取得する
let metaData = DriveV2.Files.get(id).imageMediaMetadata;
if (metaData) {
return metaData.date;
} else {
return null;
}
}
上記リファレンスの中段にimageMediaMetadata
に関する記述があり、写真の撮影日時(EXIF DateTime)は、以下のように取得すればよいことが分かります
imageMediaMetadata.time
「Drive API」を利用して、画像のExif情報を取得する際の留意事項について解説してるのでよかったら読んでみてください!
【STEP6】本文を書き換えたGoogleドキュメントをWord形式に変換する
私の過去記事の中では createPdfメソッドを作成し、GoogleドキュメントをPDFに変換しておりました
出張者が修正できるようにした方が融通が利くと考えられるため、ドキュメントのまま送信したい
お問い合わせ内容の要約
Googleドキュメントはあくまでもクラウド上のサービスであるため、ここではWordに変換する方法を伝授します!
function createDocx(docId, fileName) {
// Word変換するためのベースURLを作成する
let wUrl = `https://docs.google.com/document/d/${docId}/export?format=docx`;
// headersにアクセストークンを格納する
let wOtions = {
headers: {
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
}
};
// Word(*.docx)を作成する
let wBlob = UrlFetchApp.fetch(wUrl, wOtions).getBlob().setName(fileName + '.docx');
// Wordを指定したフォルダに保存する
return DOCX_OUTDIR.createFile(wBlob).getId();
}
特段ポイントとなる箇所はなく、exportするフォーマットをdocxとすればOKです
let wUrl = `https://docs.google.com/document/d/${docId}/export?format=docx`;
format=docx
とするのがポイントだね!
これだけで、Word形式に変換できるから便利だよね!
【STEP7】トリガーを設定する
左側にある時計みたいなマーク「トリガー」をクリックし、以下のように設定しましょう!
これで、フォーム回答時に、回答者宛に欠席届がメールで届くようになりました!ここまで、お疲れさまでした!
完成!
これで画像情報を読み込んだ上で、Wordファイルを回答者にメールを自動送信できるようになりました!
// 欠席届テンプレートファイル
const DOC_TEMPLATE = DriveApp.getFileById('〇〇〇〇〇〇(自分のドキュメントID)');
// ドキュメント出力先
const DOCX_OUTDIR = DriveApp.getFolderById('〇〇〇〇〇〇(自分のフォルダID)');
// 最後の削除用リスト
let delIdLst = new Array();
function gaslog_formSubmit(e) {
let itemResponses;
// フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
if (e !== undefined) {
itemResponses = e.response.getItemResponses();
} else {
const wFormRes = FormApp.getActiveForm().getResponses();
itemResponses = wFormRes[wFormRes.length-1].getItemResponses();
}
// 回答をもとに欠席届を作成する
let wFileRtn = createGDoc(itemResponses);
// DOCX変換してファイルIDを取得する
let wPdfId = createDocx(wFileRtn[0], wFileRtn[1]);
delIdLst.push(wFileRtn[0]);
delIdLst.push(wPdfId);
// 今回はDOCXファイルを添付してメールを送信する
sendEmailEx(
e !== undefined ? e.response.getRespondentEmail() : '(eが未定義の場合に送信されるメールアドレス)'
, wFileRtn[2]
, `受講生より欠席届が送信されました。`
, {attachments: DriveApp.getFileById(wPdfId).getBlob()}
);
// 各種保存したファイルを削除する
delIdLst.forEach(function(delId){
DriveApp.getFileById(delId).setTrashed(true);
});
}
function createGDoc(itemResponses) {
// テンプレートファイルをコピーする
const wCopyFile = DOC_TEMPLATE.makeCopy()
, wCopyFileId = wCopyFile.getId()
, wCopyDoc = DocumentApp.openById(wCopyFileId); // コピーしたファイルをGoogleドキュメントとして開く
let wCopyDocBody = wCopyDoc.getBody() // Googleドキュメント内の本文を取得する
, today = dayjs.dayjs()
, wName
, wAbsentDate;
delIdLst.push(wCopyFileId);
wCopyDocBody = wCopyDocBody.replaceText(`{{date}}`, today.format('YYYY年MM月DD日'));
itemResponses.forEach(function(itemResponse){
switch (itemResponse.getItem().getTitle()) {
case '氏名を選択してください。':
wName = itemResponse.getResponse();
wCopyDocBody = wCopyDocBody.replaceText(`{{name}}`, wName);
break;
case '欠席日を入力してください。':
dateF = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
break;
case '連日にまたがって欠席する場合は、欠席期間の終了日を入力してください。': // 欠席の場合のみ対応
if ( itemResponse.getResponse()!='' ) {
dateT = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
} else {
dateT = dateF;
}
wAbsentDate = dateF;
wCopyDocBody = wCopyDocBody.replaceText(`{{applydatefrom}}`, wAbsentDate);
wCopyDocBody = wCopyDocBody.replaceText(`{{applydateto}}`, dateT);
break;
case '届出理由を選択してください。':
wCopyDocBody = wCopyDocBody.replaceText(`{{reason}}`, itemResponse.getResponse());
break;
case '欠席理由のエビデンスを必要に応じてアップロードしてください。':
// 画像挿入位置を把握
let insertImageIdx;
wCopyDocBody.getParagraphs().some(function(para, pIdx){
if (para.getText().includes(`{{evidence}}`)) {
insertImageIdx = pIdx+1;
wCopyDocBody.replaceText(`{{evidence}}`, '');
return;
}
});
itemResponse.getResponse().forEach(function(item) {
delIdLst.push(item);
// 撮影日時を印字
let shootingTxt = getShootingDate(item);
if (shootingTxt) {
wCopyDocBody.insertParagraph(insertImageIdx, shootingTxt);
insertImageIdx++;
}
// 画像を縮小:150px程度としたうえで配置
let convImage = ImgApp.doResize(item, 150);
wCopyDocBody.insertImage(insertImageIdx, convImage.blob).setWidth(150);
insertImageIdx++;
});
break;
default:
break;
}
});
wCopyDoc.saveAndClose();
// ファイル名を変更する
let fileName = `欠席届_${wName}_${today.format('YYYYMMDD')}`;
wCopyFile.setName(fileName);
// コピーしたファイルIDとファイル名、メール用の件名を返却する(あとでこのIDをもとにDOCXに変換するため)
return [wCopyFileId, fileName, `【自動送信メール】欠席届の送信_${wName}_${wAbsentDate}`];
}
function getShootingDate(id) {
// Drive APIを用いて、Exifデータを取得する
let metaData = DriveV2.Files.get(id).imageMediaMetadata;
if (metaData) {
return metaData.date;
} else {
return null;
}
}
function createDocx(docId, fileName) {
// Word変換するためのベースURLを作成する
let wUrl = `https://docs.google.com/document/d/${docId}/export?format=docx`;
// headersにアクセストークンを格納する
let wOtions = {
headers: {
'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
}
};
// Word(*.docx)を作成する
let wBlob = UrlFetchApp.fetch(wUrl, wOtions).getBlob().setName(fileName + '.docx');
// Wordを指定したフォルダに保存する
return DOCX_OUTDIR.createFile(wBlob).getId();
}
function sendEmailEx(_recipient, _subject, _body, _option) {
// 引数の内容でメールを下書き保存する
const mailDraft = GmailApp.createDraft(_recipient, _subject, _body, _option);
// 下書き保存したメールIDから下書きを取得し、メール送信を依頼する
GmailApp.getDraft(mailDraft.getId()).send();
}
この関数を「▷実行」すると、Googleフォームで回答したメールアドレス宛に、Word文書が添付されたメールが送られてきます
ちゃんとWordファイルとして添付されてますね!
まとめ
今回は「画像を含むGoogleフォームの回答をGASで取得し、Googleドキュメントに反映後、Word文書にしてメールを自動送信する」というテーマで解説を行いました
GASは非常に便利ですが、今回の記事(GASで画像のExif情報を扱う)のように、使い方にはクセがあることがあります
GASで「Drive API」を利用する場合は仕様に留意してください
ぜひ、皆さんも実業務での活用に取り組んでみてください
引き続き、GASを楽しんでいきましょう!!
X(旧:Twieer)にて、ブログの更新やQiita記事の更新、GAS情報をお届けしますので、是非フォローしてください!
おかげさまで今年5月に起業しました!
GASやGoogleサービス、プログラミング全般のご相談承ります!
YouTubeでGoogleサービスをより
快適に使う方法をご紹介しています!
見て頂けたらうれしいです
コメント