見出し画像

添付ファイル暗号化、パスワード別送を…駆逐してやる! version2.0

少し前にこんな記事を書きました。

メールの添付ファイルの扱いは皆が苦労させられる所だと思うので、少しでも解決に繋がればという思いで書きました。

今回の記事は前回からのアップデートになります。

アップデート内容

▶︎共有の解除を送信者自身で操作可能に
▶︎共有から○日経過すると自動で共有を解除

全体のながれはこうなりました。

画像3

共有の解除を送信者自身で操作可能に

解除方法ですが、
ファイルを添付したメールの送信後、共有解除用のリンクが記載されたメールが、送信元へ届きます。

何らかの理由で共有を取り消したい場合は、送信元がこのメールに記載のリンクをクリックするだけです。

画像3

共有から○日経過すると自動で共有を解除

リンク共有したファイルがどんどん増えていくと、それがリスクになってしまうので、自動的に共有が解除されるようにしました。

実装の変更箇所

全体のプロセスは下記で、共有解除のメールが増えたくらいで変わってません。今回の説明はGAS以外は同じなので省略します🙏

画像3

上のフローで使うGASは下記です。
(あまり精査する気力がなかったので色々雑かもですがご了承…)

あと、今回のアップデートのタイミングでGmail APIとDrive APIへ書き換えました。送信数などの制限が多少緩和されるはず…きっと!

メールの添付ファイルをドライブへ格納してリンクを送信先に送るコード

//添付ファイルを保存する共有フォルダのID
const FOLDER_ID = 'XXXXXXXXXXXXXXXXXXXX';

//送信専用アドレスが受信したメールのうち、ファイル送信するメールの検索条件
const SEARCH_TERM = 'has:attachment label:inbox';

//DLPで転送するメールに設定している X-send_mail_files_key
const key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';

//doGetで公開するGASのURL
const app_url = "https://script.google.com/macros/s/XXXXXXXXXXXXX/exec";

function send_mail_files(){
   let messages
   try{
   console.log("メールを検索します。");
   messages = Gmail.Users.Messages.list('me',{"q":SEARCH_TERM});
   }catch(err){
   console.log("メール検索でエラーが発生しました : " + err );
   return
   }
   //該当するメッセージが1件でもあったら実行
   if(messages.resultSizeEstimate){
       //メッセージの処理
       messages.messages.map(function(message){
       let data_message
       try{
           console.log("メールを取得します。");
           data_message = Gmail.Users.Messages.get('me',message.id);
       }catch(err){
           console.log("メールの取得でエラーが発生しました : " + err);        
       return
       }
       const headers = data_message.payload.headers ;
       let info_header = {};
       //ヘッダーから欲しい情報だけ取得する
       headers.map(function(header){
       if(header.name == "From"){info_header.from = header.value}
       if(header.name == "To"){info_header.to = header.value}
       if(header.name == "Subject"){info_header.subject = header.value}
       if(header.name == "Cc"){info_header.cc = header.value}
       if(header.name == "Bcc"){info_header.bcc = header.value}
       if(header.name == "X-send_mail_files_key"){info_header.key = header.value}
       })
       let url_files = [];
       let del_item_list = [];
       //ヘッダーのkeyを見てDLPで転送された、添付ファイルを送信すべきメールかを確認する
       if(info_header.key == key){
           //メールの添付ファイル取得
           data_message.payload.parts.map(function(part){
               if(part.partId!=0){
                   const id_attachment = part.body.attachmentId;
                   const mimeType_attachment = part.mimeType;
                   const filename_attachment = part.filename;
                   let file
                   try{
                       console.log("添付ファイルを取得します。");
                       file = Gmail.Users.Messages.Attachments.get('me', message.id, id_attachment);
                   }catch(err){
                       console.log("添付ファイルの取得でエラーが発生しました : " + err);            
                       return
                   }
                   //メール添付ファイルをドライブへアップロード
                   const file_str = file.data.toString();
                   const blob = Utilities.newBlob(file.data,mimeType_attachment,filename_attachment);
                   const meta_file = {
                       "title": filename_attachment,
                       "mimeType": mimeType_attachment,
                       "parents": [{"id": FOLDER_ID}]
                   };
                   const op = {
                       "supportsAllDrives":true
                   }
                   let file_drive
                   try{
                       console.log("共有ドライブへアップロードします");
                       file_drive = Drive.Files.insert(meta_file,blob,op);
                   }catch(err){
                       console.log("共有ドライブへアップロードでエラーが発生しました : " + err);
                   return
                   }
                   const meta_drive = {
                       "role": 'reader',
                       "type": 'anyone',
                   }
                   //ドライブへアップロードしたファイルのリンクを取得
                   url_files.push(file_drive.alternateLink);
                   //ドライブへアップロードしたファイルのIDを取得
                   del_item_list.push(file_drive.id);
                   //ドライブへアップロードしたファイルをリンク共有に変更
                   let log_permission
                   try{
                       console.log("ファイルをリンクで共有します");
                       log_permission = Drive.Permissions.insert(meta_drive,file_drive.id,op);
                   }catch(err){
                       console.log("ファイルをリンクで共有でエラーが発生しました : " + err);
                       return
                   }
               }
           })
       }else{
           console.log("該当メールはなかったよ");
           return
       }
       //送信先へのメール作成
       let url_raw = "";
       url_files.map(function(url){
       url_raw = url_raw + url + "\n";
       })
       let mimeData_to = [
           "From: =?utf-8?B?" + Utilities.base64Encode("ファイル送信専用アドレス",Utilities.Charset.UTF_8)+"?=<system-send_mail_files@hogehoge.hoge>",
           "To: " + info_header.to,
           "Subject: =?utf-8?B?" + Utilities.base64Encode(info_header.subject,Utilities.Charset.UTF_8) + "?=",
           "MIME-Version: 1.0",
           "Content-Type: text/plain; charset=UTF-8",
           "Content-Transfer-Encoding: 7bit",
           "",
           "<<< 当社のEメールポリシーにより、ファイル送信専用アドレスからメールを送信させていただきます。送信専用アドレスの為、ご返信いただく事ができませんのでご了承ください。 >>>",
           "",
           "送信者 : " + info_header.from,
           "",
           "下記ファイルとなります。(リンクの有効期限は1週間)",
           url_raw
       ].join("\n").trim();
       let raw_to = Utilities.base64Encode(mimeData_to,Utilities.Charset.UTF_8).replace(/\+/g, '-').replace(/\//g, '_');
       //送信先へ共有リンクが記載されたメール送信
       try{
           Gmail.Users.Messages.send({"raw":raw_to}, 'me');
           //Gmail.Users.Messages.trash('me', message.id);
           console.log("メール送信できました!");
       }catch(err){
           console.log("メール送信でエラーが発生しました : " + err);
       }finally{
           //特にないか・・・
       }
       //送信元へのメール作成
       let sender = info_header.from;
       let param = {
           "item_id":del_item_list,
           "sender":sender
       }
       let en_param = Utilities.base64Encode(JSON.stringify(param));
       const link_del = app_url + "?f=" + en_param;
       let mimeData_from = [
           "From: =?utf-8?B?" + Utilities.base64Encode("ファイル送信専用アドレス",Utilities.Charset.UTF_8)+"?=<system-send_mail_files@hogehoge.hoge>",
           "To: " + info_header.from,
           "Subject: =?utf-8?B?" + Utilities.base64Encode(info_header.subject,Utilities.Charset.UTF_8) + "?=",
           "MIME-Version: 1.0",
           "Content-Type: text/plain; charset=UTF-8",
           "Content-Transfer-Encoding: 7bit",
           "",
           "<<< 添付ファイルのリンクを送信致しました。共有を解除する場合は下のリンクをクリックしてください >>>",
           "",
           "共有解除リンク↓",
           link_del,
           ""
       ].join("\n").trim();
       let raw_from = Utilities.base64Encode(mimeData_from,Utilities.Charset.UTF_8).replace(/\+/g, '-').replace(/\//g, '_');
       //送信元へ共有の解除リンクが記載されたメールを送信
       try{
           Gmail.Users.Messages.send({"raw":raw_from}, 'me');
           //Gmail.Users.Messages.trash('me', message.id);
           console.log("メール送信できました!");
       }catch(err){
           console.log("メール送信でエラーが発生しました : " + err);
       }finally{
           //特にないか・・・
       }
   })
   }else{
       console.log("メールはなかったよ");
   }  
}

解除リンクをクリックした後の、共有ドライブを操作するコード

function doGet(e) {
   //解除リンクからパラメータ取得
   const en_param = e.parameter.f;
   const dec_param = JSON.parse(Utilities.newBlob(Utilities.base64Decode(en_param)).getDataAsString());
   let list_del_files = [];
   list_del_files = dec_param.item_id;
   
   //ドライブのファイルを削除する
   list_del_files.map(function(id_del_file){
     //削除が失敗するかもなので、エラー処理入れる
     try{
       Drive.Files.trash(id_del_file, {"supportsAllDrives":true});
       console.log("deleted : " + id_del_file );
     }catch(err){
       console.log("ERR : "+ err );
       console.log( "file_id : " + id_del_file );
     }finally{
       
     }
   })
   let html = "ファイルのリンクを解除しました";
   return HtmlService.createHtmlOutput(html);
}

共有したファイルを自動削除するコード

これは定期実行のトリガーを設定してください。(サンプルは7日経過したら削除するようになってます)

function files_delete(){
   //ファイルを保存している共有ドライブのID
   const drive_id = 'XXXXXXXXXXXXXXXX';
   const date = new Date();
   //削除する日付を取得
   var old_date = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7);
   old_date = Utilities.formatDate( old_date, 'JST', 'yyyy-MM-dd');
   console.log("old_date:"+old_date);
   //削除対象のファイルを取得
   const old_files = Drive.Files.list({
       //検索対象をマイドライブにするかチームドライブにするかを渡すのに必要
       "corpora":"drive",
       "includeItemsFromAllDrives":true,
       "supportsAllDrives":true,
       "driveId":drive_id,
       "q":"trashed=false and modifiedDate < '"+old_date+"'",
   });

   //該当するファイルがある場合、削除する
   if(old_files.items.length){
       old_files.items.map(function(item){
           //削除が失敗するかもなので、エラー処理入れる
           try{
           Drive.Files.trash(item.id, {"supportsAllDrives":true});
           console.log("deleted : " + item.id );
           }catch(err){
           console.log("ERR : "+ err );
           console.log( "file_id : " + item.id );
           }finally{
               //特にないかな…  
           }
       })
   }else{
       //該当するファイルがない場合
       console.log("削除するファイルなかったよ");
   }
}


さいごに

ファイルの共有はGoogleドライブとかで済ませたい派ですw
とはいえ、どうしてもメール送信必要なケースもあるので、活用してください!

答えられるところは答えますので不明点、誤りあればDMくださーい

いいなと思ったら応援しよう!