---
title: "Import kontaktów z Google Sheets do Brevo przez Apps Script"
description: "Powtarzalny przykład Google Apps Script: sprawdzanie zgody, mapowanie pól, ochrona wypisanych kontaktów i widoczne błędy API."
url: https://tajo.io/pl/blog/import-google-sheet-contacts-to-brevo-apps-script/
markdown: https://tajo.io/pl/blog/import-google-sheet-contacts-to-brevo-apps-script.md
lang: pl-PL
author: "Set Noa"
author_url: https://tajo.io/pl/set-noa/
published: 2026-04-30
updated: 2026-10-09
alternates: {en-US: /blog/import-google-sheet-contacts-to-brevo-apps-script.md, bg-BG: /bg/blog/import-google-sheet-contacts-to-brevo-apps-script.md, cs-CZ: /cz/blog/import-google-sheet-contacts-to-brevo-apps-script.md, de-DE: /de/blog/import-google-sheet-contacts-to-brevo-apps-script.md, da-DK: /dk/blog/import-google-sheet-contacts-to-brevo-apps-script.md, es-ES: /es/blog/import-google-sheet-contacts-to-brevo-apps-script.md, fr-FR: /fr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, el-GR: /gr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, hi-IN: /hi/blog/import-google-sheet-contacts-to-brevo-apps-script.md, id-ID: /in/blog/import-google-sheet-contacts-to-brevo-apps-script.md, hr-HR: /hr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, hu-HU: /hu/blog/import-google-sheet-contacts-to-brevo-apps-script.md, it-IT: /it/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ja-JP: /jp/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ko-KR: /kr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ar-SA: /ar/blog/import-google-sheet-contacts-to-brevo-apps-script.md, nl-NL: /nl/blog/import-google-sheet-contacts-to-brevo-apps-script.md, no-NO: /no/blog/import-google-sheet-contacts-to-brevo-apps-script.md, pt-BR: /pt/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ro-RO: /ro/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ru-RU: /ru/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sv-SE: /se/blog/import-google-sheet-contacts-to-brevo-apps-script.md, zh-CN: /zh-cn/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sl-SI: /sl/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sr-Latn-RS: /sr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, th-TH: /th/blog/import-google-sheet-contacts-to-brevo-apps-script.md, tr-TR: /tr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ur-PK: /ur/blog/import-google-sheet-contacts-to-brevo-apps-script.md, vi-VN: /vi/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sk-SK: /sk/blog/import-google-sheet-contacts-to-brevo-apps-script.md}
---

[Synchronizacja danych](https://tajo.io/pl/blog/?category=data-sync)

# Import kontaktów z Google Sheets do Brevo przez Apps Script

Powtarzalny przykład Google Apps Script: sprawdzanie zgody, mapowanie pól, ochrona wypisanych kontaktów i widoczne błędy API.

google apps script brevo

Jak synchronizować kontakty Google Sheets z Brevo?

Dodaj w arkuszu kolumny email, firstName, lastName i consent. Ustaw BREVO\_API\_KEY we właściwościach skryptu i ID listy w kodzie, a potem uruchom syncSheetToBrevo. Skrypt uwzględnia tylko wiersze ze zgodą, sprawdza wypisanie w Brevo, usuwa duplikaty i zatrzymuje się przy błędzie API. To Apps Script, który utrzymujesz samodzielnie, a nie natywny konektor.

[Dowiedz się więcej](https://tajo.io/pl/blog/import-google-sheet-contacts-to-brevo-apps-script/#przygotuj-arkusz-i-list%C4%99)

| Pole źródłowe | Pole docelowe | Przykładowa wartość |
| --- | --- | --- |
| `email` | `email` | `alex@example.com` |
| `firstName` | `FNAME` | `Alex` |
| `lastName` | `LNAME` | `Example` |

Arkusz z dwunastoma zapisami na wydarzenie łatwo wyeksportować raz. Przy drugim imporcie jeden adres występuje dwukrotnie, a inna osoba wypisała się już w Brevo. Powtarzalny import musi uwzględnić oba przypadki.

Skrypt korzysta z [endpointów Brevo do odczytu, tworzenia i aktualizacji kontaktów](https://developers.brevo.com/reference/create-contact). Służy do małego, planowanego importu, nie do masowego ładowania ani jako natywny konektor Google Sheets. Nie wysyła wiadomości. Za dowód zgody i utrzymanie skryptu odpowiadasz Ty.

## Przygotuj arkusz i listę

Utwórz kartę `Contacts` z dokładnie takimi nagłówkami. Użyj pól wyboru w kolumnie `consent`; ustaw `TRUE` tylko przy zgodzie na zamierzone działania marketingowe.

| email | firstName | lastName | consent |
| --- | --- | --- | --- |
| [jane@example.com](mailto:jane@example.com) | Jane | Doe | TRUE |
| [alex@example.com](mailto:alex@example.com) | Alex | Lee | FALSE |

Utwórz lub wybierz listę Brevo i wpisz jej numeryczne ID jako `LIST_ID`. Sprawdź, czy atrybuty `FNAME` i `LNAME` istnieją w Brevo; tylko te pola są mapowane. Zachowaj poza arkuszem informację, kiedy i jak uzyskano zgodę, jeśli arkusz tego nie dowodzi. Sama komórka `TRUE` nie jest dowodem.

W **Rozszerzenia → Apps Script → Ustawienia projektu → Właściwości skryptu** dodaj `BREVO_API_KEY`. Właściwości są wspólne dla użytkowników skryptu, więc ogranicz prawo edycji. Nie umieszczaj klucza w komórce ani w kodzie. Przeczytaj [zasady dostępu Google](https://developers.google.com/apps-script/guides/properties).

## Skrypt

Zastąp `Code.gs` tym przykładem. Przed uruchomieniem ustaw `LIST_ID`.

```javascript
const LIST_ID = 42; // Replace with your existing Brevo list ID.
const TAB = 'Contacts';
const BASE = 'https://api.brevo.com/v3';

function syncSheetToBrevo() {
  const key = PropertiesService.getScriptProperties().getProperty('BREVO_API_KEY');
  if (!key) throw new Error('Set BREVO_API_KEY in Script Properties first');
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TAB);
  if (!sheet) throw new Error('Contacts tab missing');
  const values = sheet.getDataRange().getValues();
  const headers = values.shift().map(h => String(h).trim());
  const columns = ['email', 'firstName', 'lastName', 'consent']
    .map(name => headers.indexOf(name));
  if (columns.includes(-1)) throw new Error('Required header missing');
  const [emailCol, firstCol, lastCol, consentCol] = columns;
  const seen = new Set();
  const result = { written: 0, skipped: 0 };

  for (const row of values) {
    const email = String(row[emailCol] || '').trim().toLowerCase();
    if (row[consentCol] !== true || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || seen.has(email)) {
      result.skipped++;
      continue;
    }
    seen.add(email);
    const path = '/contacts/' + encodeURIComponent(email);
    const current = brevo_(key, path, 'get');
    if (current.code !== 200 && current.code !== 404) {
      throw new Error(`Contact read failed (${current.code}) for row ${result.written + result.skipped + 2}`);
    }
    if (current.code === 200) {
      const contact = JSON.parse(current.text);
      if (contact.emailBlacklisted || (contact.listUnsubscribed || []).includes(LIST_ID)) {
        result.skipped++;
        continue;
      }
    }
    const attributes = {};
    if (row[firstCol] !== '') attributes.FNAME = String(row[firstCol]);
    if (row[lastCol] !== '') attributes.LNAME = String(row[lastCol]);
    const body = { attributes, listIds: [LIST_ID] };
    const saved = current.code === 404
      ? brevo_(key, '/contacts', 'post', { email, ...body })
      : brevo_(key, path, 'put', body);
    if (![201, 204].includes(saved.code)) {
      throw new Error(`Contact write failed (${saved.code}) for ${email}: ${saved.text.slice(0, 200)}`);
    }
    result.written++;
  }
  Logger.log(JSON.stringify(result));
  return result;
}

function brevo_(key, path, method, body) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const response = UrlFetchApp.fetch(BASE + path, {
      method,
      contentType: 'application/json',
      headers: { 'api-key': key },
      payload: body ? JSON.stringify(body) : undefined,
      muteHttpExceptions: true,
    });
    const code = response.getResponseCode();
    if (code !== 429) return { code, text: response.getContentText() };
    if (attempt === 2) return { code, text: response.getContentText() };
    const reset = Object.entries(response.getHeaders()).find(
      ([name]) => name.toLowerCase() === 'x-sib-ratelimit-reset'
    );
    const raw = Number(reset && reset[1]);
    const seconds = Number.isFinite(raw) && raw > 0 ? raw : 2 ** attempt;
    const waitSeconds = seconds + 2 ** attempt;
    if (waitSeconds > 60) return { code, text: response.getContentText() };
    Utilities.sleep(waitSeconds * 1000);
  }
}
```

Zapisz projekt, wybierz `syncSheetToBrevo` i kliknij **Uruchom**. Google poprosi o dostęp do Sheets i żądań zewnętrznych. W **Wykonaniach** zobaczysz końcowy zapis `{written, skipped}`. Odczyt 404 prowadzi do utworzenia kontaktu, a 200 do aktualizacji. Inne błędy odczytu zatrzymują proces. Udany zapis potwierdza żądanie kontaktowe, nie wysłanie kampanii.

Skrypt usuwa powtórzone adresy w obrębie jednego przebiegu i przy następnym ponownie odpytuje Brevo. Nigdy nie ustawia `emailBlacklisted` na `false` ani nie zmienia adresu. Jeśli Brevo zgłasza blokadę lub wypisanie z tej listy, wiersz jest pomijany nawet przy `TRUE` w arkuszu. Nie używaj tego kodu do cofania wypisania. [Brevo ostrzega](https://developers.brevo.com/reference/update-contact), że zmiana adresu zablokowanego kontaktu może usunąć blokadę.

## Sprawdź przebieg przed zaplanowaniem

Użyj listy testowej i kontaktów pod Twoją kontrolą. Uruchom skrypt z wierszem `TRUE`, wierszem `FALSE` i powtórzonym adresem: oczekuj jednego zapisu i dwóch pominięć. Wypisz kontakt testowy w Brevo i uruchom ponownie: nie powinien być zapisany. Na próbę błędu ustaw chwilowo błędny `LIST_ID`, odczytaj błąd HTTP w **Wykonaniach**, przywróć ID i powtórz. Nie testuj na prawdziwych danych klientów. Kod sprawdzono także lokalnie na symulowanych odpowiedziach Brevo, bez zapisu live.

Aby zaplanować przebiegi, wybierz **Apps Script → Wyzwalacze → Dodaj wyzwalacz**, funkcję `syncSheetToBrevo` i interwał czasowy. [Wyzwalacze działają z konta osoby, która je utworzyła](https://developers.google.com/apps-script/guides/triggers/installable). Konto musi zachować dostęp do arkusza. Zacznij od uruchomienia raz dziennie i przeglądaj błędy. Google [ogranicza czas wykonania i wywołania URL Fetch](https://developers.google.com/apps-script/guides/services/quotas); duże źródła dziel na mniejsze zadania.

Przy 429 skrypt czyta `x-sib-ratelimit-reset`, ponawia najwyżej dwa razy i zwraca 429 do późniejszego przebiegu, jeśli wymagane oczekiwanie przekracza 60 sekund. Inne błędy kończą przebieg; następny zaczyna od początku. Kontakt może wypisać się między odczytem a zapisem. Ten przykład nadaje się tylko wtedy, gdy akceptujesz to krótkie okno. Gdy wymagasz mocniejszej gwarancji, potrzebujesz uzgadniania zdarzeń, źródła prawdy o zgodzie i końcowej kontroli przed wysyłką.

Przy większych arkuszach [asynchroniczny endpoint importu Brevo](https://developers.brevo.com/reference/import-contacts) zwraca `processId`: oznacza przyjęcie zadania, nie jego zakończenie. Sprawdź wynik procesu przed ogłoszeniem sukcesu. W pokazanej ścieżce błędy są widoczne przy konkretnym kontakcie.

## Najczęściej Zadawane Pytania

**Czy potrzebujesz natywnego konektora Google Sheets?**

Nie. Przykład działa w projekcie Google Apps Script powiązanym z arkuszem i wywołuje API kontaktów Brevo. Samodzielnie utrzymujesz skrypt, klucz API i zaplanowany wyzwalacz.

**Które wiersze trafiają do Brevo?**

Tylko te z wartością TRUE w kolumnie consent i poprawnym adresem e-mail. Skrypt usuwa duplikaty w każdym przebiegu i sprawdza Brevo przed zapisem.

**Czy ponowny przebieg zapisze wypisaną osobę?**

Skrypt pomija kontakty oznaczone w Brevo jako emailBlacklisted lub wypisane z listy docelowej. Nigdy nie wysyła emailBlacklisted: false ani nie zmienia adresu e-mail. Przed produkcją sprawdź także inne źródła zgody.

**Jak wznowić nieudany przebieg?**

Sprawdź błąd w wykonaniach Apps Script, usuń przyczynę i ponownie uruchom tę samą funkcję. Zapisy używają tego samego adresu i ID listy, więc wcześniej obsłużony wiersz nie tworzy drugiego kontaktu.

## Powiązane artykuły

### [Jak zaimportować kontakty CSV lub Excel do Brevo za pomocą skryptu (Python, Node.js, cURL)](https://tajo.io/pl/blog/import-csv-contacts-to-brevo-with-a-script/)

30 kwi 2026 · 5 min czytania

CSV → Brevo

### [Jak wysłać kontakty Excel do Brevo za pomocą makra VBA (i alternatywa Office Scripts)](https://tajo.io/pl/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30 kwi 2026 · 6 min czytania

Microsoft Excel → Brevo

### [Integracje Brevo: wybierz połączenie, które można sprawdzić](https://tajo.io/pl/blog/brevo-connector-guide/)

19 sie 2026 · 3 min czytania

6 sekcji
