Что такое Google Apps Script и зачем он нужен для Gmail?
Google Apps Script (GAS) — это облачная платформа для разработки на JavaScript, которая позволяет расширять функциональность приложений Google Workspace, включая Gmail, Sheets, Docs и другие. В контексте Gmail, GAS предоставляет мощный инструментарий для автоматизации рутинных задач, интеграции с другими сервисами и создания кастомных рабочих процессов непосредственно в интерфейсе почты.
Использование GAS для Gmail позволяет выйти за рамки стандартных фильтров и настроек, открывая возможности для сложной логики обработки писем, взаимодействия с внешними API и создания уникальных решений, адаптированных под конкретные бизнес-задачи.
Преимущества автоматизации Gmail с помощью Apps Script
Автоматизация Gmail с помощью Google Apps Script предоставляет ряд существенных преимуществ:
- Экономия времени: Автоматизация повторяющихся задач, таких как сортировка писем, отправка стандартных ответов или извлечение данных, освобождает время для более важных дел.
- Повышение эффективности: Скрипты могут обрабатывать почту 24/7, обеспечивая своевременную реакцию и обработку информации.
- Интеграция: Легкая интеграция Gmail с другими сервисами Google (Sheets, Calendar, Drive) и внешними системами через API (например, CRM, системы аналитики).
- Кастомизация: Создание уникальных решений, точно соответствующих вашим рабочим процессам, которые невозможно реализовать стандартными средствами Gmail.
- Снижение ошибок: Уменьшение вероятности человеческой ошибки при выполнении монотонных операций.
Необходимые условия: доступ к Gmail и Google Apps Script
Для начала работы вам потребуется:
- Аккаунт Google: Любой стандартный аккаунт Gmail (@gmail.com) или аккаунт Google Workspace.
- Доступ к Google Apps Script: Он предоставляется автоматически всем пользователям Google. Никакой дополнительной установки не требуется.
- Базовые знания JavaScript: Понимание синтаксиса, типов данных, функций и управляющих конструкций JavaScript является обязательным.
Начало работы: создание и запуск скрипта
Открытие редактора Google Apps Script из Gmail
Хотя прямой кнопки «Открыть редактор скриптов» в интерфейсе Gmail нет, доступ к редактору можно получить через другие приложения Google Workspace (например, Sheets, Docs, Drive) или напрямую по ссылке script.google.com. Созданный скрипт сможет взаимодействовать с Gmail после предоставления соответствующих разрешений.
Альтернативно, можно создать Gmail Add-on, который будет интегрирован непосредственно в интерфейс Gmail, но это более сложный процесс, выходящий за рамки базового использования GAS для автоматизации.
Создание нового скрипта: основа и структура
Перейдите на script.google.com и создайте новый проект. Структура скрипта на GAS аналогична JavaScript:
- Файлы с кодом (
.gs): Содержат функции JavaScript. - Файлы HTML: Используются для создания пользовательских интерфейсов (менее релевантно для чистой автоматизации Gmail, но полезно для Add-ons).
- Манифест (
appsscript.json): Файл конфигурации проекта, определяющий разрешения, зависимости и другие метаданные.
Основной файл кода (Код.gs по умолчанию) будет содержать ваши функции.
/**
* Главная функция для демонстрации.
*/
function mainGmailAutomation(): void {
Logger.log('Скрипт запущен.');
// Здесь будет основная логика
}
Первый скрипт: отправка простого электронного письма
Самый простой пример — отправка письма с использованием сервиса GmailApp.
/**
* Отправляет простое электронное письмо.
*
* @param {string} recipient Адрес получателя.
* @param {string} subject Тема письма.
* @param {string} body Текст письма.
*/
function sendSimpleEmail(recipient: string, subject: string, body: string): void {
try {
GmailApp.sendEmail(recipient, subject, body);
Logger.log(`Письмо успешно отправлено на ${recipient}`);
} catch (error) {
// @ts-ignore // Используем ts-ignore, если типы Error не полностью совместимы
Logger.log(`Ошибка при отправке письма: ${error.message}`);
}
}
/**
* Пример вызова функции отправки.
*/
function runSendEmailExample(): void {
const recipientEmail: string = 'test@example.com'; // Замените на реальный адрес для теста
const emailSubject: string = 'Тестовое письмо от Google Apps Script';
const emailBody: string = 'Привет! Это автоматическое письмо, отправленное с помощью Google Apps Script.';
sendSimpleEmail(recipientEmail, emailSubject, emailBody);
}
Запуск скрипта: авторизация и выполнение
- Сохраните скрипт (иконка дискеты).
- Выберите функцию для запуска из выпадающего списка над редактором (например,
runSendEmailExample). - Нажмите кнопку «Выполнить».
- Авторизация: При первом запуске скрипта, взаимодействующего с сервисами Google (как
GmailApp), потребуется предоставить разрешения. Внимательно просмотрите запрашиваемые доступы и подтвердите их. - Выполнение: После авторизации скрипт будет выполнен. Результаты выполнения и логи (
Logger.log) можно посмотреть в разделе «Журналы выполнения».
Основные операции с Gmail в Apps Script
Доступ к почте: получение списка писем и их свойств
Сервис GmailApp предоставляет методы для доступа к письмам (сообщениям) и цепочкам писем (тредам).
GmailApp.getInboxThreads(): Получает массив цепочек во входящих.GmailApp.search(query): Ищет цепочки писем по заданному запросу (аналогично поиску в Gmail).
Каждый объект GmailThread содержит одно или несколько сообщений (GmailMessage).
/**
* Получает и логирует темы 10 последних непрочитанных писем во входящих.
*/
function logUnreadSubjects(): void {
const query: string = 'label:inbox is:unread';
const threads: GoogleAppsScript.Gmail.GmailThread[] = GmailApp.search(query, 0, 10); // Ищем до 10 цепочек
if (threads.length === 0) {
Logger.log('Непрочитанные письма не найдены.');
return;
}
threads.forEach((thread: GoogleAppsScript.Gmail.GmailThread, index: number) => {
const firstMessage: GoogleAppsScript.Gmail.GmailMessage = thread.getMessages()[0];
const subject: string = firstMessage.getSubject();
Logger.log(`Письмо ${index + 1}: ${subject}`);
});
}
Фильтрация писем: поиск по отправителю, теме, дате и другим параметрам
Метод GmailApp.search(query) — основной инструмент для фильтрации. Он использует стандартный синтаксис поисковых операторов Gmail:
from:sender@example.comto:recipient@example.comsubject:"Важный отчет"label:my-labelhas:attachmentafter:yyyy/mm/dd,before:yyyy/mm/ddis:unread,is:starred
Комбинируя операторы, можно создавать сложные поисковые запросы.
/**
* Ищет письма от определенного отправителя с вложениями за последний месяц.
*/
function findReportsFromSender(): void {
const oneMonthAgo: Date = new Date();
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
const formattedDate: string = `${oneMonthAgo.getFullYear()}/${oneMonthAgo.getMonth() + 1}/${oneMonthAgo.getDate()}`;
const searchQuery: string = `from:reports@example.com has:attachment after:${formattedDate}`;
const threads: GoogleAppsScript.Gmail.GmailThread[] = GmailApp.search(searchQuery);
Logger.log(`Найдено ${threads.length} цепочек писем с отчетами.`);
// Дальнейшая обработка найденных писем...
}
Чтение и обработка содержимого писем: текст, HTML, вложения
Объект GmailMessage предоставляет методы для доступа к содержимому письма:
getSubject(): Получить тему.getFrom(): Получить отправителя.getTo(),getCc(): Получить получателей.getDate(): Получить дату отправки.getPlainBody(): Получить текстовую версию тела письма.getBody(): Получить HTML-версию тела письма.getAttachments(): Получить массив вложений (Blobобъекты).
/**
* Обрабатывает первое сообщение в цепочке: логирует отправителя и извлекает URL из тела.
* @param {GoogleAppsScript.Gmail.GmailThread} thread Цепочка писем для обработки.
*/
function processEmailContent(thread: GoogleAppsScript.Gmail.GmailThread): void {
const message: GoogleAppsScript.Gmail.GmailMessage = thread.getMessages()[0];
const from: string = message.getFrom();
const body: string = message.getBody(); // Получаем HTML
Logger.log(`Обработка письма от: ${from}`);
// Пример: извлечение ссылок с UTM-метками (упрощенный regex)
const utmLinkRegex: RegExp = /https?:\[/]{2}[^\s'"]*utm_source=[^\s'"]*/gi;
const links: RegExpMatchArray | null = body.match(utmLinkRegex);
if (links && links.length > 0) {
Logger.log('Найдены ссылки с UTM-метками:');
links.forEach((link: string) => Logger.log(link));
} else {
Logger.log('Ссылки с UTM-метками не найдены.');
}
// Обработка вложений
const attachments: GoogleAppsScript.Base.Blob[] = message.getAttachments();
if (attachments.length > 0) {
Logger.log(`Найдено вложений: ${attachments.length}`);
attachments.forEach((attachment: GoogleAppsScript.Base.Blob) => {
Logger.log(` - Имя файла: ${attachment.getName()}, Тип: ${attachment.getContentType()}`);
// Можно сохранить вложение на Google Drive: DriveApp.createFile(attachment);
});
}
}
Отправка писем: создание, форматирование и отправка сообщений
Метод GmailApp.sendEmail() имеет несколько вариаций, включая возможность отправки HTML-писем, добавления вложений и использования дополнительных параметров.
/**
* Отправляет форматированное HTML-письмо с вложением.
*
* @param {string} recipient Адрес получателя.
* @param {string} subject Тема письма.
* @param {string} htmlBody Тело письма в формате HTML.
* @param {GoogleAppsScript.Base.BlobSource} [attachment] Необязательное вложение.
*/
function sendFormattedEmail(
recipient: string,
subject: string,
htmlBody: string,
attachment?: GoogleAppsScript.Base.BlobSource
): void {
const options: GoogleAppsScript.Gmail.GmailAdvancedOptions = {
htmlBody: htmlBody,
name: 'Центр Автоматизации',
// Дополнительные опции:
// cc: 'cc@example.com',
// bcc: 'bcc@example.com',
// replyTo: 'support@example.com',
};
if (attachment) {
options.attachments = [attachment];
}
try {
GmailApp.sendEmail(recipient, subject, '', options); // Тело обычного текста пустое, т.к. есть htmlBody
Logger.log(`HTML письмо отправлено на ${recipient}`);
} catch (error) {
// @ts-ignore
Logger.log(`Ошибка при отправке HTML письма: ${error.message}`);
}
}
/**
* Пример вызова отправки HTML-письма.
*/
function runSendFormattedEmailExample(): void {
const recipient: string = 'test@example.com';
const subject: string = 'Ваш персонализированный отчет готов';
const htmlContent: string = `
<h1>Отчет за Октябрь</h1>
<p>Уважаемый клиент,</p>
<p>Ваш отчет готов. См. детали ниже или во вложении.</p>
<p><b>Ключевые метрики:</b></p>
<ul>
<li>Показы: 10500</li>
<li>Клики: 315</li>
<li>CTR: 3%</li>
</ul>
<p>С уважением,<br>Центр Автоматизации</p>
`;
// Можно создать Blob для вложения, например, из Google Drive или сгенерировать
// const file = DriveApp.getFileById('YOUR_FILE_ID').getBlob();
sendFormattedEmail(recipient, subject, htmlContent);
}
Практические примеры автоматизации Gmail
Автоматическая отправка ответов на определенные письма
Скрипт может искать письма по определенным критериям (например, тема или ключевые слова в теле) и отправлять заранее подготовленный ответ.
/**
* Ищет новые письма с темой 'Запрос информации' и отправляет автоответ.
*/
function autoRespondToInfoRequests(): void {
const searchQuery: string = 'subject:"Запрос информации" is:unread label:inbox';
const threads: GoogleAppsScript.Gmail.GmailThread[] = GmailApp.search(searchQuery);
const responseSubject: string = 'Re: Запрос информации';
const responseBody: string = 'Спасибо за ваш запрос! Мы получили ваше сообщение и ответим в течение 24 часов. С уважением, Служба поддержки.';
threads.forEach((thread: GoogleAppsScript.Gmail.GmailThread) => {
const lastMessage: GoogleAppsScript.Gmail.GmailMessage = thread.getMessages()[thread.getMessageCount() - 1];
const recipient: string = lastMessage.getFrom(); // Отвечаем отправителю последнего сообщения
// Проверяем, не отвечали ли мы уже в этой цепочке (простой пример)
let alreadyReplied = false;
thread.getMessages().forEach(msg => {
if (msg.getFrom().includes('me') && msg.getSubject() === responseSubject) {
alreadyReplied = true;
}
});
if (!alreadyReplied) {
try {
thread.reply(responseBody, {
name: 'Служба поддержки',
htmlBody: `<p>${responseBody.replace(/\n/g, '<br>')}</p>` // Можно использовать HTML для форматирования
});
Logger.log(`Автоответ отправлен на ${recipient}`);
thread.markRead(); // Помечаем как прочитанное
// thread.moveToArchive(); // Можно переместить в архив
} catch (error) {
// @ts-ignore
Logger.log(`Ошибка отправки автоответа для ${recipient}: ${error.message}`);
}
}
});
}
Сортировка писем по папкам на основе содержимого или отправителя
GAS позволяет автоматически применять ярлыки (аналоги папок) к письмам на основе заданных правил, которые могут быть сложнее стандартных фильтров Gmail.
/**
* Создает ярлык, если он не существует.
* @param {string} labelName Имя ярлыка.
* @returns {GoogleAppsScript.Gmail.GmailLabel} Объект ярлыка.
*/
function ensureLabelExists(labelName: string): GoogleAppsScript.Gmail.GmailLabel {
let label: GoogleAppsScript.Gmail.GmailLabel | null = GmailApp.getUserLabelByName(labelName);
if (!label) {
label = GmailApp.createLabel(labelName);
Logger.log(`Создан ярлык: ${labelName}`);
}
return label;
}
/**
* Сортирует письма от 'client@example.com' или с темой 'Срочно' в соответствующие ярлыки.
*/
function sortIncomingEmails(): void {
const clientLabel: GoogleAppsScript.Gmail.GmailLabel = ensureLabelExists('Клиенты/Важные');
const urgentLabel: GoogleAppsScript.Gmail.GmailLabel = ensureLabelExists('Срочно');
const clientThreads: GoogleAppsScript.Gmail.GmailThread[] = GmailApp.search('from:client@example.com is:unread');
const urgentThreads: GoogleAppsScript.Gmail.GmailThread[] = GmailApp.search('subject:Срочно is:unread');
clientThreads.forEach((thread: GoogleAppsScript.Gmail.GmailThread) => {
thread.addLabel(clientLabel);
thread.markRead();
Logger.log(`Письмо ${thread.getFirstMessageSubject()} помечено ярлыком ${clientLabel.getName()}`);
});
urgentThreads.forEach((thread: GoogleAppsScript.Gmail.GmailThread) => {
// Убедимся, что не дублируем ярлык, если письмо и от клиента, и срочное
if (!thread.getLabels().some(label => label.getName() === urgentLabel.getName())) {
thread.addLabel(urgentLabel);
thread.markImportant(); // Помечаем как важное
Logger.log(`Письмо ${thread.getFirstMessageSubject()} помечено ярлыком ${urgentLabel.getName()}`);
}
thread.markRead();
});
}
Извлечение информации из писем и сохранение в Google Sheets
Это мощный сценарий для сбора данных, например, информации о лидах из форм обратной связи, деталей заказов из писем подтверждения или UTM-меток из маркетинговых рассылок.
/**
* Извлекает данные о заказах из писем и записывает их в Google Sheet.
*/
function logOrdersToSheet(): void {
const sheetId: string = 'YOUR_SPREADSHEET_ID'; // ID вашей таблицы
const sheetName: string = 'Заказы';
const searchQuery: string = 'subject:"Новый заказ" from:orders@my-store.com is:unread';
const ss: GoogleAppsScript.Spreadsheet.Spreadsheet = SpreadsheetApp.openById(sheetId);
const sheet: GoogleAppsScript.Spreadsheet.Sheet | null = ss.getSheetByName(sheetName);
if (!sheet) {
Logger.log(`Лист с именем ${sheetName} не найден в таблице ${sheetId}`);
return;
}
const threads: GoogleAppsScript.Gmail.GmailThread[] = GmailApp.search(searchQuery);
threads.forEach((thread: GoogleAppsScript.Gmail.GmailThread) => {
const message: GoogleAppsScript.Gmail.GmailMessage = thread.getMessages()[0];
const body: string = message.getPlainBody();
// Пример извлечения данных (предполагается простой формат)
const orderIdMatch: RegExpMatchArray | null = body.match(/Номер заказа: (\d+)/);
const customerEmailMatch: RegExpMatchArray | null = body.match(/Email клиента: ([\w.@]+)/);
const totalAmountMatch: RegExpMatchArray | null = body.match(/Сумма: ([\d.]+)/);
if (orderIdMatch && customerEmailMatch && totalAmountMatch) {
const orderId: string = orderIdMatch[1];
const customerEmail: string = customerEmailMatch[1];
const totalAmount: string = totalAmountMatch[1];
const orderDate: Date = message.getDate();
// Запись данных в следующую пустую строку
sheet.appendRow([orderDate, orderId, customerEmail, parseFloat(totalAmount)]);
Logger.log(`Заказ ${orderId} добавлен в таблицу.`);
thread.markRead();
thread.moveToArchive();
} else {
Logger.log(`Не удалось извлечь данные из письма: ${message.getSubject()}`);
// Можно добавить логику для обработки ошибок или перемещения в спец. ярлык
}
});
}
Создание рассылок с персонализированным контентом
Используя данные из Google Sheets, можно создавать персонализированные email-рассылки.
/**
* Отправляет персонализированные письма на основе данных из Google Sheet.
*/
function sendPersonalizedEmails(): void {
const sheetId: string = 'YOUR_SPREADSHEET_ID'; // ID таблицы с данными
const sheetName: string = 'Лиды';
const subjectTemplate: string = 'Специальное предложение для вас, {Имя}!';
const htmlBodyTemplate: string = `
<p>Здравствуйте, {Имя}!</p>
<p>Мы заметили ваш интерес к {Продукт}. У нас есть специальное предложение...</p>
<p>С уважением,<br>Отдел маркетинга</p>
`;
const ss: GoogleAppsScript.Spreadsheet.Spreadsheet = SpreadsheetApp.openById(sheetId);
const sheet: GoogleAppsScript.Spreadsheet.Sheet | null = ss.getSheetByName(sheetName);
if (!sheet) {
Logger.log(`Лист с именем ${sheetName} не найден в таблице ${sheetId}`);
return;
}
// Получаем данные со 2й строки (предполагая заголовки в 1й)
// Колонки: Email, Имя, Продукт, Статус Отправки
const dataRange: GoogleAppsScript.Spreadsheet.Range = sheet.getDataRange();
const values: any[][] = dataRange.getValues();
// Пропускаем заголовки
for (let i = 1; i < values.length; i++) {
const row: any[] = values[i];
const email: string = row[0];
const name: string = row[1];
const product: string = row[2];
const status: string = row[3];
// Отправляем, только если статус не 'Отправлено'
if (email && name && product && status !== 'Отправлено') {
const subject: string = subjectTemplate.replace('{Имя}', name);
const htmlBody: string = htmlBodyTemplate
.replace('{Имя}', name)
.replace('{Продукт}', product);
try {
GmailApp.sendEmail(email, subject, '', { htmlBody: htmlBody, name: 'Отдел маркетинга' });
sheet.getRange(i + 1, 4).setValue('Отправлено'); // Обновляем статус в таблице (4я колонка)
Logger.log(`Письмо отправлено на ${email}`);
// Добавляем небольшую паузу, чтобы не превышать квоты Gmail
Utilities.sleep(1000); // Пауза 1 секунда
} catch (error) {
// @ts-ignore
Logger.log(`Ошибка отправки письма на ${email}: ${error.message}`);
sheet.getRange(i + 1, 4).setValue('Ошибка');
}
}
}
}
Продвинутые техники и советы
Использование триггеров для автоматического запуска скриптов
Триггеры позволяют запускать функции автоматически по расписанию или при наступлении определенных событий.
- Триггеры по времени (Time-driven): Запускают скрипт через определенные интервалы (каждые N минут/часов, ежедневно, еженедельно и т.д.). Идеально подходят для периодической обработки почты, отправки отчетов.
- Триггеры на события (Event-driven): Запускаются при событиях в Google Workspace (например, при отправке формы Google Forms, редактировании таблицы Sheets). Менее применимы для прямого реагирования на новое письмо в Gmail (для этого нужны Gmail Add-ons или внешние инструменты, но триггеры по времени могут проверять почту часто).
Настройка триггеров выполняется в редакторе скриптов:
- Перейдите в раздел «Триггеры» (иконка будильника на левой панели).
- Нажмите «Добавить триггер».
- Выберите функцию для запуска, источник события (например, «Время»), тип триггера (например, «Таймер по дням») и время выполнения.
- Сохраните триггер (может потребоваться повторная авторизация).
/**
* Создает триггер, который запускает функцию 'sortIncomingEmails' каждый час.
*/
function createHourlyEmailSorterTrigger(): void {
// Удаляем старые триггеры для этой функции, чтобы избежать дублирования
const existingTriggers = ScriptApp.getProjectTriggers();
existingTriggers.forEach(trigger => {
if (trigger.getHandlerFunction() === 'sortIncomingEmails') {
ScriptApp.deleteTrigger(trigger);
}
});
// Создаем новый триггер
ScriptApp.newTrigger('sortIncomingEmails')
.timeBased()
.everyHours(1)
.create();
Logger.log('Ежечасный триггер для сортировки писем создан.');
}
Обработка ошибок и отладка скриптов
Надежные скрипты должны включать обработку ошибок.
try...catchблоки: Используйте для перехвата и обработки исключений во время выполнения, предотвращая аварийное завершение скрипта.Logger.log()иconsole.log(): Основные инструменты для отладки. ВыводLogger.logвиден в «Журналах выполнения» в редакторе Apps Script.console.logиспользуется при отладке в браузере (например, для интерфейсов).- Отладчик редактора: Встроенный отладчик позволяет устанавливать точки останова (
breakpoint) и пошагово выполнять код, проверяя значения переменных. - Мониторинг выполнения: Следите за панелью «Выполнения» для отслеживания статуса запусков (включая запущенные триггерами) и выявления ошибок.
Оптимизация производительности скриптов для больших объемов почты
При работе с большим количеством писем важно оптимизировать скрипты, чтобы избежать превышения квот и замедления работы.
- Минимизация вызовов API: Каждый вызов
GmailApp,SpreadsheetAppи т.д. занимает время. Старайтесь получать данные пакетами и минимизировать количество обращений в циклах. - Пакетные операции: Используйте методы, работающие с массивами объектов, где это возможно (например,
GmailApp.moveThreadsToArchive(threads)вместо перемещения по одному). - Эффективные запросы
GmailApp.search(): Чем точнее ваш поисковый запрос, тем меньше данных нужно обработать. Используйтеis:unreadи другие фильтры для сужения выборки. - Кэширование: Используйте
CacheServiceдля временного хранения данных, которые не требуют постоянного обновления (например, настройки, часто используемые ярлыки). - Избегайте обработки уже обработанного: Внедряйте логику (например, пометка прочитанным, добавление ярлыка ‘Processed’, запись ID в Sheet), чтобы скрипт не обрабатывал одни и те же письма повторно.
- Квоты Google Apps Script: Ознакомьтесь с дневными квотами на выполнение скриптов, количество отправленных писем, время выполнения и т.д., чтобы ваши скрипты не блокировались. (https://developers.google.com/apps-script/guides/quotas)
Вопросы безопасности при работе с Gmail API
При работе с чувствительными данными почты безопасность имеет первостепенное значение.
- Принцип минимальных привилегий: Запрашивайте только те области разрешений (scopes), которые действительно необходимы для работы скрипта. Это настраивается в манифесте (
appsscript.json). - Защита учетных данных: Никогда не храните пароли, API-ключи или другую конфиденциальную информацию непосредственно в коде. Используйте
PropertiesServiceдля безопасного хранения настроек скрипта или внешние системы управления секретами. - Регулярный аудит разрешений: Периодически проверяйте, какие скрипты и приложения имеют доступ к вашему аккаунту Google, и отзывайте ненужные разрешения.
- Обработка данных: Будьте осторожны при логировании или передаче содержимого писем. Избегайте сохранения или вывода конфиденциальной информации без необходимости.
- Авторизация: Понимайте, какие разрешения вы предоставляете при авторизации скрипта. Не запускайте и не авторизуйте скрипты из недоверенных источников.