【GAS】自動受付&仕分け&台帳作成システム(6)~Gメールから投稿作品を抽出してGドライブに保存する~
いつ来るか分からない、誰が送ってくるか分からないものについて、投稿先を掲示して何らかの提出物を受け付けるシステムのご紹介です。
受け付けの入り口として投稿フォームを作成し、
→フォームからエントリー
→受け付け番号を自動生成し、申込者に返信
→Googleドライブ上に受け付け番号毎のフォルダを作成
→上記フォルダへのリンクをリスト上に記載
ここまでをご紹介しました。最終記事は以下になります。
今回の記事は上記の続きで、投稿者が作品を添付して送ったメールから、投稿作品を抽出して保存する部分の解説です。
Gメールの受信メールから、受け付け番号を含んだ件名のメールを抽出する
前準備
今回のスクリプトは、前の記事の「サブフォルダ」のGASと同じプロジェクト内に、新しいスクリプトファイルを追加作成して記述するものとします。(別のプロジェクトにするより管理が楽と思います)
スクリプトファイル名は、「作品の抽出と保存」としました。
この中に関数を作成します。関数名は何でもいいのですが、fetchFile( )としました。(fetch(フェッチ)とは、「抜き出す」の意味です)
ここにコードを書いていきます。
function fetchFile(){
・・・
内容を記述
・・・
}
該当行の受け付け番号取得
では早速コードを記述しましょう。
Gメールには、投稿作品以外にもユーザ宛ての様々なメールが届いている筈ですので、まず、投稿対象となるメール(スレッド)だけを検索によって抽出する必要があります。
対象となるメールの抽出は、今回は「件名」覧に「受け付け番号」が含まれたテキストがある事を利用します。(これを利用するため、投稿者には、件名を修正しないことを周知する必要があります)
まず、受け付け台帳であるスプレッドシートから以下の様なコードで受け付け番号を引用します。
//アプリケーションを取得|スプレッドシートのIDは各自のものを’★~★’部に記入
var myApp = SpreadsheetApp.openById('★スプレッドシートID★');
//対象シートをシートの名前を指定して取得
var シート = myApp.getSheetByName('フォームの回答 1');
//フォーム回答シートの2行目以降をループする
for(var i行=2; i行 < 最終行+1; i行++){
//シート該当行で、「専用サプフォルダ」「専用フォルダURL」覧が空白でないなら実施する
if((!シート.getRange(i行目,8列目).isBlank())&&(!シート.getRange(iRow,9列目).isBlank())){
//受付番号を取得する
var 受付番号 = mySheet.getRange(i行目,6列目).getValue();
上記のコードを走らせると、台帳シートの各行を逐次ループして、下図F列目の「C00005」 などの受け付け番号を順次取得できます。(下のシートで黄色くなっている部分です)
この時、投稿先フォルダがまだ未作成(「専用サプフォルダ」の列に「作成済」のフラグがない)の行については処理をスキップするよう、if()節による条件指定を入れています。(「!」はNOT条件、「&&」はAND条件、.isBlank()は空白かどうかを見る関数です)
これにより、投稿先フォルダがまだ無いのに抽出してしまう、というったケースが無い様にしています。
(スキップした行については、次のタイミングでのトリガーが発動した時には対応できるはずです)
保存先のフォルダを取得
次に、添付ファイルを保存するフォルダのURLを同じ様なコードで取得します。(URLは、受け付け番号の3つ右のi列のセルにあります)
コードとしては以下の様になります。
//保存フォルダを取得する
var フォルダID = シート.getRange(i行目,9列目).getValue().substring(39);
const 保存フォルダ = DriveApp.getFolderById(フォルダID);
添付ファイルを抽出する
件名からメールのスレッド群を抽出
さて、フォームの回答シートから受け付け番号と保存先フォルダのURLを取得したら、件名にこの文字が含まれているスレッドをGメールから抽出します。
抽出は、 Gメールを扱う「GmailApp」オブジェクトにある関数、search()を使う事で簡単にできます。
//検索条件を設定する |表題に受付番号を含む
const 検索条件 = 'subject:' + 受け付け番号;
//メールを検索条件で検索する |念のため最大値を30としておく
const 「スレッド群」 = GmailApp.search(検索条件, 0, 30);
上記の関数の引数に入れる検索文字列を'subject:[検索文字]'と入れることで、件名を対象とする検索が可能です。
この関数の結果は、「スレッド群」オブジェクトとして返されます。
スレッド群からメッセージ単体を抽出
検索によって抽出したスレッド群と、添付ファイルの保存先を用意したら、次はいよいよ添付ファイルの抽出です。
コードは以下の様になります。
//検索結果(2次元配列)からメッセージを抽出する
for(const thread of スレッド群){
for(const message of thread){
//スターがないメッセージのみ処理
if(!message.isStarred()){
//メッセージから添付ファイルを抽出する
const attachments = message.getAttachments();
//処理済みのメッセージにスターをつける
message.star();
for(const attachment of attachments){
myFolder.createFile(attachment);
}
}
短いコードですが、少し解説します。
単体のメッセージの取得
単体のメッセージは以下の様にスレッド群からみて、2階層下のメンバーとなっています。これに辿り着くために、以下の様に二重のforループを回して取得しています。
for(const thread of スレッド群){
for(const message of thread){
・・・メッセージの処理・・・
}
}
添付ファイル群の取得
添付ファイルは、個々のメッセージから、getAttachments( ) 関数により抽出します。(正確には、添付ファイル群です)
//メッセージから添付ファイルを抽出する
const 添付ファイル群 = message.getAttachments();
二重抽出の防止
また、抽出処理の済んだメッセージは、再度トリガーが発動した場合に再び抽出処理をしない様に、個々のメッセージに star( ) 関数により「スター」マークを付けておきます。
//処理済みのメッセージにスターをつける
message.star();
スターマークというのは、Gメールで見られる、星の形をしたフラグの事です。以下にメッセージ例を挙げます。(1番左に黄色い星型があります)
そしてスターマークが一旦つけられたメッセージからは、今後添付ファイルの抽出をしない様に、ここまでの処理全体を、以下のif文でくくっておきます。(条件は !message.isStarred() となっており、「スターがない」という意味になっています)
//メッセージにスターマークが無い場合のみ処理する
if(!message.isStarred()){
//メッセージから添付ファイルを抽出する
const 添付ファイル群 = message.getAttachments();
//処理済みのメッセージにスターをつける
message.star();
}
添付ファイル群から個々のファイルを抽出
抽出した添付ファイル群は、for構文を使って個々のファイルに分解し、前述で指定したフォルダに 保存フォルダ.createFile([添付ファイル])文を用いて保存します。
for(const attachment of 添付ファイル群){
保存フォルダ.createFile(attachment);
}
ようやく保存できた
以上の処理により、Gメールから対象メッセージを検索し、添付ファイルを抽出して保存するまでができます。
以上の処理を含んだ関数の実行
最後に、この関数を実行するための、時間管理型のトリガを設定しておきます。
GASのエディタから時計の様なアイコンをクリックすると、トリガー設定画面になりますので、フォルダ作成処理の場合と同様に時間ベースで設定します。
以上で一連の処理が終わりました。
次回は、ここまでの記事で紹介した処理の実際のコードをご説明します。
付記
noteの細切れの記事を、一つにまとめた形にしたいと思い、現在、一番最初のGASについて、KINDLE書籍にしています。
この記事について説明しました。
目次などは、以下の記事に書いてありますので、ご興味を持たれましたらどうぞ。