---
title: "Importare contatti da Google Sheets a Brevo con Apps Script"
description: "Un esempio Google Apps Script ripetibile che controlla il consenso, associa i campi, rispetta le disiscrizioni e segnala gli errori API."
url: https://tajo.io/it/blog/import-google-sheet-contacts-to-brevo-apps-script/
markdown: https://tajo.io/it/blog/import-google-sheet-contacts-to-brevo-apps-script.md
lang: it-IT
author: "Set Noa"
author_url: https://tajo.io/it/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, 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}
---

[Sincronizzazione dei dati](https://tajo.io/it/blog/?category=data-sync)

# Importare contatti da Google Sheets a Brevo con Apps Script

Un esempio Google Apps Script ripetibile che controlla il consenso, associa i campi, rispetta le disiscrizioni e segnala gli errori API.

google apps script brevo

Come importare contatti da Sheets a Brevo?

Aggiungi a un foglio le colonne email, firstName, lastName e consent. Imposta BREVO\_API\_KEY nelle proprietà dello script e l’ID della lista nel codice, poi avvia syncSheetToBrevo. Lo script considera solo le righe con consenso, controlla le disiscrizioni in Brevo, elimina i duplicati e si ferma sugli errori API. È uno script Apps Script da mantenere, non un connettore nativo.

[Scopri di più](https://tajo.io/it/blog/import-google-sheet-contacts-to-brevo-apps-script/#prepara-il-foglio-e-la-lista)

| Campo di origine | Campo di destinazione | Valore di esempio |
| --- | --- | --- |
| `email` | `email` | `alex@example.com` |
| `firstName` | `FNAME` | `Alex` |
| `lastName` | `LNAME` | `Example` |

Un foglio con dodici iscrizioni a un evento si esporta facilmente una volta. Alla seconda importazione, però, un indirizzo compare due volte e un’altra persona si è disiscritta in Brevo. Il processo deve riconoscere entrambi i casi.

Lo script usa [gli endpoint Brevo per leggere, creare e aggiornare i contatti](https://developers.brevo.com/reference/create-contact). Serve per una piccola importazione programmata, non per carichi massivi o come connettore Google Sheets nativo. Non invia email. Le prove del consenso e la gestione dello script restano a tuo carico.

## Prepara il foglio e la lista

Crea una scheda `Contacts` con queste intestazioni esatte. Usa caselle di controllo per `consent` e metti `TRUE` solo se hai il permesso per l’uso marketing previsto.

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

Crea o scegli una lista Brevo e inserisci il suo ID numerico in `LIST_ID`. Controlla che gli attributi `FNAME` e `LNAME` esistano in Brevo: sono gli unici campi associati. Conserva una prova separata di quando e come è stato dato il consenso se il foglio non può dimostrarlo. Una cella `TRUE` non basta.

In **Estensioni → Apps Script → Impostazioni progetto → Proprietà dello script**, aggiungi `BREVO_API_KEY`. Le proprietà sono condivise tra gli utenti dello script: limita chi può modificarlo. Non mettere la chiave in una cella o nel codice. Consulta le [regole di accesso di Google](https://developers.google.com/apps-script/guides/properties).

## Lo script

Sostituisci `Code.gs` con l’esempio e imposta `LIST_ID` prima dell’avvio.

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

Salva, scegli `syncSheetToBrevo` e premi **Esegui**. Google chiede accesso a Sheets e alle richieste esterne. In **Esecuzioni** trovi il riepilogo `{written, skipped}`. Un 404 nella lettura porta a creare il contatto; un 200 ad aggiornarlo. Altri errori interrompono la procedura. Una scrittura riuscita conferma la richiesta di contatto, non l’invio di una campagna.

Lo script elimina gli indirizzi duplicati nella stessa esecuzione e ricontrolla Brevo alla successiva. Non imposta `emailBlacklisted` su `false` e non cambia l’email. Se Brevo segnala un blocco generale o una disiscrizione da questa lista, la riga viene saltata anche con `TRUE` nel foglio. Non usare questo esempio per annullare una disiscrizione. [Brevo avverte](https://developers.brevo.com/reference/update-contact) che cambiare l’indirizzo di un contatto bloccato può togliere il blocco.

## Verifica una prova prima di programmare

Usa una lista di test e contatti che controlli. Avvia una prova con una riga `TRUE`, una `FALSE` e un indirizzo duplicato: aspettati una scrittura e due righe saltate. Disiscrivi il contatto di test in Brevo e ripeti: per lui non deve esserci alcuna scrittura. Per verificare un errore, imposta temporaneamente un `LIST_ID` non valido, controlla il codice HTTP in **Esecuzioni**, ripristina l’ID e riprova. Non usare dati di clienti reali. Il codice è stato anche provato localmente con risposte Brevo simulate, senza scritture live.

Per pianificare la funzione, apri **Apps Script → Trigger → Aggiungi trigger**, scegli `syncSheetToBrevo` e un intervallo temporale. [I trigger installabili girano con l’account di chi li ha creati](https://developers.google.com/apps-script/guides/triggers/installable); l’account deve mantenere accesso al foglio. Inizia con una prova giornaliera e controlla gli errori. Google [limita durata e chiamate URL Fetch](https://developers.google.com/apps-script/guides/services/quotas); dividi fonti grandi in lavori limitati.

Per un 429 lo script legge `x-sib-ratelimit-reset`, riprova al massimo due volte e restituisce 429 per un’esecuzione successiva se l’attesa necessaria supera 60 secondi. Gli altri errori fermano l’esecuzione; la successiva ricomincia dall’inizio. Un contatto può disiscriversi tra lettura e scrittura. Usa questo esempio solo se quel breve intervallo è accettabile. Per garanzie più strette servono riconciliazione per eventi, una fonte autorevole del consenso e un ultimo controllo prima dell’invio.

Per fogli grandi, l’[endpoint di importazione asincrona di Brevo](https://developers.brevo.com/reference/import-contacts) restituisce un `processId`: conferma l’accettazione del lavoro, non il suo completamento. Controlla l’esito prima di dichiarare riuscita l’importazione. Con questa via per singolo contatto, invece, l’errore resta visibile sulla riga coinvolta.

## Domande frequenti

**Serve un connettore Google Sheets nativo?**

No. L’esempio gira in un progetto Google Apps Script collegato al foglio e chiama l’API dei contatti Brevo. Gestisci tu script, chiave API e trigger programmato.

**Quali righe vengono inviate a Brevo?**

Solo quelle con TRUE nella colonna consent e un indirizzo email valido. Lo script rimuove i duplicati in ogni esecuzione e controlla Brevo prima di scrivere.

**Una nuova esecuzione reiscrive chi si è disiscritto?**

Lo script salta i contatti che Brevo segnala come emailBlacklisted o disiscritti dalla lista scelta. Non imposta emailBlacklisted su false e non modifica l’indirizzo email. Controlla anche le altre fonti di consenso prima della produzione.

**Come riprovo dopo un errore?**

Leggi l’errore nelle esecuzioni Apps Script, correggi la causa e avvia di nuovo la stessa funzione. Le scritture usano lo stesso indirizzo e ID lista, quindi una riga già riuscita non crea un secondo contatto.

## Articoli correlati

### [Come importare contatti CSV o Excel in Brevo con uno script (Python, Node.js, cURL)](https://tajo.io/it/blog/import-csv-contacts-to-brevo-with-a-script/)

30 apr 2026 · 6 min di lettura

CSV → Brevo

### [Come spingere i contatti Excel in Brevo con una macro VBA (e l'alternativa Office Scripts)](https://tajo.io/it/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30 apr 2026 · 7 min di lettura

Microsoft Excel → Brevo

### [Integrazioni Brevo: scegli un collegamento verificabile](https://tajo.io/it/blog/brevo-connector-guide/)

19 ago 2026 · 5 min di lettura

6 sezioni
