Apps Script定时触发器运行异常:重复发邮件且信息错误
问题诊断与修复方案
核心问题分析
代码在时间驱动触发器运行时出现多发邮件、内容错误,但手动运行正常,根源在于全局变量滥用和变量未局部化,结合Google Apps Script的执行机制,具体问题如下:
- 全局变量生命周期冲突:
today1、weekday1、BMs、j等全局变量仅在脚本首次加载时初始化,触发器重试或缓存时会保留旧值,导致日期判断错误、循环起始位置混乱。手动运行时每次都是全新上下文,所以表现正常。 - 隐式全局变量污染:
line1、htmlBody等变量未用var/let/const声明,自动成为全局变量,循环迭代时会被上一次的值覆盖,导致邮件内容混乱。 - 时区不一致:全局的日期格式化使用
GMT-7,但触发器默认执行时区可能与手动运行时不同,导致monthday1<20的判断出现偏差,触发错误逻辑。
修复后的代码
function sendRundownSum() { // 局部化所有变量,避免全局污染 const ssId = '1en0zmKvFthJpS_0eVDFGsvEuwq3uGhHZ53b34LF9D5g'; const st1 = SpreadsheetApp.openById(ssId).getSheetByName("Daily Email Template"); const today1 = new Date(); const timezone = "GMT-7"; const weekday1 = today1.getDay(); const monthday1 = parseInt(Utilities.formatDate(today1, timezone, "d"), 10); // 替换为实际的成员名称与邮箱数组,建议从表格指定范围读取 const BMs = []; const BMEmails = []; Logger.log(weekday1 + " " + today1); // 日期判断移至循环外,减少重复执行 if (weekday1 > 0 && weekday1 < 6 && monthday1 < 20) { for (let j = 0; j < BMs.length; j++) { let line1 = []; let line2 = []; let line0 = []; let line3 = []; let line4 = []; let line5 = []; let line6 = []; SpreadsheetApp.flush(); st1.getRange(2,2).setValue(BMs[j]); SpreadsheetApp.flush(); if (st1.getRange(7,3).getValue() !== "") { Logger.log('lates'); line1.push("请在L列选择延迟类型:"); line1.push(st1.getRange(7,3).getValue()); line1.push("对应房源表格入口"); line1.push("\n"); line1 = line1.join('\n'); } if (st1.getRange(9,3).getValue() !== "") { Logger.log('action items'); line2.push("今日需处理事项: "); line2.push(st1.getRange(9,3).getValue()); for (let i = 14; i < 100; i++) { const cellValue = st1.getRange(i,3).getValue(); if (cellValue !== "") { line2.push(cellValue); } } line2 = line2.join('\n'); } if (st1.getRange(8,3).getValue() !== "") { Logger.log('exports'); line0.push("已QC通过但未导出的房源:"); line0.push(st1.getRange(8,3).getValue()); line0.push("\n"); line0 = line0.join('\n'); } if (st1.getRange(10,3).getValue() !== "") { Logger.log('goal dates'); line3.push("未设置目标日期的房源:"); line3.push(st1.getRange(10,3).getValue()); line3.push("\n"); line3 = line3.join('\n'); } if (st1.getRange(11,3).getValue() !== "") { Logger.log('autoproof'); line4.push("未开启自动审核的房源:"); line4.push(st1.getRange(11,3).getValue()); line4.push("\n"); line4 = line4.join('\n'); } if (st1.getRange(12,3).getValue() !== "") { Logger.log('prebill'); line5.push("已归档但未发送预账单的房源:"); line5.push(st1.getRange(12,3).getValue()); line5.push("\n"); line5 = line5.join('\n'); } if (st1.getRange(13,3).getValue() !== "") { Logger.log('coming up'); line6.push(st1.getRange(3,3).getValue() + " - 即将到期的房源:"); line6.push(st1.getRange(13,3).getValue()); line6.push("\n"); line6 = line6.join('\n'); } let htmlBody; const content = line1 + line0 + line2 + line3 + line4 + line5 + line6; if (content !== "") { htmlBody = "您好!\n\n" + line1 + line0 + line3 + line4 + line5 + line6 + line2; } else { htmlBody = "您好!\n\n今日无紧急事项!"; } const recipient = BMEmails[j]; const subject = "每日摘要: " + BMs[j]; MailApp.sendEmail(recipient, subject, htmlBody); Logger.log("已发送邮件给: " + BMs[j]); } } }
关键修复点
- 变量全局部化:所有变量移至函数内部,用
const/let声明,确保每次执行都是全新上下文,避免缓存异常。 - 优化日期判断:将工作日、日期判断移至循环外,明确时区参数,避免时区不一致导致的逻辑错误。
- 修复隐式全局变量:给所有变量添加声明,消除变量污染问题。
- 简化数组操作:用
Array.join()替代复杂的concat.apply,代码更简洁易读。
额外注意事项
- 需补充
BMs和BMEmails的赋值逻辑,建议从表格指定范围读取成员信息,否则数组为空不会发送邮件。 - 触发器设置中需明确指定执行时区为
GMT-7,确保日期判断一致。 - 可添加
try-catch块捕获错误,避免单个成员的问题导致整个脚本中断。
内容的提问来源于stack exchange,提问作者Tyler Henderson
相关产品推荐
相关产品推荐

