
【小ネタ】標的型訓練メールに引っかかったのが悔しかったので標的型メール通知ツールをつくった
せーのでございます。
クラスメソッドでは定期的に標的型訓練メールが送られてきます。Microsoft や Google、OpenAI などを名乗ったり、社長名義だったりと、かなり紛らわしい。引っかかると「引っかかりました」画面が出てアンケート記入、という流れなのですが、正直すごく悔しいです。
忙しいときは注意力が散漫になりがちで、ついリンクを踏んでしまうこともあります。毎回 Gmail で送信元アドレスを目視確認するのも現実的ではないので、GAS と Vertex AI Gemini で未読の重要メールを定期チェックし、怪しければ Slack に通知するツールを作りました。
やりたいこと
- AI に「これ怪しくない?」を任せて、リンクを踏む前に気づきたい
- メールは削除せず、通知だけ(誤検知を考慮)
ざっくり仕組み
Gmail(未読 + 重要)→ GAS(5〜10分トリガー)→ Gemini 2.5 Flash(JSON判定)→ Slack通知 + 既読化
業務メールを扱うので Google AI Studio の無料枠ではなく Vertex AI を使っています(無料枠はデータがモデル改善に使われる可能性があります)。認証は ScriptApp.getOAuthToken() なので、API キーの管理は不要です。
コード
PRESIDENT_NAME はうちの社内ルール用の例です。自分の環境に合わせて書き換えてください。
// --- 設定項目 ---
const PROJECT_ID = 'YOUR_GCP_PROJECT_ID'; // GCPのプロジェクトID
const LOCATION = 'asia-northeast1'; // 東京リージョン
const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/XXXXXXXXXX';
const PRESIDENT_NAME = '横田'; // 社長名(検知ルールに使用)
const SEARCH_QUERY = 'is:unread is:important'; // 未読かつ重要ラベル
// ---------------
function checkPhishingEmails() {
const threads = GmailApp.search(SEARCH_QUERY);
if (threads.length === 0) return;
for (let i = 0; i < threads.length; i++) {
const messages = threads[i].getMessages();
for (let j = 0; j < messages.length; j++) {
const message = messages[j];
if (message.isUnread()) {
const sender = message.getFrom();
const subject = message.getSubject();
const body = message.getPlainBody();
const analysisResult = analyzeEmailWithVertexAI(sender, subject, body);
console.log("AIの判定結果:", analysisResult);
if (analysisResult && analysisResult.is_phishing) {
sendToSlack(sender, subject, analysisResult.reason);
}
message.markRead();
}
}
}
}
function analyzeEmailWithVertexAI(sender, subject, body) {
const url = `https://${LOCATION}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${LOCATION}/publishers/google/models/gemini-2.5-flash:generateContent`;
const prompt = `
あなたは優秀なサイバーセキュリティアナリストです。以下のメール情報から、フィッシング詐欺や標的型攻撃訓練メールであるかどうかを判定してください。
【判定ルール】
1. 送信者名や本文に「${PRESIDENT_NAME}」が含まれている場合、本人はメールを送らないため100%詐欺です。
2. Microsoft, Google, OpenAI, Anthropicなどの大手企業を名乗っているが、送信元アドレスのドメインがフリーメールや公式と異なるスペル(例: g00gle.comなど)の場合は詐欺です。
3. アンケートへの回答、パスワードの変更、緊急のリンククリックを促す内容は強く疑ってください。
【メール情報】
送信元: ${sender}
件名: ${subject}
本文: ${body.substring(0, 1000)}
【出力形式】
必ず以下のJSON形式のみを出力してください。
{
"is_phishing": true または false,
"reason": "判定理由を簡潔に"
}
`;
const payload = {
contents: [{ role: "user", parts: [{ text: prompt }] }],
generationConfig: { responseMimeType: "application/json" }
};
const options = {
method: 'post',
contentType: 'application/json',
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response.getContentText());
if (json.candidates && json.candidates.length > 0) {
const resultText = json.candidates[0].content.parts[0].text;
return JSON.parse(resultText);
} else {
console.error("API Error: " + response.getContentText());
}
} catch (e) {
console.error("Fetch Error: " + e);
}
return null;
}
function sendToSlack(sender, subject, reason) {
const payload = {
text: `🚨 *不審なメール(詐欺・訓練の可能性)を検知しました* 🚨\n*送信元:* ${sender}\n*件名:* ${subject}\n*AIの判定理由:* ${reason}\n\nうっかりリンクを踏まないように注意してください!`
};
const options = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
};
UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
}
appsscript.json に cloud-platform スコープが必要です。
{
"timeZone": "Asia/Tokyo",
"dependencies": {},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/gmail.modify",
"https://www.googleapis.com/auth/cloud-platform"
]
}
これを設定して5分間隔で回すだけです。
ちなみに過去に送られてきた標的型訓練メールを未読に戻してテストしてみました。

うん、ばっちし。
設定メモ
コピペしたあと、だいたい次だけやれば動きます。
- GCP プロジェクトを作成し、Vertex AI API を有効化
- GAS の「プロジェクト設定」で GCP プロジェクト番号を紐づけ
- スクリプト実行者に Vertex AI ユーザー ロールを付与(これを忘れると 403 になります)
- Slack Incoming Webhook URL を
SLACK_WEBHOOK_URLに設定 - トリガーで
checkPhishingEmailsを 5〜10 分間隔で実行
試すだけなら特に問題ありません。同じように訓練メールにうっかり引っかかりがちな方、みなさんはどう対策していますか?






