forEach结合HTML模板批量发邮件时数据无法识别的问题
问题描述
我编写了一段Google Apps Script脚本,想从电子表格中获取多行数据,为每行数据发送一封邮件。但运行data.forEach()循环时,HTML模板无法识别循环中的value参数,导致模板内的value.name和value.score无法正常渲染。
数据示例
| Student | Score |
|---|---|
| Robert | 8 |
| David | 6 |
| Frank | 9 |
现有脚本代码
function sendMultipleEmails() { const rawData = ss.getRange("A1:B3").getValues(); let data = []; // 比起表格的二维数组,我更喜欢用对象字面量 rawData.forEach(value => { data.push({ name: value[0], score: value[1], }) }) data.forEach(value => { let emailTo = "example@gmail.com"; // 这里的value.name能正常用,因为是在代码里直接设置的 let subject = `Scores for ${value.name}`; let body = HtmlService.createTemplateFromFile("scores"); let message = body.evaluate().getContent(); let options = { htmlBody: message, } GmailApp.sendEmail(emailTo, subject, body, options) }) }
现有HTML模板代码
<h2> Hey <?= value.name ?> </h2> <p>This is your score <?= value.score?></p>
解决方法
核心问题是你没有把循环中的value对象传递给HTML模板——模板有独立作用域,无法直接访问脚本循环里的变量,必须显式把数据挂载到模板对象上。
1. 传递数据到模板
创建模板后,把当前循环的学生数据赋值给模板的属性:
let body = HtmlService.createTemplateFromFile("scores"); // 将当前学生数据挂载到模板上 body.student = value;
2. 修改模板变量引用
把模板里的value.name、value.score改成对应模板属性的student.name、student.score:
<h2> Hey <?= student.name ?> </h2> <p>This is your score <?= student.score?></p>
3. 修复邮件发送参数错误
原代码中GmailApp.sendEmail的第三个参数传了模板对象body,这是错误的,应该传入纯文本版本的备用邮件内容:
// 第三个参数替换为纯文本内容,作为HTML邮件的降级备选 GmailApp.sendEmail(emailTo, subject, `Hey ${value.name}, your score is ${value.score}`, options)
优化后的完整脚本
function sendMultipleEmails() { const ss = SpreadsheetApp.getActiveSpreadsheet(); // 补充ss的定义,原代码遗漏会报错 const rawData = ss.getRange("A1:B3").getValues(); // 用map直接转换数组,比forEach+push更简洁 const data = rawData.map(row => ({ name: row[0], score: row[1] })); data.forEach(student => { const emailTo = "example@gmail.com"; const subject = `Scores for ${student.name}`; const template = HtmlService.createTemplateFromFile("scores"); template.student = student; const message = template.evaluate().getContent(); const options = { htmlBody: message }; GmailApp.sendEmail(emailTo, subject, `Hey ${student.name}, your score is ${student.score}`, options); }); }
额外优化点
- 用
map替代forEach+push转换数组,代码更简洁 - 补充
ss的声明(原代码未定义会触发报错) - 用
const替代不必要的let,提升代码严谨性
内容的提问来源于stack exchange,提问作者David Salomon
相关产品推荐
相关产品推荐

