Kako uvoziti stike iz CSV ali Excela v Brevo s skripto (Python, Node.js, cURL)

Množični uvoz stikov iz datoteke CSV ali Excel v Brevo z API-jem import-contacts. Vključuje pripravljene skripte v Pythonu in Node.js, eno vrstico cURL, obravnavanje napak in nasvete za datoteke, večje od 10 MB.

Featured image for article: Kako uvoziti stike iz CSV ali Excela v Brevo s skripto (Python, Node.js, cURL)

Če ste kdaj morali poslati nekaj tisoč stikov iz preglednice v Brevo, veste, da ročna pot prek vmesnika hitro postane mučna: izberite datoteko, mapirajte stolpce, izberite seznam, počakajte, ponovite. Skripta opravi isto delo v sekundah in, kar je še pomembneje, lahko jo ponovno zaženete po urniku, po izvozu iz baze podatkov ali kadarkoli vaš CRM izvrže svežo CSV.

Ta vodnik pokriva API endpoint, ki ga Brevo nudi prav za to, s polno delujočimi skriptami v Pythonu, Node.js in eno vrstico cURL. Vse v tem vodniku gre na POST /v3/contacts/import.

Endpoint na hitro

POST https://api.brevo.com/v3/contacts/import
Content-Type: application/json
api-key: YOUR_API_KEY
{
"fileBody": "EMAIL;FIRSTNAME;LASTNAME\n[email protected];Jane;Doe",
"listIds": [42],
"updateExistingContacts": true,
"emailBlacklist": false,
"smsBlacklist": false
}

Odziv pride hitro:

{ "processId": 78 }

To je 202 Accepted. Brevo je sprejel uvoz in ga obdeluje v ozadju. processId je vaš ročaj za sledenje, če želite preverjati dokončanje ali nastaviti webhook notifyUrl.

Nekaj stvari, ki jih je vredno omeniti, preden začnete pisati kodo:

  • Telo je lahko CSV (fileBody), JSON (jsonBody) ali oddaljeni URL (fileUrl). Izberite eno. Oblika CSV uporablja podpičja (;) za ločevanje stolpcev, ne vejic. To je pogosta past.
  • fileBody in jsonBody sta omejena na 10 MB. Brevo priporoča, da za varnost ostanete okoli 8 MB. Za karkoli večjega naložite datoteko na S3, GCS ali katerokoli HTTPS gostovanje in namesto tega posredujte fileUrl.
  • Lastni atributi, ki ne obstajajo v vašem računu, se tiho prezrejo. Ustvarite jih v vmesniku Brevo (ali prek Attributes API), preden uvozite vrstice, ki jih uporabljajo, sicer podatki preprosto izginejo.
  • updateExistingContacts ima privzeto vrednost true. Če ga nastavite na false, Brevo preskoči stike, katerih e-pošta že obstaja. Uporabno za naloge tipa „dodaj samo nove”.
  • emptyContactsAttributes nadzira, ali naj prazne celice v vašem CSV izbrišejo obstoječe vrednosti. Privzeto false (prazne celice so prezrte). Nastavite na true, če je vaš CSV vir resnice in želite, da prazne vrednosti počistijo zastarele podatke.

Pridobite API ključ

Prijavite se v Brevo, pojdite na Settings → SMTP & API → API Keys in ustvarite nov ključ. Izgleda kot xkeysib-.... Posredovali ga boste kot HTTP glavo api-key pri vsaki zahtevi. Obravnavajte ga kot geslo. Ima poln dostop za branje in pisanje na vaš račun.

Čist vzorec: dajte ga v okoljsko spremenljivko, da nikoli ne pristane v vašem izvornem drevesu.

Terminal window
export BREVO_API_KEY="xkeysib-..."

Python: preberite CSV in ga pošljite v Brevo

To je najpreprostejša možna skripta: preberite lokalni CSV s standardno knjižnico in telo pošljite naravnost v Brevo. Ne potrebujete SDK tretje osebe razen requests.

import_csv_to_brevo.py
import csv
import io
import os
import sys
import requests
API_KEY = os.environ["BREVO_API_KEY"]
LIST_ID = 42 # the Brevo list to add contacts to
INPUT_FILE = sys.argv[1] if len(sys.argv) > 1 else "contacts.csv"
# Brevo wants semicolon-separated CSV. If your file uses commas (most do),
# convert it on the fly so you don't have to edit the source spreadsheet.
def to_brevo_csv(path: str) -> str:
with open(path, newline="", encoding="utf-8") as f:
reader = csv.reader(f) # default: comma-separated
out = io.StringIO()
writer = csv.writer(out, delimiter=";")
for row in reader:
writer.writerow(row)
return out.getvalue()
body = {
"fileBody": to_brevo_csv(INPUT_FILE),
"listIds": [LIST_ID],
"updateExistingContacts": True,
"emptyContactsAttributes": False,
"emailBlacklist": False,
"smsBlacklist": False,
}
resp = requests.post(
"https://api.brevo.com/v3/contacts/import",
json=body,
headers={"api-key": API_KEY, "Content-Type": "application/json"},
timeout=60,
)
if resp.status_code != 202:
print(f"Import failed: {resp.status_code} {resp.text}")
sys.exit(1)
process_id = resp.json()["processId"]
print(f"Import accepted. Process ID: {process_id}")

Zaženite jo:

Terminal window
python import_csv_to_brevo.py contacts.csv

Prva vrstica vašega CSV je glava. Imena stolpcev se mapirajo na atribute Brevo prek velikih črk, natančno ujemanje: EMAIL, FIRSTNAME, LASTNAME, plus vsak lastni atribut, ki ste ga definirali. EMAIL je obvezen.

EMAIL,FIRSTNAME,LASTNAME,COMPANY,CITY
[email protected],Jane,Doe,Acme,Berlin
[email protected],John,Smith,Globex,Paris

To je celoten potek. Skripta se vrne v sekundi. Sam uvoz teče na strani strežnika in traja od nekaj sekund do nekaj minut, odvisno od količine.

Excelove datoteke: tri sprejemljive poti

Brevo uvozni endpoint ne bere .xlsx neposredno, zato imate tri prave možnosti, odvisno od tega, kje mora delo živeti:

  1. Zaženite VBA makro znotraj delovnega zvezka. Sinhronizacija iz samega Excela z enim klikom, brez zunanje skripte. To je pravi odgovor, ko datoteka živi na namizju in vaša ekipa želi gumb na listu. Polna koda v vodniku za VBA makro Excel-v-Brevo.
  2. Office Scripts + Power Automate. Če delovni zvezek živi v OneDrive/SharePoint in želite nenadzorovano sinhronizacijo po urniku. Pokrito tudi v Excel vodniku.
  3. Pretvorite .xlsx v CSV iz skripte. To pokriva preostanek tega odseka. Najboljše, če že poganjate Python ali Node na strežniku in morate samo enkrat dnevno potegniti delovni zvezek.

Za možnost 3 je pandas ena vrstica:

# pip install pandas openpyxl
import pandas as pd
def xlsx_to_brevo_csv(path: str, sheet_name: str | int = 0) -> str:
df = pd.read_excel(path, sheet_name=sheet_name)
return df.to_csv(sep=";", index=False)
body["fileBody"] = xlsx_to_brevo_csv("contacts.xlsx")

Če ne želite pandas kot odvisnost, sam openpyxl deluje:

from openpyxl import load_workbook
import csv, io
def xlsx_to_brevo_csv(path: str) -> str:
wb = load_workbook(path, read_only=True)
ws = wb.active
out = io.StringIO()
writer = csv.writer(out, delimiter=";")
for row in ws.iter_rows(values_only=True):
writer.writerow(["" if v is None else v for v in row])
return out.getvalue()

Node.js: isto delo, uradni SDK

Brevo objavlja @getbrevo/brevo za Node. Poskrbi za avtentikacijo, ponovne poskuse in tipizirano obliko zahteve:

import-csv-to-brevo.mjs
// npm install @getbrevo/brevo
import fs from 'node:fs/promises';
import { BrevoClient } from '@getbrevo/brevo';
const API_KEY = process.env.BREVO_API_KEY;
const LIST_ID = 42;
const INPUT_FILE = process.argv[2] ?? 'contacts.csv';
const client = new BrevoClient({ apiKey: API_KEY });
// Read the CSV and convert commas to semicolons if needed
const raw = await fs.readFile(INPUT_FILE, 'utf-8');
const csv = raw.includes(';') ? raw : raw.replace(/,/g, ';');
const result = await client.contacts.importContacts({
fileBody: csv,
listIds: [LIST_ID],
updateExistingContacts: true,
emptyContactsAttributes: false,
});
console.log(`Import accepted. Process ID: ${result.processId}`);

Ali pa, če nočete SDK, navaden fetch deluje enako:

const resp = await fetch('https://api.brevo.com/v3/contacts/import', {
method: 'POST',
headers: {
'api-key': process.env.BREVO_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileBody: csv,
listIds: [42],
updateExistingContacts: true,
}),
});
if (resp.status !== 202) {
throw new Error(`Import failed: ${resp.status} ${await resp.text()}`);
}
const { processId } = await resp.json();
console.log(`Process ID: ${processId}`);

cURL: ena vrstica za priložnostne uvoze

Ko želite samo preizkusiti endpoint ali ročno potisniti majhno datoteko:

Terminal window
# Convert commas to semicolons, then send the file inline
csv=$(sed 's/,/;/g' contacts.csv | jq -Rs .)
curl -X POST https://api.brevo.com/v3/contacts/import \
-H "api-key: $BREVO_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"fileBody\": $csv, \"listIds\": [42], \"updateExistingContacts\": true}"

jq -Rs . pogoltne celotno datoteko in jo JSON-ubeži, kar vas reši ročnega ubežanja prelomov vrstic in narekovajev.

Datoteke, večje od 10 MB: uporabite fileUrl

fileBody je omejen na 10 MB. Če je vaš izvoz stikov večji, gostujte datoteko na URL-ju, ki ga Brevo lahko pridobi, in posredujte tega:

body = {
"fileUrl": "https://files.example.com/contacts/2026-04-30.csv",
"listIds": [42],
"updateExistingContacts": True,
}

Vse, kar je dosegljivo prek javnega HTTPS URL-ja, deluje: predpodpisani S3 URL-ji, GCS, vaše lastno statično gostovanje, celo GitHub raw URL za enkratne uvoze. Brevo pridobi datoteko z vašega URL-ja in nato izvede uvoz. Sprejete oblike: .csv, .txt, .json.

Pošljite JSON namesto CSV

Če že vlečete stike iz baze podatkov, vam ni treba iti skozi CSV. Pošljite jih kot JSON neposredno:

body = {
"jsonBody": [
{
"email": "[email protected]",
"attributes": {
"FIRSTNAME": "Jane",
"LASTNAME": "Doe",
"COMPANY": "Acme",
},
},
{
"email": "[email protected]",
"attributes": {
"FIRSTNAME": "John",
"LASTNAME": "Smith",
"COMPANY": "Globex",
},
},
],
"listIds": [42],
}

Ista omejitev 10 MB. Isto asinhrono vedenje.

Preverjanje za dokončanje

Uvoz je asinhron. processId je vaš ročaj za sledenje. Obstaja ločen endpoint za preverjanje statusa procesa:

def wait_for_import(process_id: int, timeout_s: int = 600) -> dict:
import time
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(
f"https://api.brevo.com/v3/processes/{process_id}",
headers={"api-key": API_KEY},
timeout=30,
)
r.raise_for_status()
status = r.json()
if status["status"] in ("completed", "failed"):
return status
time.sleep(5)
raise TimeoutError(f"Import {process_id} did not finish in {timeout_s}s")
result = wait_for_import(process_id)
print(f"Import {result['status']}: {result}")

Za dolgotrajne naloge je čistejši vzorec notifyUrl: posredujte HTTPS endpoint, na katerega bo Brevo poslal POST, ko se uvoz zaključi, in preskočite preverjanje.

body["notifyUrl"] = "https://your-app.example.com/webhooks/brevo-import"

Pogoste napake in kako jih popraviti

400 Bad Request brez očitnega razloga. Skoraj vedno podpičja proti vejicam v CSV. Brevo uvoz pričakuje ;, ne ,. Dvakrat preverite fileBody po vašem koraku pretvorbe.

Vrednosti lastnih atributov izginejo. Atribut ne obstaja v vašem računu. Ustvarite ga pod Contacts → Settings → Contact attributes pred uvozom ali uporabite Attributes API, da ga ustvarite kot del vaše skripte.

401 Unauthorized. Napačno ime glave. Je api-key (male črke, vezaj), ne Authorization ali X-API-Key.

Uvoz je „uspel”, a se stiki niso pojavili na seznamu. Preverite, ali listIds vsebuje pravi seznam. In: če je updateExistingContacts nastavljen na false in stiki že obstajajo, jih Brevo tiho preskoči, namesto da bi jih ponovno dodal na seznam.

Nekaj vrstic je bilo uvoženih, druge ne. Brevo vam po koncu uvoza pošlje e-pošto s poročilom o napakah po vrsticah (razen če ste nastavili disableNotification: true). Poročilo vam pove, katere vrstice so imele slabe e-pošte, manjkajoča obvezna polja ali težave s formatiranjem.

Kdaj skriptirati in kdaj uporabiti vmesnik

Vmesnik je v redu za enkratne uvoze pod tisoč vrsticami. Skripta zmaga, takoj ko:

  • Uvažate več kot enkrat (npr. tedenski izvoz iz vašega CRM)
  • Izvorni podatki potrebujejo čiščenje, preden pristanejo v Brevo (deduplikacija, formatiranje telefonskih številk, deljenje polnih imen na ime in priimek)
  • Želite, da teče po urniku, ne da bi kdorkoli klikal na gumbe
  • Datoteka je večja od cone udobja vmesnika

Zavijte zgornjo skripto v cron opravilo ali GitHub Action in imate avtomatizirano sinhronizacijo stikov. Naslednji prispevek v seriji prikazuje, kako narediti isto stvar neposredno iz Google Sheet z Apps Script. Brez strežnika.

Nadaljnje branje

Frequently Asked Questions

Kateri Brevo API endpoint je za množični uvoz stikov?
POST https://api.brevo.com/v3/contacts/import. Sprejema vsebino CSV (fileBody), URL oddaljene datoteke (fileUrl) ali polje JSON (jsonBody). Endpoint je asinhron: takoj vrne processId in uvoz dokonča v ozadju.
Kakšna je največja velikost datoteke?
10 MB za vgrajen CSV (fileBody) ali JSON (jsonBody). Za večje datoteke gostujte datoteko nekje, kjer je dosegljiva, in namesto tega posredujte njen URL prek fileUrl. Ta pot nima dokumentirane zgornje meje velikosti.
Kako uvozim datoteko .xlsx?
Brevo uvozni API sprejema le .csv, .txt ali .json. Najprej pretvorite .xlsx v .csv. Pandas, openpyxl ali LibreOffice headless to opravijo v eni vrstici. Skripta v tem vodniku vsebuje pretvorbo iz xlsx v csv.
Ali bo prepisalo obstoječe stike?
Privzeto da. updateExistingContacts ima privzeto vrednost true in se ujema po e-pošti. Nastavite ga na false, če želite preskočiti stike, ki že obstajajo. Nastavite emptyContactsAttributes na true, če želite, da prazne celice CSV izbrišejo obstoječe vrednosti (sicer so prazne celice prezrte).
Začnite brezplačno z Brevo