🎃
Gmailを定期的に削除するCloud Functionsを作成
Gmail
Gmailはみなさん高確率で利用されているのではないでしょうか。
私の場合結構なウェイトを占めている利用方法があります。
会社でグループウェアを使用してメール処理をしてますが、保管用にGmailへ自動転送しています。
グループウェアだけで管理できれば良いのですが、メール検索が貧弱なため
転送先のGmailで検索してたりしています。(ファイル内容も検索してくれるので重宝しています)。
ただ、Gmail無料枠は10GBですので、転送し続けれるわけなく私の場合は90%を超えてきていました。
システムメール(ログ)なども全転送してるので、塵も積もれば山となるという感じです。
そこで、うまいこと定期的にメール削除したいと考え、Cloud Functonsで処理させることにしました。
プロジェクトの作成
事前にfirebaseプロジェクト作成
お決まりfirebase-toolsを使ってローカル環境設定
mkdir gmail-operation
firebase init
必要なパッケージをインストール
npm install -D prettier eslint-config-prettier eslint-plugin-import
npm install googleapis@105 @google-cloud/local-auth@2.1.0
GmailApi有効化
今回は先にインストールしたgoogleapisを利用しますので、
下記のURLの通りに従ってAPIを有効化およびCredentialを設定します。
なお今回利用したいAPIの機能としてはメールのゴミ箱移動(削除も今後入れる予定)なため、
必要なスコープを設定します。
https://mail.google.com/
実装
基本部分は上記のリンク先にあるサンプルソースを利用して実装
functions/src/index.ts
import { initializeApp } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';
import * as functions from 'firebase-functions';
import { authorize, getGmail, listLabels, mails, mailTrash } from './libs/google';
initializeApp();
const baseFunctionWithRegion = functions.region('asia-northeast1');
// 毎日0時に実行
export const GmailTrash = baseFunctionWithRegion.pubsub
.schedule('0 0 * * *')
.timeZone('Asia/Tokyo')
.onRun(async (ctx) => {
functions.logger.info(`----- GmailTrash Function Start -----`);
const auth = await authorize();
const gmail = getGmail(auth);
// ラベル(フォルダ)取得
const db = getFirestore();
const snapshot = await db.collection('labels').get();
const labelNames = snapshot.docs.map(doc => doc.data().label as string);
const allLabelList = await listLabels(gmail);
const targetLabelList = allLabelList?.filter((e) => labelNames.includes(e.name?.toLowerCase() ?? ''));
if (!targetLabelList) return;
const nonNullable = <T>(value: T): value is NonNullable<T> => !!value;
const labelIds = targetLabelList.map((e) => e.id).filter(nonNullable);
// メール取得
const mailList = await mails(gmail, labelIds);
functions.logger.info('mailList count:', mailList?.length);
if (!mailList) {
return;
}
for (const row of mailList) {
if (row.id) {
await mailTrash(gmail, row.id);
}
functions.logger.info(`----- trash mail -----`);
}
functions.logger.info(`----- GmailTrash Function End -----`);
});
サンプルから追加、修正した部分抜粋
functions/src/libs/google.ts
import * as fs from 'node:fs/promises';
import * as path from 'path';
import * as process from 'process';
import { authenticate } from '@google-cloud/local-auth';
import * as dayjs from 'dayjs';
import * as ja from 'dayjs/locale/ja';
import { gmail_v1, google } from 'googleapis';
import { BaseExternalAccountClient, OAuth2Client } from 'googleapis-common';
dayjs.locale(ja);
const SCOPES = ['https://mail.google.com/'];
const TOKEN_PATH = path.join(process.cwd(), 'token.json');
const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json');
export const getGmail = (auth: OAuth2Client | BaseExternalAccountClient) => google.gmail({ version: 'v1', auth });
// メール取得
export const mails = async (gmail: gmail_v1.Gmail, labelIds: string[]) => {
// 7ヶ月以上前のメール取得
const before = dayjs().add(-7, 'month');
// 7ヶ月以上前から更に1年
const after = before.add(-1, 'year');
const mails = await gmail.users.messages.list({
userId: 'me',
// default
// maxResults: 100,
labelIds,
// qはgmail画面の検索クエリと同等なので、Gmailで実際に検索してコピペ
q: `after:${after.format('YYYY/MM/DD')} before:${before.format('YYYY/MM/DD')}`,
});
return mails.data.messages;
};
// ゴミ箱移動処理
export const mailTrash = async (gmail: gmail_v1.Gmail, id: string) => {
try {
await gmail.users.messages.trash({
userId: 'me',
id,
});
} catch (error) {
console.warn(error);
throw new Error('delete error');
}
};
あとは、ローカルで一度実行し認証してトークンファイル作成し、本番デプロイ
npm run serve
npm run deploy
稼働状況確認
ログもちゃんととれてますし、実際ゴミ箱へ移動されており問題なし
今までは定期的に自分で処理してて結構めんどくさいなぁと思ってましたが、
簡単に実装できて満足です。
Gmailを無料枠で利用されている方で容量逼迫している方がいましたらぜひ実装してみてください!
Discussion