使用Microsoft Excel和Microsoft Word,可以轻松地将电子表格中的行合并到Word文件中的页面中。传统上,这是用来制作纸质邮件的。

有很多模板可以提供电子表格到电子邮件的邮件合并:
如何与Gmail合并邮件?但这不是我想要的。

评论

您是否尝试过复制/粘贴?

复制/粘贴10,000行?不用了,谢谢。 Word / Excel就可以了。

#1 楼

您将需要为此编写一个Google Apps脚本。您可以将电子表格的第一行作为字段名称,并创建一个模板文档,在其中引用诸如[FIELD]之类的字段。

因此,如果您的电子表格看起来像:

NAME  |  STREET             | ZIP    | TOWN
---------------------------------------------
Vidar | Karl Johans gate 15 | 0200   | Oslo
John  | 3021 Arlington Road | 123456 | Memphis, TN


...您可能会有一个模板文档,例如


亲爱的[NAME],住在[STREET],[TOWN] [ZIP] ...


您的脚本将需要创建一个新的空文档,并为电子表格中的每一行添加一个新页面,并使用行值搜索/替换字段占位符。 >
我有一个工作版本,可能需要一些改进。可以在这里调用。它将创建一个名为“邮件合并结果”的新文档。

您可以将其用作自己的脚本的起点。让我知道您是否感兴趣,或者我可以花更多时间完成脚本。

脚本内容:

var selectedTemplateId = null;
var selectedSpreadsheetId = null;
var spreadsheetDocPicker = null;
var templateDocPicker = null;

function mailMerge(app) {
  var app = UiApp.createApplication().setTitle("Mail Merge");
  templateDocPicker = createFilePicker(app, "Choose template", 
         UiApp.FileType.DOCUMENTS, "templateSelectionHandler"); 
  templateDocPicker.showDocsPicker();
  return app;
};

function createFilePicker(app, title, fileType, selectionHandlerName) {
  Logger.log("Creating file picker for " + fileType);
  var docPicker = app.createDocsListDialog();
  docPicker.setDialogTitle(title);
  docPicker.setInitialView(fileType);
  var selectionHandler = app.createServerHandler(selectionHandlerName);
  docPicker.addSelectionHandler(selectionHandler);
  return docPicker;
}

function templateSelectionHandler(e) {
  var app = UiApp.getActiveApplication();
  selectedTemplateId = e.parameter.items[0].id;
  UserProperties.setProperty("templateId", e.parameter.items[0].id);
  Logger.log("Selected template: " + selectedTemplateId);
  var spreadsheetDocPicker = createFilePicker(app, "Choose spreadsheet", 
        UiApp.FileType.SPREADSHEETS, "spreadsheetSelectionHandler");
  spreadsheetDocPicker.showDocsPicker();
  return app;
}

function spreadsheetSelectionHandler(e) {
  var app = UiApp.getActiveApplication();
  UserProperties.setProperty("spreadsheetId", e.parameter.items[0].id);
  selectedSpreadsheetId = e.parameter.items[0].id;
  Logger.log("Selected spreadsheet: " + selectedSpreadsheetId);
  doMerge();
  return app;
}

function doMerge() {
  var selectedSpreadsheetId = UserProperties.getProperty("spreadsheetId");
  var selectedTemplateId = UserProperties.getProperty("templateId");
  Logger.log("Selected spreadsheet: " + selectedSpreadsheetId);
  var sheet = SpreadsheetApp.openById(selectedSpreadsheetId);
  Logger.log("Spreadsheet opened");
  Logger.log("Opening template: " + selectedTemplateId);
  var template = DocumentApp.openById(selectedTemplateId);
  Logger.log("Template opened");
  var templateFile = DocsList.getFileById(selectedTemplateId);
  var templateDoc = DocumentApp.openById(templateFile.getId());
  //var mergedFile = templateFile.makeCopy();
  var mergedDoc = DocumentApp.create("Result of mail merge");
  var bodyCopy = templateDoc.getActiveSection().copy();
  Logger.log("Copy made");
  var rows = sheet.getDataRange();
  var numRows = rows.getNumRows();
  var values = rows.getValues();
  var fieldNames = values[0];

  for (var i = 1; i < numRows; i++) {
    var row = values[i];
    Logger.log("Processing row " + i + " " + row);
    var body = bodyCopy.copy();
    for (var f = 0; f < fieldNames.length; f++) {
      Logger.log("Processing field " + f + " " + fieldNames[f]);
      Logger.log("Replacing [" + fieldNames[f] + "] with " + row[f]);
      body.replaceText("\[" + fieldNames[f] + "\]", row[f]);
    }
    var numChildren = body.getNumChildren();
    for (var c = 0; c < numChildren; c++) {
      var child = body.getChild(c);
      child = child.copy();
      if (child.getType() == DocumentApp.ElementType.HORIZONTALRULE) {
        mergedDoc.appendHorizontalRule(child);
      } else if (child.getType() == DocumentApp.ElementType.INLINEIMAGE) {
        mergedDoc.appendImage(child);
      } else if (child.getType() == DocumentApp.ElementType.PARAGRAPH) {
        mergedDoc.appendParagraph(child);
      } else if (child.getType() == DocumentApp.ElementType.LISTITEM) {
        mergedDoc.appendListItem(child);
      } else if (child.getType() == DocumentApp.ElementType.TABLE) {
        mergedDoc.appendTable(child);
      } else {
        Logger.log("Unknown element type: " + child);
      }
   }
   Logger.log("Appending page break");
   mergedDoc.appendPageBreak();
   Logger.log("Result is now " + mergedDoc.getActiveSection().getText());
  }
}

function testMerge() {
  UserProperties.setProperty("templateId", 
    "1pAXWE0uklZ8z-O_Tejuv3pWSTiSv583ptUTGPt2Knm8");
  UserProperties.setProperty("spreadsheetId", 
    "0Avea1NXBTibYdFo5QkZzWWlMYUhkclNSaFpRWUZOTUE");
  doMerge();
}


function doGet() {
  return mailMerge();
}


评论


您为什么选择使用独立应用程序,而不使用电子表格中的一个版本?这将使OP更加容易。其次,为什么脚本中有那么多Logger调用?它将使脚本过于密集。

–雅各布·扬·图恩斯特拉(Jacob Jan Tuinstra)
13年2月6日在16:47

Google脚本档案曾经有一些预先构建的脚本...您或您的另一个脚本是否有任何特定原因不会上传到那里?

–布莱斯
13年2月24日在11:42

直到现在都没有注意到Jacob的评论,正如他所说,它应该应该是电子表格脚本而不是独立的脚本。我将看看是否有时间进行处理,然后将其提交到“脚本”库。

– Vidar S. Ramdal
13年2月25日在9:51

Vidar这是一个很好的答案。我清理了它,并更新了一些不推荐使用的方法,摆脱了不必要的功能,并按照@JacobJanTuinstra的建议将其修改为可以在电子表格中运行。然后我意识到存在一个破坏图像的错误,并且我也针对该错误做出了解决方法。我觉得现在可以放在Github上了。我已经将其张贴在此处,并在其中提供了指向您回复的链接,作为该作品的起始版本。

–哈迪
2015年3月4日19:24



@hadi干得好!

– Vidar S. Ramdal
2015年3月4日19:41

#2 楼

通过新的Google云端硬盘加载项,可以使用多种邮件合并功能,例如“还可以合并邮件”。

要使用它,您必须具有“新” Google Spreadsheet,然后安装通过“附加组件”菜单添加:



搜索Mail merge,您将找到几个选项。

评论


请注意,每天限制为100封电子邮件(免费)。

– Pixeline
15年1月4日在20:26

#3 楼

Google自己的帖子解释了如何在一个工作表中设置提要数据,而在另一工作表中而不是Google Spreadsheet + Google Doc中设置模板:
https://developers.google.com/apps-script/articles/mail_merge

但是,最终结果是让MailApp发送电子邮件,而不是所需的“克隆”文档。我建议结合使用本教程和@Vidar的答案,以替换方式:

MailApp.sendEmail(rowData.emailAddress, emailSubject, emailText);




var mergedDoc, bodyContent,
    // you'd have to make the DocumentTitle column for the following
    newTitle = rowData.DocumentTitle /* or set to a static title, etc */;

// make a copy of the template document -- see http://stackoverflow.com/a/13243070/1037948
// or start a new one if you aren't using the template, but rather text from a template field
if( usingTemplateFile ) {
    mergedDoc = templateDoc.makeCopy(newTitle)
    bodyContent = mergedDoc.getBody();
} else {
    mergedDoc = DocumentApp.create(newTitle);
    bodyContent = mergedDoc.getBody();
    bodyContent.setText(templateFieldContents);
}

// tweak the fillInTemplateFromObject to accept a document Body and use .replaceText() instead of .match as in mailmerge example
// .replaceText see https://developers.google.com/apps-script/reference/document/body#replaceText(String,String)
fillInTemplateFromObject(bodyContent, rowData);

// no append needed?


随机AppScripts参考:


https://developers.google.com/apps-script/reference/document/body#replaceText(String,String)
https ://developers.google.com/apps-script/reference/document/body#copy()
https://developers.google.com/apps-script/reference/document/body#setText(String)


评论


刚刚遇到了这个GIST,这是另一个示例gist.github.com/mhawksey/1170597

–drzaus
13年7月29日在18:52

该问题专门排除了电子邮件合并。

–布莱斯
13年12月8日在8:50

#4 楼

我建议使用autoCrat。这是一个Google加载项,具有出色的向导式界面,可帮助您设置合并。

#5 楼

我遇到了同样的问题,并尝试用Vidar的答案解决它,但是由于弃用,它无法正常工作。

实际的解决方案是@hadi在对Vidar的回答的评论中的链接。


Vidar:这是一个很好的答案。我清理了它,并更新了一些不推荐使用的方法,摆脱了不必要的功能,并按照@JacobJanTuinstra的建议将其修改为可以在电子表格中运行。然后我意识到存在一个破坏图像的错误,并且我也针对该错误做出了解决方法。我觉得现在可以放在Github上了。我已将其张贴在此处,并在其中提供了指向您回复的链接,作为该作品的起始版本。
– hadi 2015年3月4日,19:24“


https ://github.com/hadaf/SheetsToDocsMerge:

  A Google Apps Script that merges information from a Google Sheet into a 
  Template created by Google Docs. The result is a new Google Docs file 
  that is populated by the Sheet data.


只需按照Readme上的步骤进行操作,我便可以从模板Google-Doc创建合并文档和一个Google表格。

#6 楼

从2019年2月开始,除了其他答案中提到的Google Apps脚本外,您现在还可以使用Google Docs REST API进行此操作。

这是我写的博客文章,链接到视频我创建的文档和一个有效的(Python)示例应用程序,完全按照OP的要求进行操作,将来自Google表格的数据通过邮件合并到通过Google文档创建的套用信函中。

具体来说,您需要3 Google API,以及该示例中的代码如下:


使用Google Sheets API读取合并数据

循环-对于每个数据行:


使用Google Drive API复制模板表格信函

构建邮件合并搜索n替换请求
使用Google Docs API更新复制的模板



如果您是Google API的新手,建议您观看此视频,然后观看本视频,最后观看本视频,以了解如何使用它们。要了解有关一般如何使用Google API的更多信息,请查看我的博客以及我制作的各种Google开发人员视频(系列1和系列2)。这些代码示例使用Python,但是如果您不是Python开发人员,请假装它是伪代码,因为Google APIs Client Libraries支持大多数语言。 :-)

#7 楼

经过一会儿的磨合之后,我构建了https://www.easymailmerge.com/来做到这一点:将Google表格(或CSV文件)合并到Google文档中,然后给我PDF。目前,它使用Moustache样式的模板语法{{field name}},并支持文本,电子邮件地址,URL和图像。

我设置了付费方式:没有订阅,只是按使用付费。您可以预览合并,以确保合并能够满足您的需要,然后再付款。完成后,您将下载所有合并的PDF文件,您可以保存和打印或进行其他操作。

免责声明:我是这样写的。