Uvoz kontakata iz Google Sheetsa u Brevo pomoću Apps Scripta

Ponovljiv primjer Google Apps Scripta koji provjerava privolu, mapira polja, čuva odjave i pokazuje pogreške API-ja.

google apps script brevo

Koji je kratak odgovor?

Dodajte u tablicu stupce email, firstName, lastName i consent. Postavite BREVO_API_KEY u svojstva skripte i ID popisa u kod, pa pokrenite syncSheetToBrevo. Skripta obrađuje samo retke s privolom, provjerava odjave u Brevu, uklanja duplikate i zaustavlja se na pogrešci API-ja. To je Apps Script koji sami održavate, a ne ugrađeni poveznik.

Saznajte više
Na ovoj stranici

Tablicu s dvanaest prijava na događaj lako je izvesti jednom. Pri drugom uvozu jedna se adresa ponavlja, a druga se osoba odjavila u Brevu. Ponovljiv uvoz mora prepoznati oba slučaja.

Skripta koristi Brevo krajnje točke za čitanje, stvaranje i ažuriranje kontakata. Namijenjena je malim planiranim uvozima, a ne masovnom učitavanju ni ulozi ugrađenog poveznika za Google Sheets. Ne šalje e-poštu. Za dokaz privole i rad skripte odgovorni ste vi.

Pripremite tablicu i popis

Stvorite karticu Contacts s točno ovim zaglavljima. Za consent koristite potvrdne okvire i postavite TRUE samo ako postoji privola za planirani marketing.

emailfirstNamelastNameconsent
[email protected]JaneDoeTRUE
[email protected]AlexLeeFALSE

Stvorite ili odaberite Brevo popis te njegov brojčani ID unesite kao LIST_ID. Provjerite postoje li atributi FNAME i LNAME u Brevu. Samo su ta polja mapirana. Dokaz o tome kada i kako je privola dana spremite drugdje ako ga tablica ne može pružiti. Ćelija TRUE nije dokaz.

Pod Proširenja → Apps Script → Postavke projekta → Svojstva skripte dodajte BREVO_API_KEY. Svojstva dijele korisnici skripte, stoga ograničite pravo uređivanja. Ključ ne stavljajte u ćeliju ni u kod. Pročitajte Googleova pravila pristupa.

Skripta

Zamijenite Code.gs ovim primjerom i prije prvog pokretanja postavite LIST_ID.

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

Spremite, odaberite syncSheetToBrevo i kliknite Pokreni. Google traži pristup Sheetsu i vanjskim zahtjevima. Pod Izvršavanja je završni zapis {written, skipped}. Odgovor 404 pri čitanju vodi stvaranju kontakta, 200 ažuriranju. Druge pogreške zaustavljaju rad. Uspješan zapis potvrđuje zahtjev za kontakt, ne slanje kampanje.

Skripta uklanja dvostruke adrese u jednom pokretanju i ponovno pita Brevo pri idućem. Nikad ne postavlja emailBlacklisted na false i ne mijenja e-poštu. Ako Brevo prijavi blokadu ili odjavu s tog popisa, redak se preskače i uz TRUE u tablici. Ne koristite skriptu za poništavanje odjave. Brevo upozorava da promjena adrese blokiranog kontakta može ukloniti blokadu.

Provjerite pokretanje prije rasporeda

Koristite testni popis i kontakte koje nadzirete. Pokrenite s jednim retkom TRUE, jednim FALSE i dvostrukom adresom: očekujte jedan zapis i dva preskočena retka. Odjavite testni kontakt u Brevu i ponovite: za njega ne smije biti zapisa. Za ispitivanje pogreške privremeno postavite nevaljani LIST_ID, provjerite HTTP pogrešku pod Izvršavanja, vratite ID i pokušajte ponovno. Ne testirajte na pravim podacima kupaca. Kod je provjeren lokalno i sa simuliranim odgovorima Breva, bez stvarnog zapisivanja.

Za raspored otvorite Apps Script → Okidači → Dodaj okidač, odaberite syncSheetToBrevo i vremenski interval. Okidači se izvršavaju pod računom osobe koja ih je stvorila, pa račun mora zadržati pristup tablici. Za malu tablicu krenite jednom dnevno i pratite pogreške. Google ograničava vrijeme izvođenja i pozive URL Fetch; velike izvore podijelite u ograničene zadatke.

Pri 429 skripta čita x-sib-ratelimit-reset i ponavlja najviše dvaput. Ako potrebno čekanje prelazi 60 sekundi, vraća 429 za kasnije pokretanje. Druge pogreške zaustavljaju rad; idući put kreće ispočetka. Kontakt se može odjaviti između čitanja i zapisa. Primjer rabite samo ako je taj kratak prozor prihvatljiv. Stroža jamstva traže usklađivanje događaja, pouzdan izvor privole i posljednju provjeru prije slanja.

Za veće tablice asinkrona Brevo točka za uvoz vraća processId. To potvrđuje prihvat zadatka, ne dovršetak. Provjerite rezultat prije objave uspjeha. Put po pojedinačnim kontaktima ovdje otkriva pogrešku na dotičnom retku.

Često postavljana pitanja

Treba li vam ugrađeni poveznik za Google Sheets?

Ne. Primjer se izvršava u projektu Google Apps Script povezanom s tablicom i poziva Brevo API za kontakte. Skriptu, API ključ i zakazani okidač održavate sami.

Koji se retci šalju u Brevo?

Samo oni s TRUE u consent i valjanom adresom e-pošte. Skripta uklanja duplikate pri svakom pokretanju i provjerava Brevo prije zapisivanja.

Prijavljuje li novo pokretanje odjavljeni kontakt?

Skripta preskače kontakte koje Brevo označi kao emailBlacklisted ili odjavljene s ciljnog popisa. Nikad ne šalje emailBlacklisted: false i ne mijenja adresu. Prije produkcije provjerite druge izvore privole.

Kako ponoviti neuspjelo pokretanje?

Pročitajte pogrešku u izvršavanjima Apps Scripta, otklonite uzrok i pokrenite istu funkciju ponovno. Zapisi rabe istu adresu i ID popisa, pa uspješan redak ne stvara drugi kontakt.

Zatražite rani pristup

Unesite ime i poslovnu adresu e-pošte. Poslat ćemo vam poveznicu za potvrdu zahtjeva za pristup Taju.

Nabavi Brevo