【问题标题】:How to preserve formatting of google spreadsheet in mail merge?如何在邮件合并中保留谷歌电子表格的格式?
【发布时间】:2022-09-23 13:20:55
【问题描述】:

我想发送一封电子邮件,其中包含谷歌电子表格内容作为带有格式的正文。我从here 获取了参考,但它仅适用于单元格\'A1\',我希望它适用于完整的数据范围。发送电子邮件时如何保留所有格式?

  • 请提供minimal reproducible example。在电子邮件中获取格式的唯一方法是发送 html 电子邮件,但当然这不会保留格式。您将不得不重新创建它。

标签: javascript google-apps-script google-sheets


【解决方案1】:

您需要使用getRichTextValues 来获取给定范围内每个单元格的所有富文本值,然后迭代它们中的每一个。然后将它们编译并格式化成表格。

另外,由于脚本没有包含背景,所以我也添加了它。请参阅下面的工作脚本、示例数据和输出。

脚本修改:

const sendRichEmail = () => {
  // update cellAddress if needed, or use getDataRange below instead.
  const cellAddress = 'A1:B2';
  const sheetName = 'Mail Merge';
  const recipient = 'test@email.com';

  const richTextValue = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(sheetName)
    .getRange(cellAddress)
    .getRichTextValues();

  // Adding background color
  const backgroundColors = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(sheetName)
    .getRange(cellAddress)
    .getBackgrounds();

  /* Run is a stylized text string used to represent cell text.
     This function transforms the run into HTML with CSS
   */
  const getRunAsHtml = (richTextRun) => {
    const richText = richTextRun.getText();

    // Returns the rendered style of text in a cell.
    const style = richTextRun.getTextStyle();

    // Returns the link URL, or null if there is no link
    // or if there are multiple different links.
    const url = richTextRun.getLinkUrl();

    const styles = {
      color: style.getForegroundColor(),
      'font-family': style.getFontFamily(),
      'font-size': `${style.getFontSize()}pt`,
      'font-weight': style.isBold() ? 'bold' : '',
      'font-style': style.isItalic() ? 'italic' : '',
      'text-decoration': style.isUnderline() ? 'underline' : '',
    };

    // Gets whether or not the cell has strike-through.
    if (style.isStrikethrough()) {
      styles['text-decoration'] = `${styles['text-decoration']} line-through`;
    }

    const css = Object.keys(styles)
      .filter((attr) => styles[attr])
      .map((attr) => [attr, styles[attr]].join(':'))
      .join(';');

    const styledText = `<span style='${css}'>${richText}</span>`;
    return url ? `<a href='${url}'>${styledText}</a>` : styledText;
  };

  // Format the data that will work on multiple cells. 
  // Edit table properties if needed
  var finalBody = `<html><body><table border='1px'>`;
  /* Returns the Rich Text string split into an array of runs,
  wherein each run is the longest possible
  substring having a consistent text style. */
  for (var i = 0; i < richTextValue.length; i++) {
    finalBody += '<tr>';
    for (var j = 0; j < richTextValue[i].length; j++) {
      finalBody += `<td bgcolor='${backgroundColors[i][j]}'>`;
      finalBody += richTextValue[i][j].getRuns().map((run) => getRunAsHtml(run)).join('');
      finalBody += '</td>';
    }
    finalBody += '</tr>';
  }
  finalBody += '</table></body></html>';

  MailApp.sendEmail({to: recipient, subject: 'Rich HTML Email', htmlBody: finalBody});
};

样本数据:

输出:

笔记:

  • 我还对其进行了格式化,以将数据作为表格发送。如果需要,请随意修改表的属性。
  • 要减小单元格之间的间距,请使用以下命令:

单元格间距 0:

var finalBody = `<html><body><table border='1' cellspacing='0'>`;

输出:

参考:

编辑:

  • 对于日期对象和数字,getRichTextValues 是一个限制。或者,您可以使用getDisplayValues 插入这些值,但由于getTextStyles 不返回任何内容,因此不会具有正确的文本样式。

修改脚本:

const sendRichEmail = () => {
  const sheetName = 'Sheet1';
  const recipient = 'test@email.com';

  const richTextValue = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(sheetName)
    .getDataRange()
    .getRichTextValues();

  // get string equivalent of the data
  const values = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(sheetName)
    .getDataRange()
    .getDisplayValues();

  const backgroundColors = SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName(sheetName)
    .getDataRange()
    .getBackgrounds();

  // pass the current index of row and column
  const getRunAsHtml = (richTextRun, i, j) => {
    var richText = richTextRun.getText();
    // if richText is empty, assign value from getDisplayValues
    if (!richText)
      richText = values[i][j];
    const style = richTextRun.getTextStyle();
    const url = richTextRun.getLinkUrl();

    const styles = {
      color: style.getForegroundColor(),
      'font-family': style.getFontFamily(),
      'font-size': `${style.getFontSize()}pt`,
      'font-weight': style.isBold() ? 'bold' : '',
      'font-style': style.isItalic() ? 'italic' : '',
      'text-decoration': style.isUnderline() ? 'underline' : '',
    };

    if (style.isStrikethrough()) {
      styles['text-decoration'] = `${styles['text-decoration']} line-through`;
    }

    const css = Object.keys(styles)
      .filter((attr) => styles[attr])
      .map((attr) => [attr, styles[attr]].join(':'))
      .join(';');

    const styledText = `<span style='${css}'>${richText}</span>`;
    return url ? `<a href='${url}'>${styledText}</a>` : styledText;
  };

  var finalBody = `<html><body><table border='1px'>`;
  for (var i = 0; i < richTextValue.length; i++) {
    finalBody += '<tr>';
    for (var j = 0; j < richTextValue[i].length; j++) {
      finalBody += `<td bgcolor='${backgroundColors[i][j]}'>`;
      // pass i and j into getRunAsHtml
      finalBody += richTextValue[i][j].getRuns().map((run) => getRunAsHtml(run, i, j)).join('');
      finalBody = finalBody.replace(/\n/g, '<br>');
      finalBody += '</td>';
    }
    finalBody += '</tr>';
  }
  finalBody += '</table></body></html>';


  MailApp.sendEmail({ to: recipient, subject: 'Rich HTML Email', htmlBody: finalBody });
};

输出:

【讨论】:

  • 你好。首先感谢您的帮助。您修改后的代码运行良好,但脚本的唯一问题是没有捕获电子表格的数值。如需参考,请参阅附件sample sheet
  • 嗨@SumitSingh,遗憾的是,这是richtextvalues 的当前限制。它们不返回日期对象和数字。见related post and answer。但是,您可以使用 getDisplayValues 来获取这些值。问题是它不会获得文本样式,因为getTextStyle 没有返回任何内容。我将很快更新答案,以包括那些带有日期/数字的单元格。
  • 我现在已经更新了答案,你应该看到编辑底部的部分。 @SumitSingh
  • 嗨@Octavia Sima,感谢您的帮助。我稍微修改了代码以将数字格式化为文本,现在它按预期工作。
  • 嗨@Octavia Sima,我们也可以获取合并单元格格式吗?我的意思是,如果我们合并 2 个单元格并希望按照电子邮件中的格式选择它们,这可能吗?
【解决方案2】:

当我遇到同样的问题时,本教程对我有帮助: https://www.youtube.com/watch?v=fx6quWRC4l0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 2015-12-25
    相关资源
    最近更新 更多