---
title: "Importér kontakter fra Google Sheets til Brevo med Apps Script"
description: "Et gentageligt Google Apps Script, der tjekker samtykke, kortlægger felter, respekterer afmeldinger og viser API-fejl."
url: https://tajo.io/dk/blog/import-google-sheet-contacts-to-brevo-apps-script/
markdown: https://tajo.io/dk/blog/import-google-sheet-contacts-to-brevo-apps-script.md
lang: da-DK
author: "Set Noa"
author_url: https://tajo.io/dk/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, 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}
---

[Datasynkronisering](https://tajo.io/dk/blog/?category=data-sync)

# Importér kontakter fra Google Sheets til Brevo med Apps Script

Et gentageligt Google Apps Script, der tjekker samtykke, kortlægger felter, respekterer afmeldinger og viser API-fejl.

google apps script brevo

Hvordan importerer du Sheets-kontakter til Brevo?

Tilføj kolonnerne email, firstName, lastName og consent til et ark. Gem BREVO\_API\_KEY i scriptegenskaberne og liste-id i koden, og kør syncSheetToBrevo. Scriptet behandler kun rækker med samtykke, tjekker afmeldinger i Brevo, fjerner dubletter og stopper ved API-fejl. Det er et Apps Script, du selv vedligeholder, ikke en indbygget forbindelse.

[Læs mere](https://tajo.io/dk/blog/import-google-sheet-contacts-to-brevo-apps-script/#forbered-arket-og-listen)

| Kildefelt | Destinationsfelt | Eksempelværdi |
| --- | --- | --- |
| `email` | `email` | `alex@example.com` |
| `firstName` | `FNAME` | `Alex` |
| `lastName` | `LNAME` | `Example` |

Et ark med tolv tilmeldinger til et arrangement er nemt at eksportere én gang. Ved næste import står én adresse der to gange, og en anden person har afmeldt sig i Brevo. En gentagelig import skal håndtere begge dele.

Scriptet bruger [Brevos endepunkter til at læse, oprette og opdatere kontakter](https://developers.brevo.com/reference/create-contact). Det er til små, planlagte importer, ikke masseindlæsning eller som en indbygget Google Sheets-forbindelse. Det sender ikke e-mails. Du har ansvaret for samtykkedokumentation og drift.

## Forbered arket og listen

Opret fanen `Contacts` med præcis disse overskrifter. Brug afkrydsningsfelter i `consent`, og sæt kun `TRUE`, når du har lov til den tiltænkte markedsføring.

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

Opret eller vælg en Brevo-liste, og indsæt dens numeriske id i `LIST_ID`. Kontroller, at kontaktattributterne `FNAME` og `LNAME` findes i Brevo. Kun disse felter er knyttet til arket. Gem dokumentation for hvornår og hvordan samtykket blev givet, hvis arket ikke kan vise det. En `TRUE`-celle er ikke bevis.

Under **Udvidelser → Apps Script → Projektindstillinger → Scriptegenskaber** tilføjer du `BREVO_API_KEY`. Egenskaberne deles af scriptets brugere. Begræns derfor hvem der kan redigere projektet. Læg ikke nøglen i en celle eller i kildekoden. Læs [Googles adgangsregler](https://developers.google.com/apps-script/guides/properties).

## Scriptet

Erstat `Code.gs` med eksemplet, og sæt `LIST_ID` før første kørsel.

```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);
  }
}
```

Gem projektet, vælg `syncSheetToBrevo`, og klik **Kør**. Google beder om adgang til Sheets og eksterne forespørgsler. Under **Kørsler** finder du slutloggen `{written, skipped}`. Et 404 ved læsning fører til oprettelse; 200 fører til opdatering. Andre læsefejl stopper kørslen. En vellykket skrivning bekræfter kontaktforespørgslen, ikke en sendt kampagne.

Scriptet fjerner dublerede adresser i samme kørsel og spørger Brevo igen ved næste. Det sætter aldrig `emailBlacklisted` til `false` og ændrer ikke e-mailadressen. Hvis Brevo viser global blokering eller afmelding fra listen, springes rækken over, selv om arket viser `TRUE`. Brug ikke scriptet til at omgøre en afmelding. [Brevo advarer](https://developers.brevo.com/reference/update-contact) om, at ændring af en blokeret kontakts adresse kan fjerne blokeringen.

## Kontroller én kørsel før planlægning

Brug en testliste og kontakter, du styrer. Kør med én `TRUE`-række, én `FALSE`-række og en dublet: forvent én skrivning og to oversprungne rækker. Afmeld testkontakten i Brevo, og kør igen: den må ikke skrives. Test en fejl ved midlertidigt at sætte `LIST_ID` til en ugyldig værdi. Se HTTP-fejlen under **Kørsler**, gendan id’et, og prøv igen. Brug ikke rigtige kundedata til testen. Koden er også testet lokalt med simulerede Brevo-svar uden live-skrivning.

For en tidsplan åbner du **Apps Script → Udløsere → Tilføj udløser**, vælger `syncSheetToBrevo` og et tidsinterval. [Installerbare udløsere kører under kontoen, som oprettede dem](https://developers.google.com/apps-script/guides/triggers/installable). Kontoen skal bevare adgang til arket. Begynd dagligt for et lille ark og gennemgå fejl. Google [begrænser køretid og URL Fetch-kald](https://developers.google.com/apps-script/guides/services/quotas); del større kilder i afgrænsede jobs.

Ved 429 læser scriptet `x-sib-ratelimit-reset` og prøver højst to gange mere. Hvis nødvendig ventetid overstiger 60 sekunder, returnerer det 429 til en senere kørsel. Andre fejl stopper kørslen; den næste begynder fra toppen. En kontakt kan afmelde sig mellem læsning og skrivning. Brug kun eksemplet, hvis det korte tidsvindue er acceptabelt. Strammere garantier kræver afstemning via hændelser, en autoritativ samtykkekilde og en sidste kontrol før udsendelse.

For større ark returnerer [Brevos asynkrone importendepunkt](https://developers.brevo.com/reference/import-contacts) en `processId`. Den bekræfter modtagelse af jobbet, ikke færdiggørelse. Kontroller resultatet, før du kalder en større import vellykket. Her er en fejl synlig ved den berørte kontakt.

## Ofte Stillede Spørgsmål

**Kræver det en indbygget Google Sheets-forbindelse?**

Nej. Eksemplet kører i et Google Apps Script-projekt knyttet til arket og kalder Brevos kontakt-API. Du vedligeholder selv scriptet, API-nøglen og den planlagte udløser.

**Hvilke rækker sendes til Brevo?**

Kun rækker med TRUE i consent og en gyldig e-mailadresse. Scriptet fjerner dubletter i hver kørsel og tjekker Brevo før skrivning.

**Tilmeldes en afmeldt kontakt igen ved næste kørsel?**

Scriptet springer kontakter over, som Brevo markerer som emailBlacklisted eller afmeldt fra mållisten. Det sender aldrig emailBlacklisted: false og ændrer ikke e-mailadressen. Tjek andre samtykkekilder før produktion.

**Hvordan gentager jeg en mislykket kørsel?**

Læs fejlen under Apps Script-kørsler, ret årsagen, og kør samme funktion igen. Skrivningerne bruger samme adresse og liste-id, så en tidligere behandlet række opretter ikke en ekstra kontakt.

## Relaterede artikler

### [Sådan importerer du CSV- eller Excel-kontakter til Brevo med et script (Python, Node.js, cURL)](https://tajo.io/dk/blog/import-csv-contacts-to-brevo-with-a-script/)

30\. apr. 2026 · 5 min læsetid

CSV → Brevo

### [Sådan skubber du Excel-kontakter til Brevo med en VBA-makro (og Office Scripts-alternativet)](https://tajo.io/dk/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30\. apr. 2026 · 6 min læsetid

Microsoft Excel → Brevo

### [Brevo-integrationer: vælg en forbindelse, du kan verificere](https://tajo.io/dk/blog/brevo-connector-guide/)

19\. aug. 2026 · 3 min læsetid

6 afsnit
