如何在Google Apps Script中添加IF条件防止重复发送邮件
脚本重复发送邮件的常见原因及修复方案
核心问题原因
- 无异常捕获逻辑,发送失败后未写入标记:当前代码先执行
MailApp.sendEmail再写EMAIL_SENT标记,若发信过程中出现报错(如收件人地址无效、邮件配额耗尽、网络波动、模板替换函数执行异常),后续写标记的代码会直接中断执行,该行下次运行时仍会被判定为未发信,导致重复发送。 - 工作表按下标取值易出错:你当前用
ss.getSheets()[0]、ss.getSheets()[1]按下标取工作表,一旦有人调整了表格内工作表的顺序,就会导致操作的表和预期不符,标记无法写入正确的位置。 - 字符串匹配未兼容异常字符:若第36列已有的
EMAIL_SENT带前后空格、不可见字符,或者第11列的status存在大小写、空格差异,会导致判定条件失效,重复触发发信逻辑。 - 触发器重复/并发触发:若你给脚本配置了多个重复的触发器,或触发器间隔太短导致上一次脚本未执行完下一次就启动,上一轮还没来得及写入标记的行,会被下一轮再次判定为未发信,导致重复发送。
- 脚本运行超时未写完标记:若你的表格行数过多,循环内逐行调用
setValue会拖慢运行速度,一旦超过Google Apps Script 6分钟的执行上限,脚本会被强制终止,未写完标记的行下次运行时会再次发信。
修复代码参考
/** * Sends emails from spreadsheet rows. */ function sendEmails() { const ss = SpreadsheetApp.getActive(); // 替换为你实际的工作表名称,避免顺序变动导致错误 const dsh = ss.getSheetByName('数据源表'); // 一次性读取所有需要的列,包括预留的错误日志列(第37列) const drg = dsh.getRange(2, 1, dsh.getLastRow() - 1, 37); const vs = drg.getValues(); const output = vs.map(row => [...row]); // 复制原数据用于批量写入 const tsh = ss.getSheetByName('模板表'); const tmpl = tsh.getRange('A1').getValue(); vs.forEach((r,i) => { let emailSent = r[35]?.toString().trim() || ''; let status = r[10]?.toString().trim().toUpperCase() || ''; if (status === 'PRICE ONLY' && emailSent !== 'EMAIL_SENT') { try { MailApp.sendEmail(r[9], 'SUPERMIX QUOTATION', fillInTemplateFromObject(tmpl, r)); output[i][35] = 'EMAIL_SENT'; output[i][36] = new Date() + ' 发送成功'; } catch (e) { // 记录错误信息,避免重复发信 output[i][36] = new Date() + ' 发送失败:' + e.message; } } }); // 批量写入所有结果,减少API调用提升效率 drg.setValues(output); SpreadsheetApp.flush(); } // 其余函数保留原逻辑即可,注意检查normalizeHeader函数是否有报错
额外检查项
- 进入Google Apps Script项目的「触发器」页面,删除重复的多余触发器,避免重复触发。
- 检查
normalizeHeader函数的实现是否存在异常,该函数报错会导致模板替换失败、中断发信逻辑。
内容的提问来源于stack exchange,提问作者Les
相关产品推荐
相关产品推荐

