You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Apps Script邮件HTML格式失效及forEach报错问题求助

自行车组装提醒系统问题排查与修复

问题概述

为门店搭建自动自行车组装提醒系统,用于通知待组装车辆信息,避免遗漏。参考教程实现邮件发送后遇到两个问题:

  1. 邮件无法正常显示HTML格式
  2. 修改sendEmail适配周日特殊主题后,getEmailText函数抛出"cannot read property 'forEach' of undefined"错误

核心问题1:HTML邮件无法正常显示

问题原因

原sendEmail函数调用MailApp.sendEmail时,参数htmlbody拼写错误(应为驼峰式htmlBody),导致系统无法识别HTML格式内容;修改后的sendEmail参数格式正确,但原版本的拼写错误是根本诱因。

修复代码

原错误代码片段:

MailApp.sendEmail({
  to: emailAddress, 
  subject: "Automated Email: Bike Build Alerts", 
  body: body,
  htmlbody: htmlBody // 拼写错误:应为htmlBody
});

修复后统一使用正确参数格式:

// 两种写法均有效,推荐保持格式统一
// 写法1:参数列表传递
MailApp.sendEmail(emailAddress, subject, body, {htmlBody: htmlBody});
// 写法2:完整对象参数
MailApp.sendEmail({
  to: emailAddress,
  subject: subject,
  body: body,
  htmlBody: htmlBody // 正确驼峰命名
});

原理讲解

Google Apps Script的MailApp.sendEmail方法对参数名大小写敏感,只有htmlBody(首字母小写,第二个B大写)才会被识别为HTML内容载体。拼写错误会导致系统忽略该参数,仅显示纯文本body内容。


核心问题2:"cannot read property 'forEach' of undefined"错误

问题原因

错误根源在getData函数,存在两个关键问题:

  1. 未获取单元格实际值:whichDay仅获取了Range对象,未调用getValue()拿到单元格内的文本,导致周日判断逻辑完全失效。
  2. 循环提前终止+未返回数据:values.forEach循环内部每次添加数据后都执行return bicycles,会直接终止当前循环迭代;且函数末尾未返回bicycles数组,最终getData()返回undefined,传递给getEmailText后调用forEach就会报错。

修复代码

修复后的getData函数:

function getData(){
  var values = SpreadsheetApp.getActive().getSheetByName("Bikes to be built").getRange("Bikes").getValues();
  var bicycles = [];
  // 关键:获取单元格实际文本值
  var whichDay = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Bikes to be built").getRange("N2").getValue();
  
  if (whichDay !== "Sunday"){
    values.forEach(function(row) {
      // 合并条件判断,简化逻辑
      if (row[1] !== "#N/A" && row[4] < 4 && row[3] === ""){
        var bikes = {};
        bikes.bike = row[1];
        bikes.due = row[2];
        bikes.remaining = row[4];
        bikes.status = row[5];
        bicycles.push(bikes);
        // 移除错误的return,避免中断循环
      }  
    });
  } else if (whichDay === "Sunday"){
    values.forEach(function(row) {
      if (row[1] !== "#N/A"){
        var bikes = {};
        bikes.bike = row[1];
        bikes.due = row[2];
        bikes.remaining = row[4];
        bikes.status = row[5];
        bicycles.push(bikes);
        // 移除错误的return
      }
    });
  }
  // 关键:必须返回组装好的数组
  return bicycles;
}

同时优化getEmailText增加空值判断,避免后续报错:

function getEmailText(bikeData){
  var text = "";
  // 先判断bikeData是否为有效数组
  if (!bikeData || !Array.isArray(bikeData)) return text;
  
  bikeData.forEach(function(bike) {
    text += `${bike.bike}\n${bike.due}\n${bike.remaining}\n-----------------------\n\n`;
  });
  return text;
}

原理讲解

  1. Range对象与单元格值:getRange()返回的是单元格范围对象,必须调用getValue()才能读取单元格内的实际内容,否则对象与字符串直接比较永远不相等。
  2. forEach循环的return行为:在forEach的回调函数中使用return只会终止当前迭代,不会跳出整个循环;若需提前终止循环,应使用for循环而非forEach。
  3. 函数返回值:函数若无显式return语句,默认返回undefined。调用者接收undefined后调用数组方法(如forEach),就会抛出"cannot read property 'xxx' of undefined"错误。

额外优化建议

  1. 清理getEmailHtml冗余代码:htmlTemplate.data = ...未被模板使用,可删除以减少不必要计算:
function getEmailHtml(bikeData){
  var htmlTemplate = HtmlService.createTemplateFromFile("Template.html");
  htmlTemplate.bikes = bikeData;
  return htmlTemplate.evaluate().getContent();
}
  1. 声明subject变量:修改后的sendEmail中subject未声明,会成为全局变量,建议添加let:
let subject;
if (whichDay === "Sunday"){
  subject = "Automated Email Alerts: Sunday Roundup";
} else {
  subject = "Automated Email Alerts: Bike Build Requests";
}
  1. 空数据日志记录:当bikeData为空时,邮件不会发送,添加日志方便调试:
if (body !== ""){
  MailApp.sendEmail(emailAddress, subject, body, {htmlBody});
} else {
  Logger.log("No bike build alerts to send.");
}

内容的提问来源于stack exchange,提问作者Kathryn Gratton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:10:33