Gmailの配信解除リンクを開く前に確認|GASで候補メールをdry-run監査
ツールおじ|GoogleアカウントをAIエージェント化
「不要なメルマガを減らしたい。でも、メール内の解除リンクを片っ端から開くのは不安」ということはありませんか。
この記事では、Gmailの標準的な `List-Unsubscribe` ヘッダーを読み取り、配信解除候補をドメイン別に集計します。解除URLへのアクセス、メール送信、削除、既読化、ラベル変更は一切行いません。 まず安全な候補だけを絞り、最終判断は人が行うための無料サンプルです。
このサンプルでできること・できないこと
- Gmail検索で対象を最大30スレッドに限定します。
- 配信解除用ヘッダーの有無と、HTTPS・メール送信・ワンクリック方式への対応を確認します。
- 件名、本文、送信者の完全なメールアドレス、メッセージID、解除URLはログへ出しません。
- 配信解除リンクは開かず、解除メールも送りません。
- 正規の送信元か、解除してよい契約・通知かは自動判定しません。
配信解除ヘッダーがないメールや、サービス利用に必要な通知もあります。結果が出ても即実行せず、送信元の公式画面で契約状況を確認してください。
準備するもの
- Google Apps Scriptで新しいプロジェクトを作ります。
- 左側の「サービス」から Gmail API を追加します。
- 下のコードを貼り付けます。
- 最初は `QUERY` と `MAX_THREADS` を変えず、少量で試します。
検索条件は `category:promotions older_than:14d` です。受信トレイ全体ではなく、14日より前のプロモーション候補だけを確認します。
コピーして使える最小コード
const CONFIG = Object.freeze({
DRY_RUN: true,
QUERY: 'category:promotions older_than:14d',
MAX_THREADS: 30,
LOG_DETAILS: false
});
function auditGmailUnsubscribeHeadersFree() {
validateConfig_();
const threads = GmailApp.search(CONFIG.QUERY, 0, CONFIG.MAX_THREADS);
const summaryByDomain = new Map();
threads.forEach(thread => {
const messages = thread.getMessages();
if (!messages.length) return;
// スレッド内の最新メッセージだけを確認する
const message = messages[messages.length - 1];
const metadata = Gmail.Users.Messages.get('me', message.getId(), {
format: 'metadata',
metadataHeaders: [
'From',
'List-Unsubscribe',
'List-Unsubscribe-Post'
]
});
const headers = metadata.payload && metadata.payload.headers
? metadata.payload.headers
: [];
const fromHeader = getHeader_(headers, 'From');
const unsubscribeHeader = getHeader_(headers, 'List-Unsubscribe');
const unsubscribePostHeader = getHeader_(headers, 'List-Unsubscribe-Post');
const domain = extractDomain_(fromHeader);
const current = summaryByDomain.get(domain) || {
domain,
checked: 0,
httpsHeader: 0,
mailtoHeader: 0,
oneClickHeader: 0,
headerMissing: 0
};
current.checked += 1;
if (!unsubscribeHeader) {
current.headerMissing += 1;
} else {
if (/<https:\/\//i.test(unsubscribeHeader)) current.httpsHeader += 1;
if (/<mailto:/i.test(unsubscribeHeader)) current.mailtoHeader += 1;
}
if (/list-unsubscribe=one-click/i.test(unsubscribePostHeader)) {
current.oneClickHeader += 1;
}
summaryByDomain.set(domain, current);
});
const result = {
status: 'REVIEW',
dryRun: CONFIG.DRY_RUN,
query: CONFIG.QUERY,
checkedThreads: threads.length,
domains: [...summaryByDomain.values()]
.sort((a, b) => b.checked - a.checked)
};
// 件名・本文・完全なメールアドレス・解除URLは出力しない
Logger.log(JSON.stringify(result));
if (CONFIG.LOG_DETAILS === true) {
Logger.log('注意: 詳細ログは実装していません。個人情報を追加しないでください。');
}
}
function validateConfig_() {
if (CONFIG.DRY_RUN !== true) {
throw new Error('安全のためDRY_RUNはtrue固定です');
}
if (typeof CONFIG.QUERY !== 'string' || !CONFIG.QUERY.trim()) {
throw new Error('QUERYを空欄にしないでください');
}
if (!Number.isInteger(CONFIG.MAX_THREADS) ||
CONFIG.MAX_THREADS < 1 || CONFIG.MAX_THREADS > 30) {
throw new Error('MAX_THREADSは1〜30で指定してください');
}
}
function getHeader_(headers, name) {
const target = headers.find(header =>
String(header.name || '').toLowerCase() === name.toLowerCase()
);
return target ? String(target.value || '') : '';
}
function extractDomain_(fromHeader) {
// 表示名や完全なメールアドレスは保持せず、ドメインだけ返す
const match = String(fromHeader).toLowerCase()
.match(/@([a-z0-9.-]+\.[a-z]{2,})/i);
return match ? match[1] : 'unknown';
}実行手順
- Apps Scriptの実行関数で `auditGmailUnsubscribeHeadersFree` を選びます。
- 初回だけGmailの読み取り権限を確認し、自分のテスト用アカウントで許可します。
- 「実行ログ」を開き、`checkedThreads` と `domains` を確認します。
- `oneClickHeader` や `httpsHeader` があるドメインでも、メール内リンクを自動では開きません。
- 継続不要と判断した配信だけ、送信元サービスの公式サイトや正規メールから手動で解除します。
ログの見方
- `checked`: そのドメインで確認したスレッド数
- `httpsHeader`: HTTPSの解除候補を持つ件数
- `mailtoHeader`: 解除メール送信方式を持つ件数
- `oneClickHeader`: ワンクリック解除の標準ヘッダーを持つ件数
- `headerMissing`: 標準ヘッダーを確認できなかった件数
`headerMissing` は異常確定ではありません。また、ヘッダーがあっても送信元が安全だという保証にはなりません。見覚えのない送信元や不審なドメインはリンクを開かず、Gmailの迷惑メール報告など別の対応を検討してください。
失敗しやすい点と制限
- Gmail APIを追加していないと `Gmail is not defined` になります。
- Gmail検索の結果はアカウントの分類状況に左右されます。
- 配信解除ヘッダーは任意のため、すべてのメールに存在するわけではありません。
- 実行時間とGmail APIの利用上限があります。まず30件以下で確認してください。
- 業務アカウントでは、管理者の権限設定により実行できない場合があります。
- 重要通知、領収書、契約中サービスの連絡まで解除しないよう、人が最終確認してください。
公開前チェックリスト
- [ ] `DRY_RUN` が `true` のまま
- [ ] 対象がプロモーション候補か確認した
- [ ] 件名・本文・完全なメールアドレス・解除URLをログへ追加していない
- [ ] リンク自動アクセス、メール自動送信、削除、既読化を追加していない
- [ ] 少量のテスト用アカウントで実行した
- [ ] 最終解除は公式サイトまたは正規メールから手動で確認する
まとめ
不要メール対策は、いきなり解除リンクを自動実行するより、まず標準ヘッダーの有無を読み取り専用で確認する方が安全です。このコードは候補の集計までに限定し、Gmail上の状態は変えません。
定型メールを送信せずに下書きで確認したい方へ

GasおじのTips商品一覧を見る

※学習・検証用の例です。実データへ適用する前に、少量のテスト環境で権限とログを確認してください。Google公式・Google公認の商品ではありません。
