Как мне отправить письмо из Google Spreadsheet в Google Document?


20

Microsoft Excel и Microsoft Word позволяют легко объединять строки из электронной таблицы в страницы в файле Word. Это традиционно использовалось для изготовления бумажных рассылок. Как я могу сделать то же самое с Google Drive / Google Docs?

Существует множество шаблонов, предлагающих объединение электронной почты с электронной таблицей. Как мне объединить почту с Gmail? но это не то, что я после.


Вы пытались скопировать / вставить?
— Джейкоб Ян Туинстра

4
Копировать / вставить для 10000 строк? Спасибо, не надо. Word / Excel будет хорошо.
— Брайс

Ответы:


8

Для этого вам нужно будет написать скрипт Google Apps . Вы можете позволить первой строке электронной таблицы быть именами полей и создать шаблон документа, на который ссылаются поля, как [FIELD].

Так что если ваша таблица выглядит так:

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

... вы можете иметь шаблон документа, как

Уважаемый [ИМЯ], живущий в [УЛИЦА], [ГОРОД] [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();
}

1
Почему вы решили использовать автономное приложение, а не одну сборку из таблицы? Это сделает это намного проще для ОП. Во-вторых, почему в скрипте так много вызовов Logger? Это сделает скрипт слишком плотным.
— Джейкоб Ян Туинстра

В архиве скриптов Google раньше были какие-то предварительно собранные скрипты ... есть ли какая-то конкретная причина, по которой ваша или другая не будет загружена туда?
— Брайс

До сих пор не замечал комментария Джейкоба, и, как он говорит, это, вероятно, должен быть сценарий для электронных таблиц, а не отдельный. Я посмотрю, смогу ли я найти время, чтобы поработать над этим, и отправлю его в галерею скриптов.
— Видар С. Рамдал

5
Видар Это отличный ответ. Я очистил его, обновил некоторые устаревшие методы и избавился от ненужных функций, а также изменил его для запуска из электронной таблицы, как предложила @JacobJanTuinstra. Затем я понял, что есть ошибка, которая нарушает работу изображений , и я также сделал обходной путь для этой ошибки. Я чувствую, что теперь это достаточно хорошо, чтобы надеть Github. Я разместил его там и в нем предоставил ссылку на ваш ответ в качестве стартовой версии работы.
— хади

@hadi Хорошая работа!
— Видар С. Рамдал

6

С помощью новых надстроек на Google Диске доступно несколько возможностей слияния, например «Ещё одно слияние».

Чтобы использовать его, вы должны иметь «новую» таблицу Google и установить надстройку через меню надстроек:

Снимок экрана из таблиц Google

Ищите Mail merge, и вы найдете несколько вариантов.


Обратите внимание, что он ограничен 100 электронными письмами в день (бесплатно).
— пиксель

5

В собственном посте Google объясняется, как настроить данные фида на одном листе, а шаблон - на другом, а не как таблицу Google + Документ Google: 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:


просто наткнулся на этот GIST в качестве другого примера gist.github.com/mhawksey/1170597
— drzaus

3
Этот вопрос специально исключает слияние электронной почты.
— Брайс

3

Я рекомендую AutoCrat . Это надстройка Google с отличным волшебным интерфейсом, который поможет вам настроить слияние.


1

У меня была такая же проблема, и я пытался решить ее с помощью ответа Видара, но из-за устаревшего решения это не сработало.

Фактическое решение - ссылка @hadi в комментарии к ответу Видара.

Видар :
Это отличный ответ. Я очистил его, обновил некоторые устаревшие методы и избавился от ненужных функций, а также изменил его для запуска из электронной таблицы, как предложено @ JacobJanTuinstra . Затем я понял, что есть ошибка, которая нарушает работу изображений, и я также сделал обходной путь для этой ошибки. Я чувствую, что теперь это достаточно хорошо, чтобы надеть Github. Я разместил его там и в нем предоставил ссылку на ваш ответ в качестве стартовой версии работы.
- хади 4 марта '15 в 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-Sheet.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.