Apps Script HTML 邮件中正确处理换行符的教程

DDD
发布: 2025-09-15 11:27:50
原创
743人浏览过

Apps Script HTML 邮件中正确处理换行符的教程

本文详细介绍了在使用 Google Apps Script 通过 GmailApp 发送 HTML 邮件时,如何解决从 Google 表格获取的文本中换行符 (\n) 转换为 HTML <br /> 标签后,却被显示为纯文本的问题。核心解决方案是在 HtmlService.evaluate().getContent() 后,手动反转 HTML 实体转义,确保 <br /> 标签能被正确解析为换行。

问题分析:HTML 邮件中的换行符挑战

在使用 google apps script 自动化发送 html 邮件时,一个常见需求是从 google 表格中读取包含多行文本的数据,并将其在邮件中以正确的换行格式呈现。通常,我们会将表格中的 \n 换行符转换为 html 的 <br /> 标签,以便在 html 内容中实现换行。然而,当这些包含 <br /> 标签的字符串通过 htmlservice.createtemplatefromfile() 和 evaluate().getcontent() 处理后,我们可能会发现 <br /> 标签并没有被浏览器解析为换行,而是直接显示为
这样的纯文本。

这个问题的根本原因在于 HtmlService.evaluate().getContent() 方法在生成最终 HTML 内容时,为了安全考虑,默认会对所有动态插入的变量内容进行 HTML 实体转义。这意味着,像 < 和 > 这样的特殊字符会被转换为 。虽然这种行为有助于防止跨站脚本攻击 (XSS),但它也阻止了我们期望的 <br /> 标签被正确解析。

考虑以下 Apps Script 代码片段,它尝试从电子表格中获取文本,将 \n 替换为 <br />,然后将其插入到 HTML 模板中:

// 假设此函数从B4单元格获取文本,并将其中的\n转换为<br />
function splitTest() {
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");
  var str = ss.getRange("B4").getValue(); // 例如 "Hello\nI'm here!"
  var array1 = str.split("\n"); // ["Hello", "I'm here!"]
  var cMessage = array1.join("<br />"); // "Hello<br />I'm here!"
  return cMessage; // 返回包含<br />的字符串
}

function sendMail() {
  var emailTemp = HtmlService.createTemplateFromFile("email");
  var cMessage = splitTest(); // 获取 "Hello<br />I'm here!"

  emailTemp.cmess = cMessage; // 将其赋值给模板变量
  var htmlMessage = emailTemp.evaluate().getContent(); // 此时 cmess 会被转义
  // htmlMessage 内部可能包含 "Hello<br />I'm here!"

  // ... 其他邮件发送逻辑
  GmailApp.sendEmail(
    "recipient@example.com",
    "Subject",
    "Please open HTML format",
    {
      htmlBody: htmlMessage, 
    }
  );
}
登录后复制

以及对应的 HTML 模板文件 email.html 中的相关部分:

<p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt; white-space:pre-line;">
  <span style="font-size: 11pt; font-family: Arial;">
    <?= cmess ?>
  </span>
</p>
登录后复制

尽管 p 标签上设置了 white-space:pre-line; 样式(它能将 \n 转换为换行),但由于 cmess 变量中的 <br /> 已经被转义为
,浏览器仍然会将其视为普通文本,从而导致换行失效。

立即学习前端免费学习笔记(深入)”;

解决方案:反转 HTML 实体转义

解决这个问题的关键在于,在 HtmlService.evaluate().getContent() 生成了转义后的 HTML 字符串之后,但在将其用于 GmailApp.sendEmail 之前,手动将 替换回 < 和 >。这样,原本被转义的 <br /> 标签就能恢复其作为 HTML 标签的功能。

我们可以使用 JavaScript 的 String.prototype.replace() 方法配合正则表达式来完成这个任务。

行者AI
行者AI

行者AI绘图创作,唤醒新的灵感,创造更多可能

行者AI 100
查看详情 行者AI
function sendMailCorrected() {
  var emailTemp = HtmlService.createTemplateFromFile("email");
  var cMessage = splitTest(); // 获取 "Hello<br />I'm here!"

  emailTemp.cmess = cMessage; 
  var htmlContent = emailTemp.evaluate().getContent(); // 此时内容为 "Hello<br />I'm here!"

  // 核心解决方案:反转HTML实体转义
  var unescapedHtmlContent = htmlContent.replace(/</g, "<");
  unescapedHtmlContent = unescapedHtmlContent.replace(/>/g, ">");

  // ... 其他邮件发送逻辑
  GmailApp.sendEmail(
    "recipient@example.com",
    "Subject",
    "Please open HTML format",
    {
      htmlBody: unescapedHtmlContent, // 使用反转后的内容
    }
  );
}
登录后复制

通过这两行 replace() 操作,htmlContent 中的所有 都会被替换回 < 和 >,从而使 <br /> 标签能够被邮件客户端正确解析并实现换行。

完整实现步骤

以下是结合了上述解决方案的完整 Apps Script 邮件发送流程:

1. Apps Script 代码 (Code.gs)

/**
 * 从电子表格指定单元格获取文本,并将内部的 '\n' 转换为 '<br />'。
 * @returns {string} 包含 HTML 换行符的字符串。
 */
function splitTest() {
  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");
  var str = ss.getRange("B4").getValue(); // 从B4单元格获取文本
  var array1 = str.split("\n"); // 按换行符分割
  var cMessage = array1.join("<br />"); // 用 <br /> 连接
  return cMessage;
}

/**
 * 发送 HTML 格式的邮件,并正确处理从电子表格获取的换行符。
 */
function sendMail() {
  // 定义列索引,方便维护
  var emailCol = 5; // 邮件地址所在列 (从0开始)
  var checkboxCol = 6; // 筛选复选框所在列 (从0开始)

  var wsRecipients = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Recipients");
  var wsSettings = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");

  // 从Settings工作表获取邮件主题和发件人名称
  var subject = wsSettings.getRange("B1").getValue();
  var senderName = wsSettings.getRange("B2").getValue();

  // 获取处理后的邮件内容字符串
  var cMessage = splitTest(); 

  // 创建 HTML 模板
  var emailTemp = HtmlService.createTemplateFromFile("email");
  emailTemp.cmess = cMessage; // 将处理后的内容赋值给模板变量

  // 评估模板并获取原始 HTML 内容(此时 <br /> 已被转义)
  var rawHtmlContent = emailTemp.evaluate().getContent();

  // 核心步骤:反转 HTML 实体转义
  var unescapedHtmlContent = rawHtmlContent.replace(/</g, "<");   
  unescapedHtmlContent = unescapedHtmlContent.replace(/>/g, ">"); 

  // 获取收件人数据并筛选
  var recipientData = wsRecipients.getRange("A2:G" + wsRecipients.getLastRow()).getValues();
  recipientData = recipientData.filter(function(row){ 
    return row[checkboxCol] === true; // 筛选出勾选的收件人
  });

  // 遍历收件人并发送邮件
  recipientData.forEach(function(row){
    var recipientEmail = row[emailCol];

    GmailApp.sendEmail(
      recipientEmail,
      subject,
      "请打开Html格式以阅读邮件,谢谢!", // 纯文本备用内容
      {
        name: senderName,
        htmlBody: unescapedHtmlContent, // 使用反转后的 HTML 内容
      }
    );
  }); 
  Logger.log("邮件发送完成。");
}
登录后复制

2. HTML 模板文件 (email.html)

<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <div align="left">
      <table style="border: none;"><colgroup><col style="width: 487px;" /><col style="width: 115px;" /></colgroup>
        <tbody>
          <!-- 邮件头部图片等内容 -->
          <tr style="height: 99pt;">
            <td style="vertical-align: top; background-color: #f4cccc;">
              <p style="line-height: 1.2; text-align: justify; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial;"><span style="border: none;"><img src="https://drive.google.com/uc?id=1rRVBhFpEbp8bjGI9jqWlbn_6K8H4djAv" width="438" height="158" /></span></span></p>
            </td>
            <td style="border-right: 1pt solid #ffffff; border-bottom: 1pt solid #ffffff; border-top: 1pt solid #ffffff; vertical-align: top; background-color: #f4cccc;">
              <p style="line-height: 1.2; text-align: right; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial;"><span style="border: none;"><img src="https://drive.google.com/uc?id=1vwNZtLRAnoRX5WuEWeojEKMf6lOOYbre" width="67" height="137" /></span></span></p>
            </td>
          </tr>
          <!-- 邮件主要内容区域 -->
          <tr style="height: 470.66pt;">
            <td style="border-left: 1pt solid #ffffff; border-right: 1pt solid #ffffff; vertical-align: top;" colspan="2">
              <!-- 可以有其他模板变量,如 cbegin, cend -->
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial;"><?= cbegin ?></span></p>
              <br />
              <!-- 插入动态内容 cmess -->
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt; white-space:pre-line;"><span style="font-size: 11pt; font-family: Arial;">
                <?= cmess ?>
              </span></p>
              <br /><br /><br />
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 11pt; font-family: Arial;"><?= cend ?></span></p>
            </td>
          </tr>
          <!-- 邮件底部信息 -->
          <tr style="height: 60.1465pt;">
            <td style="vertical-align: top; background-color: #f4cccc;">
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><strong><span style="font-size: 9pt; font-family: Arial;">Formosa Chinesische Sprachschule e.V.</span></strong></p>
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 9pt; font-family: Arial;">Schulort : Geschwister-Scholl-Gymnasium D&uuml;sseldorf</span></p>
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><span style="font-size: 9pt; font-family: Arial;">Redinghovenstra&szlig;e 41, 40225 D&uuml;sseldorf</span></p>
              <p style="line-height: 1.2; margin-top: 0pt; margin-bottom: 0pt;"><strong><span style="font-size: 9pt; font-family: Arial;">Email: </span></strong><a style="text-decoration: none;" href="mailto:info@formosa.de"><strong><span style="font-size: 9pt; font-family: Arial; color: #1155cc; text-decoration: underline; text-decoration-skip-ink: none;">info@formosa.de</span></strong></a></p>
            </td>
            <td style="border-right: 1pt solid #ffffff; border-bottom: 1pt solid #ffffff; border-top: 1pt solid #ffffff; vertical-align: top; background-color: #f4cccc;"> </td>
          </tr>
        </tbody>
      </table>
    </div>
  </body>
</html>
登录后复制

注意事项与最佳实践

  1. 安全性考量: 手动反转 HTML 实体转义会降低应用程序的安全性。如果 cMessage 变量中包含的是用户直接输入的、未经净化的数据,那么攻击者可能会注入恶意 HTML 或 JavaScript 代码(如 <script>alert('XSS');</script>),从而导致跨站脚本攻击 (XSS)。

    • 建议: 仅当您确信插入的内容是安全的(例如,它只包含您明确生成的 <br /> 标签,而不是任意用户输入)时,才使用此方法。对于用户输入,应考虑使用更严格的净化或不同的方法来处理换行(例如,仅允许 \n 并依赖 white-space: pre-line; CSS 属性)。
  2. white-space: pre-line; 的作用: HTML 模板中的 white-space:pre-line; 样式在处理 \n 字符时非常有用,它会保留文本中的换行符和空格,并在必要时折行。然而,它无法处理已经被转义的 HTML 标签。因此,当 <br /> 标签被转义为
    时,white-space:pre-line; 无法将其识别为换行标签。本教程的解决方案正是为了解决 <br /> 标签被转义的问题。

  3. 调试技巧: 在开发过程中,使用 Logger.log() 打印中间变量的值是非常有用的。例如,您可以打印 cMessage、rawHtmlContent 和 unescapedHtmlContent 来观察它们在不同阶段的内容,从而更好地理解数据流和转义过程。

    Logger.log("cMessage: " + cMessage);
    Logger.log("rawHtmlContent: " + rawHtmlContent);
    Logger.log("unescapedHtmlContent: " + unescapedHtmlContent);
    登录后复制

总结

在使用 Google Apps Script 发送 HTML 邮件并从电子表格动态插入内容时,HtmlService.evaluate().getContent() 的默认 HTML 实体转义行为可能会导致像 <br /> 这样的 HTML 标签无法正确解析。通过在发送邮件前,手动将 反转回 < 和 >,我们可以确保这些标签被邮件客户端正确渲染。在实施此解决方案时,务必注意安全性,确保只对可信内容执行此操作。

以上就是Apps Script HTML 邮件中正确处理换行符的教程的详细内容,更多请关注php中文网其它相关文章!

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号