en_US en_US

GoogleAppsScript: SendMail from form näidis

  1. on tehtud ja oma väljandega vormpilt

2. GoogleTable salvestab vormisestused

3. Liisame GoogleApp Script

function sendEmailToClient() {
    // Текущая Гугл Таблица записана в переменную:
    var ss = SpreadsheetApp.getActiveSpreadsheet();

    // Лист текущей таблицы с именем "Avalda tabel", в который загружаются ответы из формы
    var listAnswers = ss.getSheetByName("Avalda tabel");
    if (!listAnswers) {
        Logger.log("Ошибка: Лист 'Avalda tabel' не найден!");
        return;
    }

    // Получен email клиента из ячейки: последняя строка, 4-й столбец
    var clientEmail = listAnswers.getRange(listAnswers.getLastRow(), 4).getValue();

    // Получен выбранный вариант из второй ячейки последней строки
    var answer = listAnswers.getRange(listAnswers.getLastRow(), 2).getValue().toLowerCase().trim();

    // Варианты текста письма
    var bodyValik1 = 'Tere <br/> Me helistame teile <strong>täna</strong>.<br/> ' +
                     'Olge valmis kõne vastu võtma.<br/><br/>' + 
                     '<a href="https://www.tthk.ee/">Rohkem infot</a>' + 
                     '<br/><br/> Päikest <br/> TTHK';

    var bodyValik2 = 'Tere <br/> Teie taotlus on registreeritud. <strong>Helistame homme.</strong><br/> ' +
                     'Olge valmis kõne vastu võtma homme.<br/><br/>' + 
                     '<a href="https://www.tthk.ee/">Rohkem infot</a>' + 
                     '<br/><br/> Päikest <br/> TTHK';

    var bodyValik3 = 'Tere <br/> Meie juht võtab teiega ühendust <strong>ülehomme</strong>.<br/> ' +
                     'Palun olge valmis kõne vastu võtma ülehomme.<br/><br/>' + 
                     '<a href="https://www.tthk.ee/">Rohkem infot</a>' + 
                     '<br/><br/> Päikest <br/> TTHK';

    var bodyValikDefault = 'Tere <br/> Te ei määranud soovitud kuupäeva.<br/> ' +
                           'Seetõttu me ei saa teiega ühendust võtta õigel ajal.<br/><br/>' + 
                           'Palun täpsustage kuupäev ja võtke meiega ühendust.<br/><br/>' +
                           '<a href="https://www.tthk.ee/">Rohkem infot</a>' + 
                           '<br/><br/> Päikest <br/> TTHK';

    var body;
    if (answer === "täna") {
        body = bodyValik1;
    } else if (answer === "home") {
        body = bodyValik2;
    } else if (answer === "ülehomme") {
        body = bodyValik3;
    } else {
        body = bodyValikDefault;
    }

    // Отправка письма клиенту
    MailApp.sendEmail({
        to: clientEmail,
        subject: "Ваша заявка получена",
        htmlBody: body
    });
}

  1. Võtab andmed Google’i tabelist „Avalda tabel“.
  2. Võtab kliendi e-posti aadressi (viimane rida, veerg 4)
  3. Võtab kliendi valiku (viimane rida, veerg 2)
  4. Saadab sõltuvalt valikust erineva e-kirja:
  • „täna“ (täna) – „Me helistame teile täna“.
  • „koju“ (ERROR, peaks olema „homme“ – homme) – „Helistage homme“.
  • „ülehomme“ – „Helista ülehomme“.
  • other – „Te ei ole sisestanud kuupäeva“

WordPress – Google Apps Scripts konspekti loomine.

20.03.2025 tund

Töötamine onEdit trigeriga (reaktsioon muudatustele tabelis) ja LanguageApp klassiga (teksti tõlkimine Google Spreadsheets’ile).

// Функция onEdit является триггером, который срабатывает при завершении ввода данных в ячейку Таблицы пользователем
// https://developers.google.com/apps-script/guides/triggers/#onedite
function onEdit(e) {
  Logger.log(e);
 
  // Получаем диапазон ячеек, в которых произошли изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/range
  var range = e.range;
 
  // Лист, на котором производились изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/sheet
  var sheet = range.getSheet();
 
  // Проверяем, нужный ли это нам лист
  Logger.log(sheet.getName());
  if (sheet.getName() != 'Перевод текста') {
    return false;
  }
 
  // Переводить необходимо текст, введённый только в первую колонку.
  // Проверяем стартовую позицию диапазона
  Logger.log(range.getColumn());
  if  (range.getColumn() != 1) {
    return false;
  }
 
  for (var i = 1; i <= range.getNumRows(); i++) {
    var cell = range.getCell(
      i, // номер строки
      1 // номер колонки
    );
 
    // Получаем текст на русском
    var russianText = cell.getValue();
 
    // Переводим текст на английский
    // https://developers.google.com/apps-script/reference/language/language-app
    var translatedText = LanguageApp.translate(
      russianText, // текст
      'ru', // с какого языка переводим
      'en' // на какой язык переводим
    );
 
    // Вставляем переведённый текст во вторую колонку
    sheet.getRange(
      cell.getRowIndex(), // номер строки
      2 // номер столбца
    ).setValue(translatedText);
  }
 
}

Lisatud teine keel (Prantsuse keel)

Lisatud uus muutuja prantsuse keele tõlke jaoks:
LanguageApp.translate(
russianText,
‘ru’,
‘fr’
);

Lisatud kood tõlke sisestamiseks kolmandasse veergu:
sheet.getRange(
cell.getRowIndex(),
3
).setValue(translatedTextFr);

sheet.getRange(cell.getRowIndex(), 3).setValue(‘Tõlkimise viga’);

Lisatud veakäitlus kolmanda veeru jaoks:
sheet.getRange(cell.getRowIndex(), 3).setValue(‘Tõlkimise viga’);

// Функция onEdit - это триггер, который срабатывает, когда пользователь завершает ввод данных в ячейку таблицы
// https://developers.google.com/apps-script/guides/triggers/#onedite
function onEdit(e) {
  // Проверяем, определен ли объект события
  if (!e || !e.range) {
    Logger.log('Ошибка: объект события не определен или не содержит свойство range');
    return;
  }
  
  Logger.log(e);
 
  // Получаем диапазон ячеек, где произошли изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/range
  var range = e.range;
 
  // Лист, где были сделаны изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/sheet
  var sheet = range.getSheet();
 
  // Проверяем, является ли это нужным нам листом
  Logger.log(sheet.getName());
  if (sheet.getName() != 'Leht1') {
    return;
  }
 
  // Требуется переводить только текст, введенный в первый столбец.
  // Проверяем начальную позицию диапазона
  Logger.log(range.getColumn());
  if (range.getColumn() != 1) {
    return;
  }
 
  for (var i = 1; i <= range.getNumRows(); i++) {
    var cell = range.getCell(
      i, // номер строки
      1  // номер столбца
    );
 
    // Получаем текст на русском языке
    var russianText = cell.getValue();
    
    // Проверяем пустую ячейку
    if (!russianText) {
      continue;
    }
 
    try {
      // Переводим текст на английский язык
      // https://developers.google.com/apps-script/reference/language/language-app
      var translatedTextEn = LanguageApp.translate(
        russianText, // текст
        'ru',        // с какого языка переводим
        'en'         // на какой язык переводим
      );
      
      // Переводим текст на французский язык
      var translatedTextFr = LanguageApp.translate(
        russianText, // текст
        'ru',        // с какого языка переводим
        'fr'         // на какой язык переводим
      );
   
      // Вставляем переведенный на английский текст во второй столбец
      sheet.getRange(
        cell.getRowIndex(), // номер строки
        2                    // номер столбца
      ).setValue(translatedTextEn);
      
      // Вставляем переведенный на французский текст в третий столбец
      sheet.getRange(
        cell.getRowIndex(), // номер строки
        3                    // номер столбца
      ).setValue(translatedTextFr);
      
    } catch (error) {
      Logger.log('Ошибка при переводе: ' + error.toString());
      sheet.getRange(cell.getRowIndex(), 2).setValue('Ошибка перевода');
      sheet.getRange(cell.getRowIndex(), 3).setValue('Ошибка перевода');
    }
  }
}

// Функция для ручного тестирования onEdit
function testOnEdit() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Leht1');
  if (!sheet) {
    Logger.log('Лист "Лист1" не найден');
    return;
  }
  
  var range = sheet.getRange('A1');
  
  var mockEvent = {
    range: range,
    source: SpreadsheetApp.getActiveSpreadsheet()
  };
  
  onEdit(mockEvent);
  Logger.log('Тест завершен');
}

Hispaania keele

Lisatud 2 põhielementi, et töötada koos hispaania keele tõlkega:

Teksti tõlkimine hispaania keelde:

// Teksti tõlkimine hispaania keelde
var translatedTextEs = LanguageApp.translate(
russianText, // tekst
‘ru’, // millisest keelest me tõlkime.
‘es’ // millisesse keelde me tõlgime
);

Oluline on siin keelekood ‘es’, mis tähistab hispaania keelt.

Kirjutage tõlke tulemus neljandasse veergu:
// Sisestage hispaania keelest tõlgitud tekst neljandasse veergu.
sheet.getRange(
cell.getRowIndex(), // rea number
4 // veeru number
).setValue(translatedTextEs);

Oluline on, et ma kasutan veeru numbrit 4, et panna hispaania keele tõlge rea neljandasse lahtrisse.

// Функция onEdit - это триггер, который срабатывает, когда пользователь завершает ввод данных в ячейку таблицы
// https://developers.google.com/apps-script/guides/triggers/#onedite
function onEdit(e) {
  // Проверяем, определен ли объект события
  if (!e || !e.range) {
    Logger.log('Ошибка: объект события не определен или не содержит свойство range');
    return;
  }
  
  Logger.log(e);
 
  // Получаем диапазон ячеек, где произошли изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/range
  var range = e.range;
 
  // Лист, где были сделаны изменения
  // https://developers.google.com/apps-script/reference/spreadsheet/sheet
  var sheet = range.getSheet();
 
  // Проверяем, является ли это нужным нам листом
  Logger.log(sheet.getName());
  if (sheet.getName() != 'Leht1') {
    return;
  }
 
  // Требуется переводить только текст, введенный в первый столбец.
  // Проверяем начальную позицию диапазона
  Logger.log(range.getColumn());
  if (range.getColumn() != 1) {
    return;
  }
 
  for (var i = 1; i <= range.getNumRows(); i++) {
    var cell = range.getCell(
      i, // номер строки
      1  // номер столбца
    );
 
    // Получаем текст на русском языке
    var russianText = cell.getValue();
    
    // Проверяем пустую ячейку
    if (!russianText) {
      continue;
    }
 
    try {
      // Переводим текст на английский язык
      // https://developers.google.com/apps-script/reference/language/language-app
      var translatedTextEn = LanguageApp.translate(
        russianText, // текст
        'ru',        // с какого языка переводим
        'en'         // на какой язык переводим
      );
      
      // Переводим текст на французский язык
      var translatedTextFr = LanguageApp.translate(
        russianText, // текст
        'ru',        // с какого языка переводим
        'fr'         // на какой язык переводим
      );
   
      // Вставляем переведенный на английский текст во второй столбец
      sheet.getRange(
        cell.getRowIndex(), // номер строки
        2                    // номер столбца
      ).setValue(translatedTextEn);
      
      // Вставляем переведенный на французский текст в третий столбец
      sheet.getRange(
        cell.getRowIndex(), // номер строки
        3                    // номер столбца
      ).setValue(translatedTextFr);
      
    } catch (error) {
      Logger.log('Ошибка при переводе: ' + error.toString());
      sheet.getRange(cell.getRowIndex(), 2).setValue('Ошибка перевода');
      sheet.getRange(cell.getRowIndex(), 3).setValue('Ошибка перевода');
    }
  }
}

// Функция для ручного тестирования onEdit
function testOnEdit() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Leht1');
  if (!sheet) {
    Logger.log('Лист "Лист1" не найден');
    return;
  }
  
  var range = sheet.getRange('A1');
  
  var mockEvent = {
    range: range,
    source: SpreadsheetApp.getActiveSpreadsheet()
  };
  
  onEdit(mockEvent);
  Logger.log('Тест завершен');
}

S

Menüü ja initsialiseerimisfunktsioon:
funktsioon onOpen() {
SpreadsheetApp.getUi()
.createMenu(‘Translator’)
.addItem(‘Open Translator’, ‘showSidebar’)
.addToUi();
}

See funktsioon loob Google Tablesi uue menüüelemendi.

Luuakse küljeriba HTML-liides:
var sidebarHTML = ”; // stiililehe ühendamine
sidebarHTML += ‘…’; // vormi loomine

See kood genereerib sisendväljadega külgriba HTML-märgistuse.

Skript, mis suhtleb serveripoolse koodiga:
SidebarHTML += „“;
See kood saadab andmed vormilt serverifunktsioonile.

Funktsioon, mis kuvab külgriba:
var htmlOutput = HtmlService
.createHtmlOutput(sidebarHTML)
.setTitle(‘Multi-translator’);

SpreadsheetApp.getUi().showSidebar(htmlOutput);
Need käsud loovad ja kuvavad Google Tables’i kasutajaliideses küljeriba.

Serveripoolne andmetöötlusfunktsioon:

funktsioon translateAndSave(e) {
var russianText = e.russianText;
var rowNum = parseInt(e.rowNum);

var translatedTextEn = LanguageApp.translate(russianText, ‘ru’, ‘en’);
var translatedTextFr = LanguageApp.translate(russianText, ‘ru’, ‘fr’);
var translatedTextEs = LanguageApp.translate(russianText, ‘ru’, ‘es’);

sheet.getRange(rowNum, 1).setValue(russianText);
sheet.getRange(rowNum, 2).setValue(translatedTextEn);
sheet.getRange(rowNum, 3).setValue(translatedTextFr);
sheet.getRange(rowNum, 4).setValue(translatedTextEs);

}
See funktsioon tõlgib ja kirjutab andmed tabelisse.

// Функция onOpen() запускается всегда при открытии документа
function onOpen() {
  // Создаём новое меню
  SpreadsheetApp.getUi()
      .createMenu('Переводчик')
      .addItem('Открыть переводчик', 'showSidebar') // При нажатии на этот элемент меню откроется сайдбар
      .addToUi();
}

// Открытие сайдбара
function showSidebar() {
    // Подключаем Bootstrap для стилей
    var sidebarHTML = '<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">';
    // Подключаем jQuery
    sidebarHTML += '<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>';

    // Создаём форму
    sidebarHTML += '<form style="padding: 20px;text-align:center;">\
        <div class="form-group">\
            <label for="russianText">Текст на русском</label>\
            <textarea class="form-control" id="russianText" name="russianText" rows="3"></textarea> \
        </div>\
        <div class="form-group">\
            <label for="rowNum">Номер строки для записи</label>\
            <input type="number" class="form-control" id="rowNum" name="rowNum" value="1" min="1">\
        </div>\
        <button type="submit" class="btn btn-primary">Перевести и записать</button>\
        <br><br>\
        <button type="button" id="sidebarClose" class="btn btn-danger">Закрыть</button>\
    </form>';

    // Добавляем скрипты
    sidebarHTML += "<script>\
     $(document).on('submit', 'form', function () { \
        google.script.run \
     .withSuccessHandler(function (resultMsg) { \
                  alert(resultMsg);\
         })\
     .translateAndSave(\
                { russianText: $('#russianText').val(), rowNum: $('#rowNum').val() }\
     );\
        return false;\
     });\
\
     $('#sidebarClose').on('click', function() {\
        google.script.host.close();\
     });\
     </script>";

    var htmlOutput = HtmlService
        .createHtmlOutput(sidebarHTML)
        .setTitle('Мульти-переводчик');

    SpreadsheetApp.getUi().showSidebar(htmlOutput);
}

// Функция для перевода и сохранения
function translateAndSave(e) {
    var russianText = e.russianText;
    var rowNum = parseInt(e.rowNum);
    
    if (!russianText) {
        return "Ошибка: введите текст для перевода!";
    }
    
    try {
        // Переводим текст на разные языки
        var translatedTextEn = LanguageApp.translate(russianText, 'ru', 'en');
        var translatedTextFr = LanguageApp.translate(russianText, 'ru', 'fr');
        var translatedTextEs = LanguageApp.translate(russianText, 'ru', 'es');
        
        // Получаем активную таблицу
        var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Leht1');
        if (!sheet) {
            sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
        }
        
        // Записываем данные в таблицу
        sheet.getRange(rowNum, 1).setValue(russianText);
        sheet.getRange(rowNum, 2).setValue(translatedTextEn);
        sheet.getRange(rowNum, 3).setValue(translatedTextFr);
        sheet.getRange(rowNum, 4).setValue(translatedTextEs);
        
        return "Перевод успешно выполнен и сохранен в строке " + rowNum;
    } catch (error) {
        return "Ошибка при переводе: " + error.toString();
    }
}

Navigatoor

Funktsioon sendMapFromAddress():

  1. Aadressi määramine: Copyvar address = sheet.getRange('B2').getValue();
    • Võtab aadressi tabeli lahtrist B2.
  2. Staatilise kaardi loomine: Copyvar map = Maps.newStaticMap() .setSize(600, 400) .setZoom(14) .addMarker(address) .setMapType(Maps.StaticMap.Type.ROADMAP);
    • Maps.newStaticMap() – pöördub Google Maps API poole.
    • addMarker(address) – edastab tekstilise aadressi Google Maps API-le, mis teisendab selle koordinaatideks ja asetab markeri.
    • Tulemuseks on genereeritud staatiline kaardipilt.

Funktsioon sendRouteLink():

  1. Lähte- ja sihtkoha hankimine: Copyvar destAddress = sheet.getRange('B2').getValue(); var homeAddress = sheet.getRange('B4').getValue();
    • Võtab sihtkoha lahtrist B2 ja lähteaadressi lahtrist B4.
  2. Marsruudi URL-i loomine: Copyvar encodedStart = encodeURIComponent(homeAddress); var encodedDest = encodeURIComponent(destAddress); var routeUrl = 'https://www.google.com/maps/dir/?api=1&origin=' + encodedStart + '&destination=' + encodedDest + '&travelmode=driving';
    • encodeURIComponent() – kodeerib aadressis olevad erimärgid URL-is korrektseks edastamiseks.
    • Luuakse spetsiaalne Google Maps URL järgmiste parameetritega:
      • origin – alguspunkt
      • destination – sihtpunkt
      • travelmode=driving – transpordi režiim (autoga)
    • Seda linki avades koostab Google Maps automaatselt marsruudi määratud punktide vahel.

/** @OnlyCurrentDoc */
function sendMapFromAddress() {
  // Получаем активный лист
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // Получаем адрес из ячейки B2
  var address = sheet.getRange('B2').getValue();
  
  // Проверяем, что адрес не пустой
  if (!address) {
    sheet.getRange('B5').setValue('Ошибка: Адрес пуст. Пожалуйста, введите адрес.');
    Logger.log("Адрес в ячейке B2 пуст. Отправка карты отменена.");
    return;
  }
  
  try {
    // Создаем статическую карту с маркером по указанному адресу
    var map = Maps.newStaticMap()
              .setSize(600, 400)  // Устанавливаем размер карты
              .setZoom(14)        // Устанавливаем масштаб
              .addMarker(address) // Добавляем маркер по адресу
              .setMapType(Maps.StaticMap.Type.ROADMAP); // Устанавливаем тип карты как дорожную карту
    
    // Получаем email получателя из ячейки B3
    var recipientEmail = sheet.getRange('B3').getValue();
    if (!recipientEmail) {
      recipientEmail = promptForEmail();
      if (recipientEmail) {
        sheet.getRange('B3').setValue(recipientEmail);
      } else {
        sheet.getRange('B5').setValue('Отправка карты отменена: email не указан');
        return;
      }
    }
    
    // Создаем тему письма с указанием адреса
    var subject = 'Карта для адреса: ' + address;
    
    // Создаем текст письма
    var body = 'Здравствуйте!\n\nВот карта для запрошенного адреса: ' + address + 
               '\n\nЭто сообщение было автоматически сгенерировано Google Apps Script.';
    
    // Отправляем письмо с вложенной картой
    GmailApp.sendEmail(recipientEmail, subject, body, {
      attachments: [map],
      name: 'Генератор карт'
    });
    
    // Записываем статус отправки в ячейку статуса
    sheet.getRange('B5').setValue('Карта отправлена: ' + new Date());
    
    // Сохраняем карту как вложение к электронной таблице
    var mapBlob = map.getBlob().setName("Map_" + new Date().getTime() + ".png");
    
    // Получаем текущий файл таблицы
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var file = DriveApp.getFileById(ss.getId());
    
    // Создаем временный файл с картой
    var tempFile = DriveApp.createFile(mapBlob);
    
    // Устанавливаем ссылку на карту в ячейке A9
    var mapUrl = tempFile.getUrl();
    sheet.getRange('A8').setValue('Карта для адреса: ' + address);
    sheet.getRange('A8').setFontWeight("bold");
    
    // Вставляем ссылку на изображение
    sheet.getRange('A9').setFormula('=HYPERLINK("' + mapUrl + '"; "Открыть карту в новой вкладке")');
    sheet.getRange('A9').setFontColor("blue");
    
    // Добавляем информацию о ссылке на карту
    sheet.getRange('A10').setValue('Копия карты сохранена в Google Drive');
    
  } catch(error) {
    // В случае ошибки записываем информацию об ошибке в ячейку статуса
    sheet.getRange('B5').setValue('Ошибка: ' + error.toString());
    Logger.log('Ошибка при создании/отправке карты: ' + error);
  }
}

/**
 * Функция для отправки ссылки на маршрут Google Maps
 */
function sendRouteLink() {
  // Получаем активный лист
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // Получаем адрес назначения из ячейки B2
  var destAddress = sheet.getRange('B2').getValue();
  
  // Получаем домашний/начальный адрес из ячейки B4
  var homeAddress = sheet.getRange('B4').getValue();
  
  // Проверяем, что оба адреса не пустые
  if (!destAddress) {
    sheet.getRange('B5').setValue('Ошибка: Адрес назначения пуст.');
    return;
  }
  
  if (!homeAddress) {
    sheet.getRange('B5').setValue('Ошибка: Домашний адрес пуст.');
    return;
  }
  
  try {
    // Получаем email получателя из ячейки B3
    var recipientEmail = sheet.getRange('B3').getValue();
    if (!recipientEmail) {
      recipientEmail = promptForEmail();
      if (recipientEmail) {
        sheet.getRange('B3').setValue(recipientEmail);
      } else {
        sheet.getRange('B5').setValue('Отправка ссылки на маршрут отменена: email не указан');
        return;
      }
    }
    
    // Создаем URL маршрута Google Maps (URL-кодированные адреса)
    var encodedStart = encodeURIComponent(homeAddress);
    var encodedDest = encodeURIComponent(destAddress);
    var routeUrl = 'https://www.google.com/maps/dir/?api=1&origin=' + encodedStart + '&destination=' + encodedDest + '&travelmode=driving';
    
    // Создаем тему письма
    var subject = 'Маршрут до: ' + destAddress;
    
    // Создаем текст письма со ссылкой на маршрут
    var body = 'Здравствуйте!\n\n' +
               'Вот ваш запрошенный маршрут от: ' + homeAddress + '\n' +
               'До: ' + destAddress + '\n\n' +
               'Нажмите на ссылку ниже, чтобы просмотреть маршрут на Google Картах:\n' +
               routeUrl + '\n\n' +
               'Это сообщение было автоматически сгенерировано Google Apps Script.';
    
    // Отправляем письмо со ссылкой на маршрут
    GmailApp.sendEmail(recipientEmail, subject, body);
    
    // Записываем статус отправки в ячейку статуса
    sheet.getRange('B5').setValue('Ссылка на маршрут отправлена: ' + new Date());
    
    // Сохраняем ссылку на маршрут в таблице
    sheet.getRange('A14').setValue('Маршрут от: ' + homeAddress + ' до: ' + destAddress);
    sheet.getRange('A14').setFontWeight("bold");
    
    sheet.getRange('A15').setFormula('=HYPERLINK("' + routeUrl + '"; "Открыть маршрут в Google Maps")');
    sheet.getRange('A15').setFontColor("blue");
    sheet.getRange('A15').setFontSize(12);
    
  } catch(error) {
    // В случае ошибки записываем информацию об ошибке в ячейку статуса
    sheet.getRange('B5').setValue('Ошибка: ' + error.toString());
    Logger.log('Ошибка при отправке ссылки на маршрут: ' + error);
  }
}

/**
 * Создает пользовательское меню в интерфейсе Google Таблиц
 */
function onOpen() {
  // Создаем таблицу ввода адреса при открытии электронной таблицы
  createAddressTable();
  
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Карты')
      .addItem('Отправить карту для адреса', 'sendMapFromAddress')
      .addItem('Отправить ссылку на маршрут', 'sendRouteLink')
      .addItem('Сбросить таблицу адресов', 'createAddressTable')
      .addItem('Очистить карту и ссылку', 'clearMapAndLink')
      .addToUi();
}

/**
 * Запрашивает у пользователя ввод адреса электронной почты
 * @return {string} Адрес электронной почты, введенный пользователем
 */
function promptForEmail() {
  var ui = SpreadsheetApp.getUi();
  var result = ui.prompt(
      'Адрес электронной почты',
      'Пожалуйста, введите email получателя:',
      ui.ButtonSet.OK_CANCEL);

  // Обрабатываем ответ пользователя
  var button = result.getSelectedButton();
  var text = result.getResponseText();
  
  if (button == ui.Button.OK) {
    // Проверяем формат email
    if (validateEmail(text)) {
      return text;
    } else {
      ui.alert('Неверный формат email. Пожалуйста, попробуйте снова.');
      return promptForEmail();
    }
  } else {
    return null;
  }
}

/**
 * Простая функция проверки email
 * @param {string} email Email для проверки
 * @return {boolean} Корректен ли email
 */
function validateEmail(email) {
  var re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return re.test(email);
}

/**
 * Очищает изображение карты и ссылку на маршрут из таблицы
 */
function clearMapAndLink() {
  var sheet = SpreadsheetApp.getActiveSheet();
  // Очищаем ячейки с информацией о карте
  sheet.getRange("A8:A10").clear();
  
  // Очищаем ячейки с ссылкой на маршрут и ее заголовком
  sheet.getRange("A14:A15").clear();
}

/**
 * Создает таблицу в листе для ввода информации об адресе
 */
function createAddressTable() {
  var sheet = SpreadsheetApp.getActiveSheet();
  
  // Очищаем область для таблицы и результатов
  clearMapAndLink();
  sheet.getRange("A1:C6").clear();
  
  // Создаем границы таблицы и фон
  var tableRange = sheet.getRange("A1:C6");
  tableRange.setBorder(true, true, true, true, true, true, '#000000', SpreadsheetApp.BorderStyle.SOLID);
  tableRange.setBackground('#f9f9f9');
  
  // Устанавливаем заголовок
  sheet.getRange("A1:C1").merge();
  sheet.getRange("A1").setValue("КАРТЫ И МАРШРУТЫ");
  sheet.getRange("A1").setFontWeight("bold");
  sheet.getRange("A1").setHorizontalAlignment("center");
  sheet.getRange("A1").setBackground("#4285f4");
  sheet.getRange("A1").setFontColor("#ffffff");
  
  // Создаем заголовки таблицы
  sheet.getRange("A2").setValue("Адрес назначения:");
  sheet.getRange("A3").setValue("Email получателя:");
  sheet.getRange("A4").setValue("Домашний адрес:");
  sheet.getRange("A5").setValue("Статус:");
  sheet.getRange("A6").setValue("Действия:");
  
  // Устанавливаем форматирование заголовков
  var headerRange = sheet.getRange("A2:A6");
  headerRange.setFontWeight("bold");
  headerRange.setBackground("#e8eaed");
  
  // Форматируем ячейки ввода
  sheet.getRange("B2:C2").merge();
  sheet.getRange("B2").setBackground("#ffffff");
  sheet.getRange("B2").setBorder(true, true, true, true, false, false, '#cccccc', SpreadsheetApp.BorderStyle.SOLID);
  
  sheet.getRange("B3:C3").merge();
  sheet.getRange("B3").setBackground("#ffffff");
  sheet.getRange("B3").setBorder(true, true, true, true, false, false, '#cccccc', SpreadsheetApp.BorderStyle.SOLID);
  
  sheet.getRange("B4:C4").merge();
  sheet.getRange("B4").setBackground("#ffffff");
  sheet.getRange("B4").setBorder(true, true, true, true, false, false, '#cccccc', SpreadsheetApp.BorderStyle.SOLID);
  
  // Устанавливаем ячейку статуса
  sheet.getRange("B5:C5").merge();
  sheet.getRange("B5").setBackground("#ffffff");
  sheet.getRange("B5").setFontStyle("italic");
  sheet.getRange("B5").setValue("Готов к отправке карты или маршрута");
  
  // Создаем ячейку-кнопку с инструкциями
  sheet.getRange("B6:C6").merge();
  sheet.getRange("B6").setValue("Используйте меню 'Карты' для отправки карты или маршрута");
  sheet.getRange("B6").setHorizontalAlignment("center");
  sheet.getRange("B6").setBackground("#e6f4ea");
  
  // Добавляем инструкции в виде примечаний
  sheet.getRange("B2").setNote("Введите адрес назначения, включая город, область/страну и почтовый индекс");
  sheet.getRange("B3").setNote("Введите адрес электронной почты, на который следует отправить карту");
  sheet.getRange("B4").setNote("Введите ваш домашний/начальный адрес для построения маршрута (необходим для ссылки на маршрут)");
  
  // Регулируем ширину столбцов
  sheet.setColumnWidth(1, 150);
  sheet.setColumnWidth(2, 200);
  sheet.setColumnWidth(3, 200);
}

https://docs.google.com/spreadsheets/d/1-gsnY1qRJsP8msNTRb5_a5Mum4t0gxDcdEX9RYnyv24/edit?usp=sharing