使用 Google 脚本创建和/或更新邮件合并 Google 文档

     2023-02-22     120

关键词:

【中文标题】使用 Google 脚本创建和/或更新邮件合并 Google 文档【英文标题】:Creating and/or update mail merge Google document using Google Script 【发布时间】:2021-03-11 21:21:16 【问题描述】:

(Continuation of another thread)

我目前有一个 Google 表格,其中包含要使用模板文件合并到 Google 文档中的数据行。每行都将根据模板的布局生成一个新的 Google 文档。我当前正在运行的脚本将检查是否已经存在与 Google 表格行相关的文件(使用标题单元格进行匹配)。如果是这样,那么它将被删除,并在其位置创建一个新文档,其中包含在 Google 表格中所做的所有更改。如果它不存在,将创建一个新文档。

但是,我现在需要从外部网站链接到这些 Google 文档。使用当前脚本,这意味着如果对电子表格中的一行进行了更改,则相应的文档将被删除并重新创建,连同它的 URL,从而使网站链接无用,需要手动更改。

因此,理想情况下,我想要实现的不是删除和重新创建文档,而是更新同一个文档(如果它已经存在)。这样,文档会得到更新,并且 URL 将始终保持不变。

目前的脚本是这样的

    /*###################################################################
 * Create multiple versions of a document based on Google Sheet Data
 * and a Google Doc Template (Mailmerge)
 *###################################################################
 */

/*###################################################################
 * Main run file sets up variables for insertion into the mailMerge() 
 * function. 
 */
function mergeSheetDoc() 
  const TEMPLATE_ID = '16YfyeDjGDp-88McAtLCQQyZ1xz4QX5zEKAS09SaLkJI';//Add your Google Doc template ID
  const SS_ID = '1C5gtJCSzHMuSz-oVWEItl2EUVRDwF5iH_RVr6BxLkOU'; // Add your Google Sheet ID
  const SHEET_NAME = "data"; // Add your Google Sheet Tab name
  const MAPPED = mappedDocToSheet; // Go to Map.gs to update
  const FILE_NAME = ["Titre de la formation"] // Header IDs from your Sheet. Change to make your own file name.
  
  docMerge(TEMPLATE_ID,SS_ID,SHEET_NAME,MAPPED, FILE_NAME);



/** ###################################################################
 * Merges data from a Google Sheet into a newly created doc based on a 
 * Google Doc template. 
 * 
 * param string templateID: The id from the Google Doc template. 
 * param string ssID: The id of the Google Sheet. 
 * param string sheetName: the name of the sheet tab you are referencing.
 * param object mapped: Object array of data you mapped from your Doc template against your Google Sheet headers
 * param array fileNameDara: An array of data used to generate the file name. 
 * param string rowLen: (optional) If you want to add a number rows to create your merged documents.  
 */ 
function docMerge(templateID,ssID, sheetName, mapped, fileNameData, rowLen = "auto")
  //Get the Spreadsheet and sheet tab
  const ss = SpreadsheetApp.openById(ssID);
  const sheet = ss.getSheetByName(sheetName);
  
  //Get number of rows to process
  rowLen = (rowLen = "auto") ? getRowLen() : rowLen;
  
  //Gets the range of data in the sheet then grabs the values of the range
  const range = sheet.getRange(1,1,rowLen,sheet.getDataRange().getNumColumns());
  const matrix = range.getValues();
  
  // Searches the file mapped object and finds the corresponding number returns the column number in an array.
  const fileNameRows = getFileNameRows()
  
  
  //Loops through each row of the sheet grabbing the data from each row and putting it into a new doc.
  for(let i = 1; i < rowLen; i++)
    let row = matrix[i];
    //Get the title for the file.
    let fileName = buildFileName(row);
   
    //This query parameter will search for an exact match of the filename with Doc file type
  let params = "title='"+fileName+"' and mimeType = 'application/vnd.google-apps.document'"
    let files = DriveApp.searchFiles(params);

    if(files.hasNext())
      while (files.hasNext()) 
        //Filename exist
        var file = files.next();


        //Create a new file
        var tmpDoc = DriveApp.getFileById(templateID).makeCopy("tempfile");
        //Update the file
        updateFileData(row, tmpDoc.getId());

        //Copy contents of the new file to the existing file
        copyFileData(tmpDoc.getId(), file.getId());

        //Delete temporary file
        tmpDoc.setTrashed(true);
      
    else
      //Create a new file
      let newDoc = DriveApp.getFileById(templateID).makeCopy(fileName);
    
      updateFileData(row, newDoc.getId());
    
  
  
;

  function copyFileData(sourceDoc, destinationDoc)
   var srcParagraph = DocumentApp.openById(sourceDoc).getBody().getParagraphs();
   var dstParagraph = DocumentApp.openById(destinationDoc).getBody().getParagraphs();
   
   for(var i = 0; i<dstParagraph.length; i++)

      //Paragraph Index of description and suivantes information
      if(i==5||i==21)
        
        dstParagraph[i].editAsText().setText(srcParagraph[i].editAsText().getText());
        dstParagraph[i].setAttributes(srcParagraph[i].getAttributes());
        dstParagraph[i].setLeftToRight(true);
        dstParagraph[i].setIndentFirstLine(srcParagraph[i].getIndentFirstLine());
        dstParagraph[i].setIndentStart(srcParagraph[i].getIndentStart());
        dstParagraph[i].editAsText().setFontSize(srcParagraph[i].editAsText().getFontSize());

      
   
 

此代码还引用了一个映射脚本,可在此处找到

https://textuploader.com/18xic

【问题讨论】:

【参考方案1】:

解决方法总结:

如果文件名已经存在,则创建一个临时文档,用于替换模板文档中的 textId 标签 将临时文档的段落文本和属性复制到现有文档中。

示例修改代码:

仅包含修改/新功能。

function docMerge(templateID,ssID, sheetName, mapped, fileNameData, rowLen = "auto")
  //Get the Spreadsheet and sheet tab
  const ss = SpreadsheetApp.openById(ssID);
  const sheet = ss.getSheetByName(sheetName);
  
  //Get number of rows to process
  rowLen = (rowLen = "auto") ? getRowLen() : rowLen;
  
  //Gets the range of data in the sheet then grabs the values of the range
  const range = sheet.getRange(1,1,rowLen,sheet.getDataRange().getNumColumns());
  const matrix = range.getValues();
  
  // Searches the file mapped object and finds the corresponding number returns the column number in an array.
  const fileNameRows = getFileNameRows()
  
  
  //Loops through each row of the sheet grabbing the data from each row and putting it into a new doc.
  for(let i = 1; i < rowLen; i++)
    let row = matrix[i];
    //Get the title for the file.
    let fileName = buildFileName(row);
   
    //This query parameter will search for an exact match of the filename with Doc file type
  let params = "title='"+fileName+"' and mimeType = 'application/vnd.google-apps.document'"
    let files = DriveApp.searchFiles(params);

    if(files.hasNext())
      while (files.hasNext()) 
        //Filename exist
        var file = files.next();


        //Create a new file
        var tmpDoc = DriveApp.getFileById(templateID).makeCopy("tempfile");
        //Update the file
        updateFileData(row, tmpDoc.getId());

        //Copy contents of the new file to the existing file
        copyFileData(tmpDoc.getId(), file.getId());

        //Delete temporary file
        tmpDoc.setTrashed(true);
      
    else
      //Create a new file
      let newDoc = DriveApp.getFileById(templateID).makeCopy(fileName);
    
      updateFileData(row, newDoc.getId());
    
  
  ;
 
 function copyFileData(sourceDoc, destinationDoc)
   var srcParagraph = DocumentApp.openById(sourceDoc).getBody().getParagraphs();
   var dstParagraph = DocumentApp.openById(destinationDoc).getBody().getParagraphs();
   
   for(var i = 0; i<dstParagraph.length; i++)

      //Paragraph Index of description and suivantes information
      if(i==5||i==21)
        
        dstParagraph[i].editAsText().setText(srcParagraph[i].editAsText().getText());
        dstParagraph[i].setAttributes(srcParagraph[i].getAttributes());
        dstParagraph[i].setLeftToRight(true);
        dstParagraph[i].setIndentFirstLine(srcParagraph[i].getIndentFirstLine());
        dstParagraph[i].setIndentStart(srcParagraph[i].getIndentStart());
        dstParagraph[i].editAsText().setFontSize(srcParagraph[i].editAsText().getFontSize());

      
   
 

它有什么作用?

    如果找到文件名,请根据电子表格中的更新信息创建一个临时文档 将临时文档中的特定段落复制到现有文档中 使用setTrashed()方法删除临时文档。

【讨论】:

我似乎遇到了 docMerge 或 mergeSheetDoc 的以下错误“ReferenceError: getRowLen is not defined”。我已经修改了我的初始帖子以显示脚本我的结束 你需要包括你所有的功能,我没有把完整的代码放在答案中。我刚刚修改了 docMerge() 并定义了一个新函数 copyFileData() 我明白了,我可以看到它在工作,这太棒了。我现在将测试多行并进行测试,以便它为新行创建文档 注意,如果您遇到任何其他问题,请告诉我 似乎为新行创建新文档并使用更新的内容更新现有文档。它完全按照我的需要工作。再次感谢你。我非常感激。很高兴看到它工作。赞成并接受回答:)

通过 Web 应用程序通过电子邮件获取损坏或空白文件 - Google 脚本

】通过Web应用程序通过电子邮件获取损坏或空白文件-Google脚本【英文标题】:CorruptedorBlankfileisgettingbyemailthroughWebapp-Googlescript【发布时间】:2020-06-1408:17:08【问题描述】:问题以下google脚本运行正常,但通过电子邮件发送的上传... 查看详情

使用 Google Apps 脚本创建 Etag 字符串

】使用GoogleApps脚本创建Etag字符串【英文标题】:CreateEtagstringusingGoogleappsscript【发布时间】:2021-10-1221:18:35【问题描述】:我使用GooglepeopleAPI更新联系人。我保存创建的联系人的资源名称,当我更新联系人时,我只使用此代码Peo... 查看详情

使用特定变量在google表单提交上发送电子邮件(代码片段)

我对谷歌脚本非常新,我需要你的帮助。我有一个表单,在它拥有的字段中,它有一个名为owner的字段,这只是一个名称。我需要创建一个脚本,以便在提交表单时向所有者字段中列出的人员发送通知。我知道如何直接在脚本上... 查看详情

如何合并两个 Firebase 帐户(一个使用电子邮件创建,另一个使用电话号码创建)?

】如何合并两个Firebase帐户(一个使用电子邮件创建,另一个使用电话号码创建)?【英文标题】:HowtomergetwoFirebaseaccounts(onecreatedwithemailandanotheronewithphonenumber)?【发布时间】:2022-01-2401:32:02【问题描述】:这是场景:用户使用电... 查看详情

如何使用 Mailchimp 和/或 Mandrill 从电子邮件标题中删除 *|MC_PREVIEW_TEXT|*

】如何使用Mailchimp和/或Mandrill从电子邮件标题中删除*|MC_PREVIEW_TEXT|*【英文标题】:Howtoremove*|MC_PREVIEW_TEXT|*fromemailtitleusingMailchimpandorMandrill【发布时间】:2017-12-2913:45:47【问题描述】:我创建了一个电子邮件模板,其中包含MailChimp... 查看详情

我可以在 Google 表格中使用脚本或参考附加组件的功能吗?

】我可以在Google表格中使用脚本或参考附加组件的功能吗?【英文标题】:CanIusescriptsalongsideorinreferencetoanAdd-on\'sfunctionsinGoogleSheet?【发布时间】:2021-05-1312:11:30【问题描述】:我创建了一个Google表格,我在其中使用了AutocratAdd-on... 查看详情

如何使用 Google Apps 脚本将 PDF 正文格式化为看起来像电子邮件?

】如何使用GoogleApps脚本将PDF正文格式化为看起来像电子邮件?【英文标题】:HowtoformatPDFbodytolookliketheemailusingGoogleAppsScript?【发布时间】:2021-12-2716:59:07【问题描述】:下面的代码确实获得了表单响应,并使用格式如下的正文通... 查看详情

使用 Terraform 和启动脚本创建专用网络 - Google Cloud Platform

】使用Terraform和启动脚本创建专用网络-GoogleCloudPlatform【英文标题】:CreateprivatenetworkwithTerraformwithstartingscript-GoogleCloudPlatform【发布时间】:2019-11-0902:25:37【问题描述】:最近使用GCP开始使用Terraform,我想完成一个练习:使用单... 查看详情

使用 Google Apps 脚本删除 Gmail 电子邮件的附件

】使用GoogleApps脚本删除Gmail电子邮件的附件【英文标题】:RemoveanattachmentofaGmailemailwithGoogleAppsScript【发布时间】:2018-03-0803:29:57【问题描述】:使用GoogleApps脚本(http://script.google.com),我从thedocs知道如何发送、转发、移动到垃圾... 查看详情

如何在将应用程序脚本呈现给用户浏览器之前使用应用程序脚本授权 Google 表单

】如何在将应用程序脚本呈现给用户浏览器之前使用应用程序脚本授权Google表单【英文标题】:HowtoauthorizeGoogleFormusingappscriptbeforeitrenderingittotheuserbrowser【发布时间】:2020-06-2708:59:48【问题描述】:我创建了一个Google表单和一个Go... 查看详情

无法向 Google 应用脚本授予授权或许可

...间】:2018-08-2507:46:49【问题描述】:为什么我无法向我也使用同一个Google帐户创建的GoogleApps脚本授予权限/授权?Google似乎不相信自己将自己的GoogleApps脚本与自己的电子表格一起使用。这是破坏一切的代码行。如果这条线不存在 查看详情

Firebase 使用 Google 帐户覆盖登录

】Firebase使用Google帐户覆盖登录【英文标题】:FirebaseOverwritesSigninwithGoogleAccount【发布时间】:2017-04-0713:43:19【问题描述】:文档中似乎没有提到这一点,我发现的只是this和this,我想在这里确认一下:如果现有帐户具有相同的电... 查看详情

允许其他用户执行 google 电子表格脚本

...颜色、设置行的更新和创建日期以及其他一些控件。当我使用自己的用户编辑它时,一切正常,但现在设置的电子表格设置为公开(通过链接访问),任何其他访问电子表 查看详情

如何使用 Google Apps 脚本获取 Gmail 用户的个人资料图片?

】如何使用GoogleApps脚本获取Gmail用户的个人资料图片?【英文标题】:HowtogetaGmailuser\'sprofilepictureusingGoogleAppsScript?【发布时间】:2021-11-0112:29:04【问题描述】:我想在我们的域工作区中更新用户的电子邮件签名。我想使用用户的... 查看详情

在输出前拼合邮件合并的文档

...put【发布时间】:2018-11-2305:51:50【问题描述】:我遇到了使用pythonuno脚本创建的邮件合并文件的问题。使用mailmerge向导在LibreOffice中运行mailmerge就像在隐藏字段中一样,文档中的其他字段被展平/执行,生成的文档具有正确的最终... 查看详情

我需要结合 MS Access 和 MS Outlooks 数据收集功能创建自定义(邮件合并)电子邮件

...eature【发布时间】:2012-12-0518:03:07【问题描述】:我正在使用MicrosoftAccess2007和MicrosoftOut 查看详情

使用 Google 脚本从 MYSQL 更新 google 电子表格

】使用Google脚本从MYSQL更新google电子表格【英文标题】:UpdatingthegooglespreedsheetfromMSSQLusingGoogleScripts【发布时间】:2016-09-0309:48:28【问题描述】:我正在尝试使用谷歌应用脚​​本将MSSQL连接到谷歌电子表格。这是我的应用脚本代... 查看详情

使用 Google Script 永久删除我的电子邮件的脚本

】使用GoogleScript永久删除我的电子邮件的脚本【英文标题】:ScripttopermenantlydeletemyemailswithGoogleScript【发布时间】:2016-07-2212:05:02【问题描述】:这个Gmail.Users.Messages.remove(userId,id)是如何工作的?电子邮件的ID是什么?永久删除电... 查看详情