現象
- Gmailに届いた特定のメールをスプレッドシートに書き出す
- そこから●時間以内に返信する、という対応をしている
- スプレッドシートへの書き出しはGASが行っている(10分ごとのトリガーが動いている)
- 9/21の2時台に動いたGASが9/20の21:13:17のメールを書き出す、という事象が起こった
課題感
10分間隔のトリガーが動いているので、遅くとも9/20の21時23分までにはGASで書き出されることを期待していたが約4時間後に書き出されたのはなぜ?
現状把握
GASが取得した「受信日時」
ここでの「受信日時」は GmailMessage.getDate() を利用している。
const msgs = GmailApp.getMessagesForThreads(threads);
for (let i = 0; i < msgs.length; i++) {
for (let j = 0; j < msgs[i].length; j++) {
const date = msgs[i][j].getDate(); // ← ここ
実行ログにメールの受信日時を出力していたのですが、その時のログがこちら。
↓ 9/21 2:19:47 に 9/20 21:13:17 のメールを取得している記録がある。
Gmail画面からみた受信日時
↓ 実際のメールをGmailで確認したところ、日付は 9/21 2:14

原因
(メールヘッダを見ることでわかりました)
- 今回はメーリングリストを経由したメール
- GASが取得した日時: メール送信者が送信した日時
- Gmailの画面に表示される日時:そのメールがメーリングリストサーバーを経由し、サーバーから再配送された日時
上の両者に時差があることによって起こった。
なお、メーリングリストを経由したメールには、ほぼ必ず「元の送信日時」と「メーリングリストによる再配送日時」という2つのタイムスタンプが存在することになります。
どれだけ時差があるのか、はメーリングリストサーバー次第であり、再配送が「即時」実行される保証はない。
対策
本当の意味(?)で「受信者がメールを受け取った時刻」を取るにはGASの修正が必要 (getDateではだめで、メールヘッダから抜き出す)
メーリングリスト経由の場合、メールヘッダに下記の表記がある。
Resent-Date: Sun, 21 Sep 2025 02:14:38 +0900
よって下記のように修正。
const msgs = GmailApp.getMessagesForThreads(threads);
for (let i = 0; i < msgs.length; i++) {
for (let j = 0; j < msgs[i].length; j++) {
const msg = msgs[i][j];
let date;
// メールのヘッダー情報を含む生コンテンツを取得
const rawContent = msg.getRawContent();
// "Resent-Date:" ヘッダーを探すための正規表現
const resentDateRegex = /^Resent-Date: (.*)$/im;
const resentDateMatch = rawContent.match(resentDateRegex);
if (resentDateMatch && resentDateMatch[1]) {
// Resent-Date が見つかった場合、その値をDateオブジェクトに変換
date = new Date(resentDateMatch[1].trim());
} else {
// Resent-Date が見つからない場合(通常のメールなど)は、
// 従来の方法で日付を取得
date = msg.getDate();
}
他にいい方法あったら教えてください!
