Как получить адрес электронной почты с помощью Google Apps Script?

Что такое Google Apps Script и его возможности?

Google Apps Script (GAS) — это облачная платформа для разработки скриптов на основе JavaScript, позволяющая расширять функциональность приложений Google Workspace (Docs, Sheets, Forms, Drive, Gmail и др.) и автоматизировать рабочие процессы. GAS предоставляет удобный API для взаимодействия с этими сервисами, создания пользовательских интерфейсов и интеграции со сторонними системами.

Необходимость получения адреса электронной почты в Google Apps Script: сценарии использования

Получение адреса электронной почты пользователя является частой задачей в автоматизации. Вот несколько распространенных сценариев:

  • Персонализация: Обращение к пользователю по имени в автоматических письмах или документах.
  • Авторизация и контроль доступа: Проверка прав пользователя, запустившего скрипт или открывшего документ.
  • Логирование действий: Запись email пользователя, выполнившего определенное действие в системе.
  • Автоматизация рассылок: Отправка уведомлений или отчетов конкретным пользователям или группам.
  • Интеграция с другими системами: Использование email как уникального идентификатора пользователя.

Предварительные требования: настройка и авторизация Google Apps Script

Для работы с большинством методов, требующих доступа к данным пользователя, необходимо:

  1. Создать проект Google Apps Script: Либо привязанный к документу (bound script), либо автономный (standalone script).
  2. Авторизовать скрипт: При первом запуске скрипта, использующего сервисы, требующие доступа к данным пользователя (например, Session, Admin SDK Directory Service), Google запросит у пользователя разрешение на предоставление необходимых прав доступа (scopes). Важно запрашивать только минимально необходимые права.

Получение адреса электронной почты текущего пользователя

Использование Session.getActiveUser().getEmail() для получения адреса электронной почты активного пользователя

Самый простой способ получить email текущего пользователя, взаимодействующего со скриптом в данный момент (например, открывшего документ или запустившего функцию из меню).

/**
 * Получает и логирует адрес электронной почты активного пользователя.
 *
 * @returns {string | null} Адрес электронной почты активного пользователя или null, если не удалось получить.
 */
function logActiveUserEmail(): string | null {
  try {
    // Получаем объект текущего пользователя
    const activeUser: GoogleAppsScript.Base.User = Session.getActiveUser();
    // Получаем email пользователя
    const userEmail: string = activeUser.getEmail();

    if (userEmail) {
      console.log(`Email активного пользователя: ${userEmail}`);
      return userEmail;
    } else {
      console.warn('Не удалось получить email активного пользователя. Возможно, скрипт запущен в анонимном режиме или пользователь не предоставил разрешение.');
      return null;
    }
  } catch (error) {
    console.error(`Ошибка при получении email активного пользователя: ${error}`);
    return null;
  }
}

Важно: Этот метод вернет пустую строку (''), если пользователь не принадлежит к тому же домену Google Workspace, что и автор скрипта (для потребительских аккаунтов Gmail это ограничение не так актуально, но может проявляться в сложных сценариях авторизации или при использовании специфических настроек Workspace).

Разница между getActiveUser() и getEffectiveUser()

  • Session.getActiveUser(): Возвращает пользователя, взаимодействующего с интерфейсом или запустившего скрипт вручную. В контексте триггеров, установленных пользователем, это будет тот пользователь, который установил триггер.
  • Session.getEffectiveUser(): Возвращает пользователя, от имени которого скрипт выполняется в данный момент. Это особенно важно для:
    • Installable Triggers: Если триггер установлен разработчиком, getEffectiveUser() вернет разработчика, а getActiveUser() вернет пользователя, чье действие вызвало триггер (если применимо).
    • Web Apps: Запущенных с опцией «Execute as: Me (developer)». getEffectiveUser() вернет разработчика.
    • Add-ons: В зависимости от модели авторизации.

Если скрипт выполняется под авторизацией пользователя, запустившего его, эти два метода часто возвращают одного и того же пользователя. Однако getEffectiveUser().getEmail() часто является более надежным способом получить email пользователя, чьи квоты и разрешения используются для выполнения скрипта, особенно в автоматизированных сценариях.

Обработка ошибок: что делать, если адрес электронной почты не найден?

Как видно в примере выше, getEmail() может вернуть пустую строку или вызвать исключение. Возможные причины:

  • Ограничения безопасности/конфиденциальности: В некоторых контекстах (например, анонимный доступ к веб-приложению) получить email невозможно.
  • Недостаточные разрешения: Пользователь не предоставил скрипту необходимое разрешение (script.container.ui или userinfo.email).
  • Тип аккаунта: Редкие сценарии с особыми типами аккаунтов Google.

Всегда проверяйте возвращаемое значение и используйте блоки try...catch для обработки потенциальных ошибок.

Получение адресов электронной почты из Google Workspace (G Suite)

Использование Admin SDK Directory API для доступа к информации о пользователях

Для получения информации о любых пользователях в вашем домене Google Workspace (а не только текущего) необходимо использовать Admin SDK Directory Service. Этот сервис требует специальных разрешений и доступен только для аккаунтов Google Workspace.

Авторизация скрипта для работы с Admin SDK Directory API

  1. Включите Admin SDK Directory API: В редакторе скриптов перейдите в «Сервисы» (Services +), найдите Admin Directory API и добавьте его.
  2. Запросите необходимые OAuth Scopes: В файле манифеста appsscript.json добавьте нужные области видимости. Для чтения информации о пользователях обычно достаточно:
    json
    {
    "timeZone": "Europe/Moscow",
    "dependencies": {
    "enabledAdvancedServices": [{
    "userSymbol": "AdminDirectory",
    "serviceId": "admin",
    "version": "directory_v1"
    }]
    },
    "oauthScopes": [
    "https://www.googleapis.com/auth/admin.directory.user.readonly",
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/script.scriptapp"
    ],
    "exceptionLogging": "STACKDRIVER",
    "runtimeVersion": "V8"
    }
  3. Получите права администратора: Скрипт должен быть запущен пользователем, обладающим достаточными правами администратора в Google Workspace для чтения данных пользователей.

Примеры кода: получение списка всех адресов электронной почты в домене

/**
 * Получает список адресов электронной почты всех активных пользователей в домене Google Workspace.
 *
 * @returns {string[]} Массив адресов электронной почты или пустой массив в случае ошибки.
 */
function getAllDomainUserEmails(): string[] {
  let pageToken: string | undefined;
  let allEmails: string[] = [];
  const domain: string = Session.getActiveUser().getEmail().split('@')[1]; // Получаем домен текущего пользователя

  if (!AdminDirectory) {
     console.error('Сервис AdminDirectory не включен.');
     return [];
  }

  try {
    do {
      const options: GoogleAppsScript.AdminDirectory.Schema.UsersListOptionalArgs = {
        domain: domain,
        orderBy: 'email',
        maxResults: 500, // Максимальное количество пользователей за один запрос (до 500)
        pageToken: pageToken,
        query: "isSuspended=false" // Получаем только активных пользователей
      };

      const response: GoogleAppsScript.AdminDirectory.Schema.Users = AdminDirectory.Users.list(options);
      const users: GoogleAppsScript.AdminDirectory.Schema.User[] | undefined = response.users;

      if (users && users.length > 0) {
        const emails: string[] = users.map((user: GoogleAppsScript.AdminDirectory.Schema.User) => user.primaryEmail || '');
        allEmails = allEmails.concat(emails.filter(email => email)); // Добавляем только непустые email
      }

      pageToken = response.nextPageToken;
    } while (pageToken);

    console.log(`Найдено ${allEmails.length} активных пользователей в домене ${domain}.`);
    return allEmails;

  } catch (error) {
    // Часто ошибка связана с недостаточными правами администратора
    console.error(`Ошибка при получении списка пользователей из Admin SDK: ${error}`);
    console.info('Убедитесь, что скрипт запущен администратором Workspace и имеет необходимые разрешения.');
    return [];
  }
}

Фильтрация и поиск пользователей по критериям (например, по имени или отделу)

Параметр query в AdminDirectory.Users.list(options) позволяет фильтровать пользователей по различным атрибутам. Синтаксис запросов описан в документации Google Admin SDK Directory API.

Реклама
/**
 * Ищет пользователей в домене по имени или email.
 *
 * @param {string} searchQuery Имя или часть email для поиска.
 * @returns {GoogleAppsScript.AdminDirectory.Schema.User[]} Массив найденных пользователей или пустой массив.
 */
function findUsersByQuery(searchQuery: string): GoogleAppsScript.AdminDirectory.Schema.User[] {
  const domain: string = Session.getActiveUser().getEmail().split('@')[1];

  if (!AdminDirectory) {
     console.error('Сервис AdminDirectory не включен.');
     return [];
  }

  try {
    const options: GoogleAppsScript.AdminDirectory.Schema.UsersListOptionalArgs = {
      domain: domain,
      maxResults: 100,
      query: `email:${searchQuery}* OR name:'${searchQuery}'*` // Пример: поиск по началу email ИЛИ имени
    };
    const response: GoogleAppsScript.AdminDirectory.Schema.Users = AdminDirectory.Users.list(options);
    const users: GoogleAppsScript.AdminDirectory.Schema.User[] = response.users || [];

    console.log(`Найдено ${users.length} пользователей по запросу: '${searchQuery}'`);
    // Выводим email найденных пользователей для примера
    users.forEach(user => console.log(` - ${user.primaryEmail} (${user.name?.fullName})`));

    return users;

  } catch (error) {
    console.error(`Ошибка при поиске пользователей: ${error}`);
    return [];
  }
}

// Пример использования:
// findUsersByQuery('ivan');
// findUsersByQuery('support@');

Получение адресов электронной почты из Google Sheets

Чтение данных из Google Sheets с использованием Google Apps Script

Google Sheets часто используется как источник данных для автоматизации, включая списки email-адресов. Сервис SpreadsheetApp позволяет легко читать данные из таблиц.

/**
 * Читает все данные с указанного листа Google Sheets.
 *
 * @param {string} spreadsheetId ID таблицы Google Sheets.
 * @param {string} sheetName Имя листа.
 * @returns {any[][] | null} Двумерный массив данных или null в случае ошибки.
 */
function readSheetData(spreadsheetId: string, sheetName: string): any[][] | null {
  try {
    const ss: GoogleAppsScript.Spreadsheet.Spreadsheet = SpreadsheetApp.openById(spreadsheetId);
    const sheet: GoogleAppsScript.Spreadsheet.Sheet | null = ss.getSheetByName(sheetName);

    if (!sheet) {
      console.error(`Лист с именем '${sheetName}' не найден в таблице ID: ${spreadsheetId}`);
      return null;
    }

    const dataRange: GoogleAppsScript.Spreadsheet.Range = sheet.getDataRange();
    const values: any[][] = dataRange.getValues();
    console.log(`Прочитано ${values.length} строк и ${values[0]?.length || 0} столбцов с листа '${sheetName}'.`);
    return values;

  } catch (error) {
    console.error(`Ошибка при чтении данных из Google Sheets (ID: ${spreadsheetId}, Лист: ${sheetName}): ${error}`);
    return null;
  }
}

Извлечение адресов электронной почты из определенных столбцов

После получения данных в виде двумерного массива, необходимо извлечь email из нужного столбца.

/**
 * Извлекает адреса электронной почты из указанного столбца двумерного массива данных.
 *
 * @param {any[][]} data Двумерный массив данных (например, из Google Sheets).
 * @param {number} emailColumnIndex Индекс столбца (начиная с 0), содержащего email.
 * @param {boolean} skipHeader Пропустить ли первую строку (заголовок).
 * @returns {string[]} Массив извлеченных адресов электронной почты.
 */
function extractEmailsFromColumn(data: any[][], emailColumnIndex: number, skipHeader: boolean = true): string[] {
  if (!data || data.length === 0) {
    return [];
  }

  const startIndex: number = skipHeader ? 1 : 0;
  const emails: string[] = [];

  for (let i = startIndex; i < data.length; i++) {
    if (data[i] && data[i].length > emailColumnIndex) {
      const emailValue: any = data[i][emailColumnIndex];
      // Проверяем, что значение существует и является строкой
      if (typeof emailValue === 'string' && emailValue.trim() !== '') {
        emails.push(emailValue.trim());
      }
    }
  }
  console.log(`Извлечено ${emails.length} адресов из столбца ${emailColumnIndex + 1}.`);
  return emails;
}

Проверка валидности полученных адресов электронной почты

Часто данные в таблицах содержат ошибки. Рекомендуется проверять формат email перед использованием.

/**
 * Фильтрует массив строк, оставляя только валидные адреса электронной почты.
 *
 * @param {string[]} emails Массив потенциальных адресов электронной почты.
 * @returns {string[]} Массив валидных адресов электронной почты.
 */
function validateEmails(emails: string[]): string[] {
  // Простое регулярное выражение для проверки базового формата email
  // Для строгой валидации по RFC 5322 могут потребоваться более сложные выражения
  const emailRegex: RegExp = /^[^"\s@]+@[^"\s@]+\.[^"\s@]+$/;

  const validEmails: string[] = emails.filter(email => emailRegex.test(email));

  if (emails.length !== validEmails.length) {
      console.warn(`Обнаружено ${emails.length - validEmails.length} невалидных email адресов.`);
  }

  return validEmails;
}

// Пример использования:
// const sheetData = readSheetData('YOUR_SPREADSHEET_ID', 'Sheet1');
// if (sheetData) {
//   const rawEmails = extractEmailsFromColumn(sheetData, 2); // Предполагаем, что email в 3-м столбце (индекс 2)
//   const validEmails = validateEmails(rawEmails);
//   console.log('Валидные email:', validEmails);
// }

Практические примеры и советы

Пример: Отправка персонализированных электронных писем списку адресов из Google Sheets

Этот пример комбинирует чтение из Sheets, извлечение и валидацию email, а затем отправку писем с помощью MailApp.

/**
 * Отправляет персонализированные письма списку пользователей из Google Sheet.
 *
 * @param {string} spreadsheetId ID таблицы Google Sheets.
 * @param {string} sheetName Имя листа с данными (ожидается: столбец Имя, столбец Email).
 * @param {number} nameColumnIndex Индекс столбца с именем (начиная с 0).
 * @param {number} emailColumnIndex Индекс столбца с email (начиная с 0).
 * @param {string} subject Тема письма.
 * @param {string} bodyTemplate Шаблон тела письма (используйте {{name}} для подстановки имени).
 */
function sendPersonalizedEmailsFromSheet(
  spreadsheetId: string,
  sheetName: string,
  nameColumnIndex: number,
  emailColumnIndex: number,
  subject: string,
  bodyTemplate: string
): void {

  const sheetData: any[][] | null = readSheetData(spreadsheetId, sheetName);
  if (!sheetData || sheetData.length < 2) { // Проверяем, есть ли данные кроме заголовка
    console.error('Нет данных для отправки в таблице.');
    return;
  }

  // Пропускаем заголовок (индекс 0)
  for (let i = 1; i < sheetData.length; i++) {
    const row: any[] = sheetData[i];
    const name: string = typeof row[nameColumnIndex] === 'string' ? row[nameColumnIndex].trim() : 'Коллега';
    const email: string = typeof row[emailColumnIndex] === 'string' ? row[emailColumnIndex].trim() : '';

    // Простая валидация email
    const emailRegex: RegExp = /^[^"\s@]+@[^"\s@]+\.[^"\s@]+$/;
    if (email && emailRegex.test(email)) {
      const personalizedBody: string = bodyTemplate.replace('{{name}}', name);
      try {
        MailApp.sendEmail(email, subject, personalizedBody);
        console.log(`Письмо успешно отправлено на: ${email}`);
        // Добавляем небольшую паузу, чтобы не превысить квоты Google
        Utilities.sleep(500); 
      } catch (error) {
        console.error(`Ошибка отправки письма на ${email}: ${error}`);
      }
    } else {
      console.warn(`Пропуск строки ${i + 1}: невалидный или пустой email '${email}'.`);
    }
  }
  console.log('Рассылка завершена.');
}

// Пример вызова:
// sendPersonalizedEmailsFromSheet(
//   'YOUR_SPREADSHEET_ID',
//   'Contacts',
//   0, // Имя в первом столбце (индекс 0)
//   1, // Email во втором столбце (индекс 1)
//   'Важное обновление',
//   'Здравствуйте, {{name}}!\n\nЭто важное сообщение для вас.\n\nС уважением,\nКоманда проекта.'
// );

Рекомендации по безопасности при работе с адресами электронной почты

  • Минимальные разрешения: Запрашивайте только те oauthScopes, которые действительно необходимы.
  • Конфиденциальность: Не логируйте списки email без необходимости. Соблюдайте политики конфиденциальности данных (например, GDPR).
  • Admin SDK: Используйте с осторожностью, так как он дает широкий доступ к данным пользователей домена. Доступ к скриптам, использующим Admin SDK, должен быть строго ограничен.
  • Избегайте хардкодинга: Не вставляйте email адреса напрямую в код. Используйте свойства скрипта (PropertiesService) или читайте их из внешних источников (Sheets, Firestore и т.д.).

Оптимизация скриптов для работы с большим количеством адресов электронной почты

  • Пакетные операции: Читайте данные из Sheets одним вызовом getValues() вместо чтения ячеек по одной.
  • Admin SDK: Используйте параметр maxResults и пагинацию (pageToken) для эффективной обработки больших списков пользователей.
  • Квоты: Учитывайте квоты Google Apps Script (например, на количество отправленных писем в день, время выполнения скрипта). Используйте Utilities.sleep() для предотвращения превышения лимитов частоты вызовов.
  • Эффективная обработка данных: Используйте методы массивов JavaScript (map, filter, reduce) для обработки данных вместо циклов по ячейкам Range.

Устранение распространенных проблем и ошибок

  • Exception: You do not have permission to call Session.getActiveUser().getEmail().: Пользователь не авторизовал скрипт с нужными разрешениями (userinfo.email). Попросите пользователя повторно авторизовать скрипт.
  • getEmail() возвращает пустую строку: См. раздел про getActiveUser() – возможно, пользователь из другого домена или существуют ограничения безопасности.
  • Ошибки Admin SDK (403 Forbidden): Убедитесь, что скрипт запущен администратором Workspace, API включен в проекте Google Cloud Platform, связанном со скриптом, и необходимые oauthScopes добавлены в манифест и авторизованы.
  • Превышение квот: Оптимизируйте скрипт, используйте Utilities.sleep(), рассмотрите возможность использования триггеров, запускающихся по времени, для распределения нагрузки.

Добавить комментарий