添付ファイル暗号化、パスワード別送を…駆逐してやる! version2.0
少し前にこんな記事を書きました。
メールの添付ファイルの扱いは皆が苦労させられる所だと思うので、少しでも解決に繋がればという思いで書きました。
今回の記事は前回からのアップデートになります。
アップデート内容
▶︎共有の解除を送信者自身で操作可能に
▶︎共有から○日経過すると自動で共有を解除
全体のながれはこうなりました。
共有の解除を送信者自身で操作可能に
解除方法ですが、
ファイルを添付したメールの送信後、共有解除用のリンクが記載されたメールが、送信元へ届きます。
何らかの理由で共有を取り消したい場合は、送信元がこのメールに記載のリンクをクリックするだけです。
共有から○日経過すると自動で共有を解除
リンク共有したファイルがどんどん増えていくと、それがリスクになってしまうので、自動的に共有が解除されるようにしました。
実装の変更箇所
全体のプロセスは下記で、共有解除のメールが増えたくらいで変わってません。今回の説明はGAS以外は同じなので省略します🙏
上のフローで使う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くださーい