0
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?

【GAS】Gmail受信時にDiscordへ自動通知する方法

0
Posted at

メールの新着通知を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時間おき(任意変更可能)でトリガーを設定してください。
スクリーンショット 2026-07-25 002011.png

本スクリプトの動作の流れ

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文字)に注意が必要です。

0
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
0
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?