---
title: "Import kontaktů z Google Sheets do Brevo pomocí Apps Script"
description: "Opakovatelný příklad Google Apps Script: ověření souhlasu, mapování polí, ochrana odhlášení a viditelné chyby API."
url: https://tajo.io/cz/blog/import-google-sheet-contacts-to-brevo-apps-script/
markdown: https://tajo.io/cz/blog/import-google-sheet-contacts-to-brevo-apps-script.md
lang: cs-CZ
author: "Set Noa"
author_url: https://tajo.io/cz/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, 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, pl-PL: /pl/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}
---

[Synchronizace dat](https://tajo.io/cz/blog/?category=data-sync)

# Import kontaktů z Google Sheets do Brevo pomocí Apps Script

Opakovatelný příklad Google Apps Script: ověření souhlasu, mapování polí, ochrana odhlášení a viditelné chyby API.

google apps script brevo

Jak synchronizovat kontakty z Google Sheets do Breva?

Přidejte do listu sloupce email, firstName, lastName a consent. Nastavte BREVO\_API\_KEY ve vlastnostech skriptu a ID seznamu v kódu, pak spusťte syncSheetToBrevo. Skript bere jen řádky se souhlasem, kontroluje odhlášení v Brevo, odstraňuje duplicity a zastaví se při chybě API. Jde o Apps Script, který spravujete Vy, nikoli o nativní konektor.

[Zjistit více](https://tajo.io/cz/blog/import-google-sheet-contacts-to-brevo-apps-script/#p%C5%99ipravte-list-a-seznam)

| Zdrojové pole | Cílové pole | Ukázková hodnota |
| --- | --- | --- |
| `email` | `email` | `alex@example.com` |
| `firstName` | `FNAME` | `Alex` |
| `lastName` | `LNAME` | `Example` |

List s dvanácti registracemi na akci snadno vyexportujete jednou. Při druhém importu se jedna adresa opakuje a další člověk se mezitím v Brevo odhlásil. Opakovatelný import musí rozpoznat obojí.

Skript používá [endpointy Brevo pro čtení, vytvoření a aktualizaci kontaktů](https://developers.brevo.com/reference/create-contact). Je určen pro malé plánované importy, ne pro hromadné načítání nebo jako nativní konektor Google Sheets. E-maily neposílá. Za důkaz souhlasu a provoz skriptu odpovídáte Vy.

## Připravte list a seznam

Vytvořte kartu `Contacts` přesně s těmito záhlavími. Pro `consent` použijte zaškrtávací políčka a `TRUE` nastavte jen se souhlasem pro zamýšlený marketing.

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

Vytvořte nebo vyberte seznam Brevo a jeho číselné ID zadejte do `LIST_ID`. Ověřte, že kontaktní atributy `FNAME` a `LNAME` v Brevo existují. Mapují se jen tato dvě pole. Záznam o čase a způsobu získání souhlasu uchovejte zvlášť, pokud jej list nedokáže doložit. Buňka `TRUE` sama o sobě důkazem není.

V **Rozšíření → Apps Script → Nastavení projektu → Vlastnosti skriptu** přidejte `BREVO_API_KEY`. Vlastnosti jsou sdílené mezi uživateli skriptu, proto omezte oprávnění k úpravám. Klíč nedávejte do buňky ani do zdrojového kódu. Viz [pravidla přístupu Google](https://developers.google.com/apps-script/guides/properties).

## Skript

Nahraďte `Code.gs` tímto příkladem a před prvním spuštěním nastavte `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);
  }
}
```

Uložte projekt, vyberte `syncSheetToBrevo` a klikněte na **Spustit**. Google požádá o přístup k Sheets a externím požadavkům. Ve **Spuštěních** najdete souhrn `{written, skipped}`. Odpověď 404 při čtení vede k vytvoření kontaktu, 200 k aktualizaci. Jiné chyby běh zastaví. Úspěšný zápis potvrzuje kontaktní požadavek, nikoli odeslání kampaně.

Skript odstraní duplicitní adresy v jednom běhu a v dalším se znovu zeptá Brevo. Nikdy nenastavuje `emailBlacklisted` na `false` ani nemění e-mail. Pokud Brevo ukazuje blokaci nebo odhlášení z daného seznamu, řádek přeskočí i při `TRUE` v listu. Nepoužívejte jej k vrácení odhlášení. [Brevo upozorňuje](https://developers.brevo.com/reference/update-contact), že změna adresy blokovaného kontaktu může blokaci zrušit.

## Ověřte jeden běh před plánováním

Použijte testovací seznam a kontakty pod Vaší kontrolou. Spusťte skript s jedním řádkem `TRUE`, jedním `FALSE` a duplicitní adresou: očekávejte jeden zápis a dva přeskočené řádky. Testovací kontakt v Brevo odhlaste a spusťte znovu: nesmí dojít k zápisu. Pro test chyby nastavte dočasně neplatné `LIST_ID`, ověřte HTTP chybu ve **Spuštěních**, vraťte správné ID a opakujte. Netestujte na skutečných zákaznických datech. Kód byl také ověřen místně s napodobenými odpověďmi Brevo, bez živého zápisu.

Pro pravidelné běhy otevřete **Apps Script → Spouštěče → Přidat spouštěč**, vyberte `syncSheetToBrevo` a časový interval. [Instalovatelné spouštěče běží pod účtem tvůrce](https://developers.google.com/apps-script/guides/triggers/installable); účet musí mít stále přístup k listu. U malého listu začněte denně a kontrolujte chyby. Google [omezuje délku běhu a volání URL Fetch](https://developers.google.com/apps-script/guides/services/quotas); větší zdroje rozdělte na omezené úlohy.

Při 429 skript čte `x-sib-ratelimit-reset` a opakuje nejvýše dvakrát. Pokud nutné čekání přesáhne 60 sekund, vrátí 429 pro pozdější běh. Jiné chyby běh zastaví; další začne od začátku. Kontakt se může odhlásit mezi čtením a zápisem. Příklad použijte jen tehdy, když je toto krátké okno přijatelné. Přísnější záruky vyžadují soulad událostí, autoritativní zdroj souhlasu a poslední kontrolu před odesláním.

Pro větší listy [asynchronní importní endpoint Brevo](https://developers.brevo.com/reference/import-contacts) vrací `processId`. Potvrzuje přijetí úlohy, ne dokončení. Před prohlášením úspěchu zkontrolujte výsledek. Tato cesta po jednotlivých kontaktech ukáže chybu u dotčeného řádku.

## Často Kladené Otázky

**Potřebujete nativní konektor Google Sheets?**

Ne. Příklad běží v projektu Google Apps Script navázaném na list a volá kontaktní API Brevo. Skript, API klíč a naplánovaný spouštěč spravujete Vy.

**Které řádky se odešlou do Brevo?**

Pouze řádky s TRUE ve sloupci consent a platnou e-mailovou adresou. Skript v každém běhu odstraní duplicity a před zápisem zkontroluje Brevo.

**Přihlásí další běh znovu odhlášený kontakt?**

Skript přeskočí kontakty, které Brevo označuje jako emailBlacklisted nebo odhlášené z cílového seznamu. Nikdy neposílá emailBlacklisted: false ani nemění adresu. Před produkcí ověřte i další zdroje souhlasu.

**Jak zopakovat neúspěšný běh?**

Přečtěte chybu v záznamu spuštění Apps Script, opravte příčinu a spusťte stejnou funkci znovu. Zápisy používají stejnou adresu a ID seznamu, takže dříve úspěšný řádek nevytvoří druhý kontakt.

## Související články

### [Jak importovat kontakty z CSV nebo Excelu do Brevo pomocí skriptu (Python, Node.js, cURL)](https://tajo.io/cz/blog/import-csv-contacts-to-brevo-with-a-script/)

30\. 4. 2026 · 5 min čtení

CSV → Brevo

### [Jak poslat kontakty z Excelu do Brevo pomocí VBA makra (a alternativa Office Scripts)](https://tajo.io/cz/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30\. 4. 2026 · 6 min čtení

Microsoft Excel → Brevo

### [Integrace Brevo: vyberte ověřitelné propojení](https://tajo.io/cz/blog/brevo-connector-guide/)

19\. 8. 2026 · 3 min čtení

6 sekcí
