3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

身の回りの困りごとを楽しく解決! by Works Human IntelligenceAdvent Calendar 2024

Day 2

Gmailの整理を効率化!Google Apps Scriptでラベル管理と古いメールの削除を自動化する方法

Last updated at Posted at 2024-12-01

※この記事は「身の回りの困りごとを楽しく解決! by Works Human Intelligence Advent Calendar 2024」の参加記事です。

はじめに

背景

メールって、気付くと大量に溜まってしまって、Google Driveの容量を圧迫してしまったりしませんか?
不要なメールは減らしたいとは思いつつも、メールマガジンやアラートメール、ワンタイムパスワードのメールなど、結構な数のメールが日々届くため、毎日整理するのは大変です。
また、通知系のメールなどは、届かないのも困ってしまうので、これまではある程度溜まったら検索して一括削除、といったことをやっていました。

今回、もっと楽に整理をしたいと思い、Google Apps Script(GAS)を使って古いメールの削除を自動化する仕組みを構築しました。
この記事では、その仕組の内容とスクリプトを紹介します。

作成した仕組の特徴

とはいえ、GASを用いたメール整理自動化は、比較的ネット上にも情報が多い内容です。
自分が作成した仕組みは、もうちょっと応用的な、以下の特徴を持った仕組みです。

  • 指定したメールアドレスから届いたメールのみを対象とする
    • メールマガジンや通知メールなど、特定のメールを対象にできるようにしました
  • 対象のメールアドレス毎に保持期間を指定できる
    • このメールマガジンは2週間、この通知メールは1年など、保持期間を指定できます。
  • Gmailアプリ上だけで完結できる
    • 対象のメールアドレスや保持期間をSpreadsheetで管理しますが、Spreadsheetを開かずにGmailアプリ上の操作だけで対象の追加、保持期間の変更などの操作を実施できます

特に3つ目が重要で、メール整理のためにSpreadsheetにメールアドレスを転記して・・・といった作業はやりたくありませんでした。
Gmailアプリ上で、しかもスマホからも操作できるようにしたため、整理がとても楽に行えるようになりました。

作成した仕組の使い方

仕組の使い方はこうです。
すべてGmailアプリ上で操作を行います。

  1. 一定期間後に削除したいメールを選んで「Cleaner-xx(xxは期間指定)」というラベルを付与する
  2. 一定時間ごとにスクリプトが動作し、「Cleaner-xx」のラベルが付いたものを取得、Spreadsheetに記録して「AutoClean-xx」というラベルに付け替える

基本的にはこれだけです。

画像のように、「Cleaner-14d」とラベルをつけると、14日間保持する設定になります(「Cleaner」ラベルは「Cleaner-1m」と同等です)。
スクリプトが動作したあとは、2枚目のようにAutoClean-xxにラベルが置き換わります。
また、このAutoClean-xxラベルは、対象のメールから届いたもの全てにラベルが付くため、「このメールは削除対象にしていたっけ?」といったことを調べる必要はありません。

ラベルを付けたものは、以下のようにSpreadsheetに転記されていきます。

image.png

期間の指定はラベルの末尾xxで行います。
dは日数、mは月数、yは年数です。
Gmailの検索仕様のolder_thanの仕様に準ずるため、詳しくは以下のページを御覧ください。

期間指定は自由に増やすことが可能なので、「10日保持するようにしたい」と思ったら、「Cleaner-10d」というラベルを新たに作って付与するだけです。
Spreadsheetを開いて設定する、といったことはしなくて良いのです。
唯一、対象を除外する場合のみ、Spreadsheetを開いて対象行を削除してやる必要があります。
(そこもラベルで指定できるようにすることも可能ですが、頻繁にある作業ではないのでやめました)

コードの概要

機能説明

  • main関数:
    日中定期的に起動し、ラベル「Cleaner-xx」を元にメールを整理し、管理情報をスプレッドシートに記録します。
  • deleteThreads関数:
    毎日0時頃に起動し、指定期間以上前のメールを検索してゴミ箱に移動します。

それぞれGASのトリガーを設定し、main関数の方は10分おきに実行、deleteThereads関数の方は1日おきに0時-1時に実行するようにしています。


コード

実際のコードは以下のとおりです。

// Compiled using gmail-cleaner 1.0.0 (TypeScript 4.9.5)
"use strict";
/**
 * Gmail Cleaner
 * 1. ラベル「Cleaner-xx」が付与されたメールアドレスを取得
 * 2. メールアドレスをスプレッドシートに記録
 * 3. 指定期間以上前のメールをゴミ箱に移動
 */
function main() {
    const sheet = SpreadsheetApp.getActiveSheet();

    // 削除対象のラベルを取得
    const labels = GmailApp.getUserLabels();
    const cleanerLabels = labels.filter((l) => l.getName().toLowerCase().includes("cleaner"));
    
    // ラベル「Cleaner-xx」が付与されたメールアドレスを取得
    cleanerLabels.forEach((label) => {
        const labelName = label.getName();
        const olderThan = labelName.split("-")[1] || "1m";
    
        // Cleaner-xxから付け替えるためのAutoClean-xxの取得・作成
        const autoCleanLabel = GmailApp.getUserLabelByName("AutoClean-" + olderThan) ||
            GmailApp.createLabel("AutoClean-" + olderThan);
        
        // ラベル「Cleaner-xx」が付与されたメールアドレスを取得
        const cleanerMailAddress = GmailApp.search(`label:${labelName}`);
        
        cleanerMailAddress.forEach((mail) => {
            mail.getMessages().forEach((message) => {
            
                // メールアドレスが記録されていなければスプレッドシートに記録
                const mailAddress = message.getFrom();
                var textFinder = sheet.createTextFinder(mailAddress);
                var cells = textFinder.findAll();
                
                // すでに記録されている場合は、AutoClean-xxを付け替える
                if (cells.length > 0) {
                    const nextAutoCleanLabel = GmailApp.getUserLabelByName("AutoClean-" + olderThan) ||
                        GmailApp.createLabel("AutoClean-" + olderThan);
                    cells.forEach((cell) => {
                        const range = sheet.getRange(cell.getRowIndex(), 2);
                        const prevOlderThan = range.getValue();
                        const prevAutoCleanLabel = GmailApp.getUserLabelByName("AutoClean-" + prevOlderThan) ||
                            GmailApp.createLabel("AutoClean-" + prevOlderThan);
                        range.setValue(olderThan);
                
                        // おなじラベルの場合はスキップ
                        if (prevAutoCleanLabel.getName() === nextAutoCleanLabel.getName()) {
                            return;
                        }
                        
                        // 前のラベルが付与されたスレッドを取得
                        const labelAddThreads = GmailApp.search(`from:(${mailAddress}) label:${prevAutoCleanLabel.getName()} -is:starred`);
                        if (labelAddThreads.length === 0) {
                            return;
                        }
                        
                        // 配列を100件ずつに分割(addToThreadsは1度に100件まで)
                        const chunk = 100;
                        for (let i = 0; i < labelAddThreads.length; i += chunk) {
                            const threads = labelAddThreads.slice(i, i + chunk);
                            // ラベルの付け替え
                            prevAutoCleanLabel.removeFromThreads(threads);
                            nextAutoCleanLabel.addToThreads(threads);
                        }
                    });
                }
                else {
                    sheet.appendRow([mailAddress, olderThan]);
                }
            });
            
            // ラベル「Cleaner-xx」を削除し、AutoClean-xxを付与
            mail.removeLabel(label);
            mail.addLabel(autoCleanLabel);
        });
    });
    
    // 削除対象のFromメールアドレスを取得
    const targetMailAddressRange = sheet.getDataRange();
    const targetMailAddressList = targetMailAddressRange.getValues();
    
    targetMailAddressList.forEach(([targetMailAddress, olderThan]) => {
    
        //検索条件:指定されたメールアドレス && ラベルなし && ☆スターなし
        const labelAddThreads = GmailApp.search(`from:(${targetMailAddress}) has:nouserlabels -is:starred`);
        if (labelAddThreads.length === 0) {
            return;
        }
        
        //検索条件に合致するメールに「AutoClean-xx」ラベルを付与
        const label = GmailApp.getUserLabelByName("AutoClean-" + olderThan) ||
            GmailApp.createLabel("AutoClean-" + olderThan);
            
        // 配列を100件ずつに分割
        const chunk = 100;
        for (let i = 0; i < labelAddThreads.length; i += chunk) {
            const threads = labelAddThreads.slice(i, i + chunk);
            label.addToThreads(threads);
        }
    });
}

/**
 * 指定期間以上前のメールをゴミ箱に移動
 */
function deleteThreads() {
    const sheet = SpreadsheetApp.getActiveSheet();
    const targetMailAddressRange = sheet.getDataRange();
    const targetMailAddressList = targetMailAddressRange.getValues();
    
    targetMailAddressList.forEach(([targetMailAddress, delayDays]) => {
    
        //検索条件:指定されたメールアドレス && 受信日が指定期間より前 && ☆スターなし
        const deleteThreads = GmailApp.search(`from:(${targetMailAddress}) older_than:${delayDays} -is:starred`);
        console.log(targetMailAddress, delayDays, deleteThreads.length, "");
        
        //検索条件に合致するメールをゴミ箱に移動
        // 配列を100件ずつに分割
        const chunk = 100;
        for (let i = 0; i < deleteThreads.length; i += chunk) {
            const threads = deleteThreads.slice(i, i + chunk);
            GmailApp.moveThreadsToTrash(threads);
        }
    });
}

制約事項

GASはいくつかの制約事項があります。
今回のスクリプトで影響を受けるのはこのあたりです。

  • タイムアウト時間(6分 or 30分)
  • Gmail APIの1日の最大実行回数

基本的には削除できずにエラーが出てメールが溜まってしまうだけなので、致命的な影響はないと思います。
気になる方は、実行数の管理なども加えてあげると良いでしょう。

終わりに

今回はネット上で見かける自動化の仕組みを、より自分の使いやすいようにカスタマイズをしてみました。
ネット上の情報は参考になったり便利なものも多いですが、そのままでは使いづらいことも多いです。

自分の欲しい機能とのギャップをいかに埋めるか、試行錯誤して解決できたときの満足感はひとしおですね。
今後も、日常のちょっとした手間を簡単に解消する方法を、日々探していきたいと思います。

参考

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?