メールの新着通知をDiscordの個人用サーバに通知できるのでは?
ということで実際に作ってみました。
GASのコード
function checkRecentEmailsAndNotifyDiscord() {
const DISCORD_WEBHOOK_URL = "YOUR_WEBHOOK_URL_HERE";
// 1. 保存済みの通知済みメッセージIDリストを取得
const scriptProperties = PropertiesService.getScriptProperties();
const notifiedIdsJson = scriptProperties.getProperty("NOTIFIED_MESSAGE_IDS");
let notifiedIds = notifiedIdsJson ? JSON.parse(notifiedIdsJson) : [];
const nowInSeconds = Math.floor(Date.now() / 1000);
const sixHoursAgoInSeconds = nowInSeconds - (6 * 60 * 60);
// 過去6時間以内のメールを取得
const searchQuery = `after:${sixHoursAgoInSeconds}`;
const threads = GmailApp.search(searchQuery);
if (threads.length === 0) return;
const now = new Date();
const sixHoursAgo = new Date(now.getTime() - (6 * 60 * 60 * 1000));
let hasNewNotification = false;
for (const thread of threads) {
const messages = thread.getMessages();
for (const message of messages) {
const messageId = message.getId();
const messageDate = message.getDate();
// 「6時間以内」かつ「メッセージIDが保存リストに未登録」の場合のみ処理
if (messageDate >= sixHoursAgo && !notifiedIds.includes(messageId)) {
const sender = message.getFrom();
const subject = message.getSubject() || "(件名なし)";
const content = `📩 **新着メールを受信しました**\n` +
`**送信者:** ${sender}\n` +
`**件名:** ${subject}\n` +
`**日時:** ${Utilities.formatDate(messageDate, Session.getScriptTimeZone(), "yyyy-MM-dd HH:mm:ss")}`;
// Discord送信
sendToDiscordWithRetry(DISCORD_WEBHOOK_URL, content);
// IDをメモリ上のリストに追加
notifiedIds.push(messageId);
hasNewNotification = true;
}
}
}
// 2. 新しい通知があった場合、プロパティを更新(肥大化防止のため直近500件のみ保持)
if (hasNewNotification) {
if (notifiedIds.length > 500) {
notifiedIds = notifiedIds.slice(-500);
}
scriptProperties.setProperty("NOTIFIED_MESSAGE_IDS", JSON.stringify(notifiedIds));
}
}
/**
* リトライ機能付きDiscord送信処理
*/
function sendToDiscordWithRetry(webhookUrl, content, maxRetries = 3) {
const payload = { content: content };
const options = {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = UrlFetchApp.fetch(webhookUrl, options);
const statusCode = response.getResponseCode();
// HTTP 200〜299(成功)
if (statusCode >= 200 && statusCode < 300) {
return;
}
console.warn(`送信失敗 (試行 ${attempt}/${maxRetries}): HTTP ${statusCode}`);
} catch (e) {
console.warn(`通信例外 (試行 ${attempt}/${maxRetries}): ${e.toString()}`);
}
// 再試行前の待機 (2秒, 4秒...)
if (attempt < maxRetries) {
Utilities.sleep(Math.pow(2, attempt) * 1000);
}
}
throw new Error(`Discordへの送信に ${maxRetries} 回失敗したため、処理を中断しました。`);
}
事前準備
Discord テキストチャンネルのWebhookURLを取得
上記コード2行目の"YOUR_WEBHOOK_URL_HERE" へ貼り付けてください。("は消さない)
Apps Scriptのトリガーを設定
時間主導型、時間ベースのタイマー、2時間おき(任意変更可能)でトリガーを設定してください。

本スクリプトの動作の流れ
1. 過去6時間のメールを一括取得
定期トリガーの遅延や一時的なエラーに備え、実行時から過去6時間以内に受信したメール(スレッド)をまとめて取得します。
2. メッセージ単位での新着・未通知判定
スレッド内のメールを1通ずつ確認し、「受信日時が6時間以内」かつ「スクリプトプロパティ(PropertiesService)にIDが未登録」のメッセージのみを抽出します。
※これにより、Gmailのスレッドビュー(返信が1つにまとまる機能)を保持したまま、同じスレッドに届いた2通目以降の新着返信メールだけを正確に識別できます。
3. 送信者・件名・日時の抽出
該当する新着メールから「送信者 (From)」「件名 (Subject)」「受信日時」の情報を取得します。
4. エラー時の自動リトライ機能(指数バックオフ)
Discordへの送信時に一時的な通信エラーが発生した場合、数秒間隔を空けて最大3回まで自動で再試行します。
5. Discordへの通知発行
取得したメール情報を整形し、設定したDiscordのWebHookを通じて指定チャンネルへ即座に転送します。
6. メッセージIDの保存(二重通知の完全防止)
通知が成功したメール固有のメッセージIDをスクリプトプロパティへ安全に記録します。
補足
GASにおけるUrlFetchAppの1日当たりの実行回数制限は、無料のGoogleアカウント(Gmailなど): 20,000回 / 日なので、他のスクリプトでガンガン使用している場合には上限にご注意ください。
message.getPlainBody() を使えば本文も送れますが、Discordの文字数制限(2000文字)に注意が必要です。