Создание статистики и управление рассылки писем
в Google Docs (с разных аккаунтов) на основе FormEmailer
Мы, Большой Брат Ltd., решили создать статистику результатов рассылки посредством скрипта — шаблона FormEmailer. Расскажем, как это делалось.
Для любопытных сразу покажу, к чему мы стремимся.
Выглядеть это будет примерно так:

Рисунок 1: Итоговый вид разработки.
Теперь приступим к самому интересному — реализации.
Для работы с рассылкой будем использовать скрипт — шаблон FormEmailer. Он многофункционален, гибок в настройке и при небольших усилиях становится действительно мощным инструментом.
Создаем таблицу “Рассылка” в Google Docs.
Нажимаем “Вставка” -> “Скрипт”, находим FormEmailer от hgabreu, нажимаем Install. Авторизируемся, давая право использовать свой календарь.

После установки в меню появится пункт Form Emailer.

При нажатии на него вы увидите в меню Install. Нажимаем на него и получаем форму с выбором языка и Листа с данными (сюда вы будете собирать базу для рассылки).
Оговорюсь, в БАЗУ ДЛЯ РАССЫЛКИ мы включаем исключительно своих подписчиков.
Также важно учитывать и специфики ограничений Google таблиц. Поэтому настоятельно рекомендуем ознакомиться с данным разделом Читать тут
ВАЖНО: Для того чтобы все создалось без ошибок и проблем, лист должен содержать хотя бы названия колонок (иметь шапку).

Если база для рассылки у Вас больше пары тысяч, нужно использовать дополнительные аккаунты и проделывать в них те же манипуляции.
Если у Вас возникли проблемы с установкой, зайдите на сайт программы. Сайт
В итоге, мы получаем инструмент для массовой рассылки с лимитом на использование аккаунта Gmail — 500 писем в день. Желательно, не использовать максимальный лимит из-за риска получить бан.
Так выглядят наши документы:

Рисунок 2: Виды листов
1. — лист “Data”; 2. — лист “FormEmailer”; 3. — лист “05/2012”; 4. — лист “Report”.
При создании, из Install вы получите 2 вкладки:
1) Data — наша база. Этот документ Вы будете использовать в качестве базы рассылки.
2) FormEmailer — шаблон и основные настройки рассылки.
Создаем еще один лист — “Report”, а лист архива мы создадим с помощью программы. В него будут собираться все отчеты об отправке.

Итак, приступим к приведению скрипта FormEmailer-a под себя. Версия не имеет значения.
Открываем редактор скриптов, откроется код FormEmailera.
С помощью Ctrl+F найдем функцию processManually и впишем перед ней наш код.
Для того, чтобы все работало, необходимо чтобы код был таким же, как и у меня.
Данный код добавит в наш документ лист архива с названием текущего месяца и года в виде “05/2012” — месяц/год.

var thisMonth = Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "MM/yyyy"); var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(thisMonth); if ( !outputSheet ) { SpreadsheetApp.getActiveSpreadsheet().insertSheet(thisMonth); var outputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(thisMonth); }
Добавляем счетчик отправленных писем.

var count_send_email = 0;
Создаем в колонках ячейки с датой и копированием в архив для отсчета и комментируем текст, который отвечает за статистические данные.

var thisDate_send_email = Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "MM/dd/yyyy"); var time_send_email = Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "MM/dd/yyyy hh:mm:ss"); c.fs.getRange(line,1).setValue("Email sent, " + time_send_email); c.fs.getRange(line,2).setValue(thisDate_send_email); var dataHeight = c.fs.getDataRange().getHeight(); var dataWidth = c.fs.getDataRange().getWidth(); // Check if there free rows in the output sheet if(outputSheet.getDataRange().getHeight()==outputSheet.getMaxRows()) outputSheet.insertRowAfter(outputSheet.getMaxRows()); Logger.log("height:"+outputSheet.getDataRange().getHeight()); Logger.log("max: "+outputSheet.getMaxRows()) count_send_email++; c.fs.getRange(line, 1, 1, dataWidth).moveTo(outputSheet.getRange(outputSheet.getDataRange().getHeight()+1, 1)); c.fs.deleteRow(line); } catch(e) { status.push(repl_(T.statusError, s.qtt == 1 ? '' : i+1, e)); c.err.push(repl_(T.mailError, s.qtt == 1 ? '' : i+1, e, line)); } } else { status.push(T.statusQuota); if( c.err.length == 0 || !startsWith_(c.err[c.err.length-1], T.statusQuota) ) c.err.push(t.statusQuota+'. '+new Date()); break; } } outputSheet.getRange(outputSheet.getLastRow(),5).setValue(count_send_email); /* c.fs.getRange(line,1).setValue(status.join('; ')); if( c.fl && line != 2 ) { if( s.closure === 'values' ) all.setValues([values]); else if( s.closure === 'clear' ) all.clearContent(); //else formulas > just leave them there }*/
Вдаваться в подробности написания скрипта мы не будем.
Если возникнут вопросы, пишите — ответим.
На этом доработка FormEmailer-a почти закончена.
Приступаем к статистике.
Создадим файл, где и будет собираться статистика.
Далее, нам необходимо сделать так, чтобы суммарная таблица “Report” копировалась в сводный документ Статистика
Для этого, создаем новую функцию updateData в скрипте FormEmailera.
В конце кода, примерно на строке 1164, после закрывающей скобки предыдущей функции добавляем следующее:
var SOURCE_SPREADSHEET_ID = "ключ листа, с которого будем копировать"; var SOURCE_SHEET_NAME = "название копируемого листа"; var DESTINATION_SPREADSHEET_ID = "ключ листа, куда будем копировать"; var DESTINATION_SHEET_NAME = "название листа, куда будем копировать"; function updateData() { try { var sourceSheet = SpreadsheetApp.openById(SOURCE_SPREADSHEET_ID).getSheetByName(SOURCE_SHEET_NAME); if(sourceSheet!=null) { var sourceData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SOURCE_SHEET_NAME).getDataRange().getValues(); var destinSheet = SpreadsheetApp.openById(DESTINATION_SPREADSHEET_ID).getSheetByName(DESTINATION_SHEET_NAME); if(destinSheet!=null) destinSheet.getRange(1, 1, sourceData.length, sourceData[0].length).setValues(sourceData); else throw new Error("Destination sheet not found."); } else throw new Error("Source sheet not found."); } catch(e) { Logger.log(e.message); Browser.msgBox(Logger.getLog()); } }
Для того чтобы наш лист сводной статистики приобрел окончательный вид, пропишем формулы для сбора количества писем категории отправлено / ожидает отправки.
ОТПРАВЛЕНО:
=(ARRAYFORMULA(SUMIF('05/2012'!$B:$B,$A2,'05/2012'!$E:$E)))
Расшифруем формулу:
ARRAYFORMULA — Формулы массива «в одной ячейке» позволяют записывать формулы с помощью ввода массива, а не выходных данных.
SUMIF — СуммаЕСЛИ(диапазон; критерии; суммарный_диапазон)
диапазон — лист 05/2012 колонка B, знак $ закрепляет данную колонку при размножении формулы посредством “тянем вниз” (то есть, в каждой ячейке будет диапазон $B:$B; $B:$B; $B:$B, если бы $ не было, то было бы так: B:B; С: С; D:D. (в данном случае, это дата).
$A2 — это критерий, по которому следует вести суммирование, в нашем случае это 5/1/2012 и тд.
ВАЖНО: для того, чтобы у Вас все подсчеты были верными, вид искомых критериев должен быть одинаковым. То есть, если Вы отбираете по 5/1/2012, то это не то же самое, что 1/5/2012, ММ/ДД/ГГГГ не равно ДД/ММ/ГГГГ.
суммарный_диапазон — ‘05/2012'!$E:$E — столбец, где должны производиться расчеты (в нашем случае, это количество писем).
ОЖИДАЕТ:
=COUNTIF('Data'!C:C, "*@*")
расшифруем формулу — СЧИТАТЬ ЕСЛИ (В столбце С листа “Data” есть текст с содержимым @)
подробнее о формулах
Список функций Таблиц Google
Есть одна проблема — если мы запишем нашу формулу во все столбцы, то получим во всех столбцах одну и ту же цифру, а нам нужна реальная цифра, привязанная к дате.
Для правильной обработки ожидающих отправки писем, необходимо привязать цифру к дате и при работе с формулой оставить лишь полученное значение. Приведенный ниже код решает данную задачу.

var thisDay = Utilities.formatDate(new Date(), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "dd"); var myArray_Date = new Array(); myArray_Date = [1,2,3,4,7,8,9,10,11,14,15,16,17,18,21,22,23,24,25,28,29,30,31]; var dataSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Report"); for (var date_count = 0; date_count < 30; date_count++) { if (myArray_Date[date_count]==thisDay) { var y = myArray_Date[date_count] + 1; dataSheet.getRange(y, 3).setFormula("=COUNTIF('Date'!C:C, \"*@*\")"); } } var datatocopy = dataSheet.getRange(y, 3).getValues(); dataSheet.getRange(y, 3).setValues(datatocopy);
Теперь приступим к формированию статистики.
У нас есть документ для формирования статистики, но для того, чтобы сформировать ее полностью, необходим не один такой документ, а несколько.
Но пока мы будем исходить только из одного документа, имеющегося у нас.
Для формирования используем формулы.
Создаем страницу для суммарного подсчета.

Рисунок 3. Статистика, которую мы и хотели увидеть.
Для того, чтобы ускорить работу, напишем скрипт для сбора данных с наших двух листов.
function myFunction() { var workSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("REPORT"); var rew; var myReport_Name = new Array(); var first_work_row = 3, last_work_row = 33, count_column = 2; workSheet.getRange("B" + first_work_row + ":F" + last_work_row).clearContent(); for (var i=first_work_row; i<=last_work_row; i++) { rew = i - 1; workSheet.getRange(i, 2).setFormula("=(ARRAYFORMULA(SUMIF('Аккаунт для рассылки'!$A:$A&'Аккаунт для рассылки'!$A$1; $A" + i + "&$B$1; 'Аккаунт для рассылки'!B:B)))"); workSheet.getRange(i, 3).setFormula("=(ARRAYFORMULA(SUMIF('Аккаунт для рассылки'!$A:$A&'Аккаунт для рассылки'!$A$1; $A" + i + "&$B$1; 'Аккаунт для рассылки'!C:C)))"); workSheet.getRange(i, 4).setFormula("=Report_Тематика!F" + rew); workSheet.getRange(i, 5).setFormula("=Report_Тематика!E" + rew); workSheet.getRange(i, 6).setFormula("=Report_Тематика!D" + rew); } }
Для того, чтобы в меню была кнопка, допишем маленький код:
function onOpen() { SpreadsheetApp.getActiveSpreadsheet().addMenu("Копаем?", [{name: "Копаем!", functionName: "myFunction"}]); }
Теперь не надо заходить в скрипт каждый раз, когда надо совершить подсчет. Просто нажмем на кнопку “Копать” и ждем результата.
Для автоматизации процесса запуска скрипта также можно использовать тригерры, которые настраиваются в редакторе скриптов (Ресурсы — Тригерры текущего скрипта).
Должна появиться вот такая таблица, нажимаем на ссылку “Добавить” и выставляем следующие параметры.

Теперь скрипт будет выполняться автоматически без вашего участия каждые 2 часа. Настраивать можно по-разному.
Можно прописать формулы вручную, но когда у тебя не один лист, а 20 и больше, можно с легкостью допустить ошибку при составлении тех же формул.
Единственное, чего не хватает в нашем скрипте, так это параметра “только значения”, который необходим для того, чтобы не нагружать документ формулами.
Таблица с аккаунтом и критериями — Аккаунт
Таблица сводная — Сводная
Единственный минус данной статистики, это необходимость проставлять даты вручную. Если кто-то предложит автоматизацию процесса проставления даты, без учета выходных, будем благодарны вам за помощь.
Вот и все, что мы смогли рассказать вам об организации статистики с онлайн доступом.
Пользуйтесь файлами, учитесь, делитесь ссылками с друзьями.
Ждем ваших отзывов.
С уважением, Антон.