Hogyan importálj CSV vagy Excel kapcsolatokat a Brevóba script segítségével (Python, Node.js, cURL)

Importálj tömegesen kapcsolatokat CSV vagy Excel fájlból a Brevóba az import-contacts API-val. Tartalmaz futásra kész Python és Node.js scripteket, cURL one-linert, hibakezelést és tippeket 10 MB-nál nagyobb fájlokhoz.

Featured image for article: Hogyan importálj CSV vagy Excel kapcsolatokat a Brevóba script segítségével (Python, Node.js, cURL)

Ha valaha is kellett pár ezer kapcsolatot egy táblázatból a Brevóba feltöltened, a manuális UI-út gyorsan fárasztóvá válik: válaszd ki a fájlt, párosítsd az oszlopokat, válassz listát, várj, ismételd. Egy script ugyanezt a munkát másodpercek alatt elvégzi, és (ami még fontosabb) bármikor újra futtathatod ütemezve, adatbázis-export után, vagy amikor a CRM friss CSV-t küld.

Ez az útmutató bemutatja a Brevo API-végpontját, amit pontosan erre a célra adott, teljes működő scriptekkel Pythonban, Node.js-ben, és egy cURL one-linerrel. Mindegyik példa a POST /v3/contacts/import végpontot hívja.

A végpont egy pillantás alatt

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
}

A válasz gyorsan megérkezik:

{ "processId": 78 }

Ez egy 202 Accepted, a Brevo elfogadta az importot és a háttérben dolgozza fel. A processId a követési azonosító, ha le akarod kérdezni az állapotot, vagy notifyUrl webhookot szeretnél beállítani.

Pár dolog, amire érdemes figyelni a kód írása előtt:

  • A törzs lehet CSV (fileBody), JSON (jsonBody) vagy távoli URL (fileUrl). Egyet válassz. A CSV forma pontosvesszővel (;) választja el az oszlopokat, nem vesszővel, ez gyakori csapda.
  • A fileBody és a jsonBody 10 MB-ra van korlátozva. A Brevo a 8 MB körüli méretet ajánlja a biztonság kedvéért. Bármi nagyobbnál töltsd fel a fájlt S3-ra, GCS-re vagy bármilyen HTTPS hostra, és add át a fileUrl paramétert.
  • A fiókodban nem létező egyéni attribútumokat csendben figyelmen kívül hagyja. Hozd létre őket a Brevo felületén (vagy az Attributes API-n keresztül), mielőtt olyan sorokat importálsz, amelyek ezeket használják, különben az adat egyszerűen eltűnik.
  • Az updateExistingContacts alapértéke true. Ha false-ra állítod, a Brevo kihagyja azokat a kapcsolatokat, amelyek e-mail címe már létezik, hasznos a “csak újat hozzáadni” jellegű feladatokhoz.
  • Az emptyContactsAttributes szabályozza, hogy a CSV üres cellái törlik-e a meglévő értékeket. Alapértelmezett false (az üres cellákat figyelmen kívül hagyja). Állítsd true-ra, ha a CSV az igazság forrása, és azt szeretnéd, hogy az üresek töröljék a régi adatokat.

Szerezz egy API kulcsot

Jelentkezz be a Brevóba, Settings -> SMTP & API -> API Keys, hozz létre új kulcsot. Úgy néz ki, mint xkeysib-.... Az api-key HTTP fejlécben add át minden kérésnél. Kezeld jelszóként, teljes olvasási és írási joga van a fiókodon.

Tiszta minta: tedd környezeti változóba, hogy soha ne kerüljön a forráskódba.

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

Python: olvass be egy CSV-t, küldd a Brevóba

Ez a legegyszerűbb lehetséges script: olvass be egy helyi CSV-t a standard könyvtárral, küldd a törzset egyenesen a Brevónak. A requests könyvtáron kívül semmi külső függőség nem kell.

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

Futtasd:

Terminal window
python import_csv_to_brevo.py contacts.csv

A CSV első sora a fejléc. Az oszlopnevek nagybetűvel, pontos egyezéssel kerülnek a Brevo attribútumaihoz: EMAIL, FIRSTNAME, LASTNAME, plusz minden egyéni attribútum, amit definiáltál. Az EMAIL kötelező.

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

Ennyi a folyamat. A script egy másodpercen belül visszatér; a tényleges import a szerver oldalon fut, és a mennyiségtől függően néhány másodperctől néhány percig tart.

Excel fájlok: három járható út

A Brevo import végpontja közvetlenül nem olvas .xlsx fájlt, ezért három valós lehetőséged van attól függően, hogy hol fut a munka:

  1. Futtass VBA makrót a munkafüzeten belül, egykattintásos szinkron magából az Excelből, külső script nélkül. Ez a megfelelő válasz, ha a fájl asztali gépen van, és a csapatod gombot szeretne a táblázaton. Teljes kód az Excel-to-Brevo VBA makró útmutatóban.
  2. Office Scripts + Power Automate, ha a munkafüzet OneDrive-on/SharePoint-on van, és felügyelet nélküli ütemezett szinkront szeretnél. Szintén az Excel útmutatóban.
  3. Konvertáld az .xlsx fájlt CSV-re scriptből, ezt a részt mutatjuk be. Akkor a legjobb, ha már Pythont vagy Node-ot futtatsz egy szerveren, és csak naponta egyszer kell behúznod egy munkafüzetet.

A 3. opcióhoz a pandas egy soros megoldást kínál:

# 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")

Ha nem akarod a pandast függőségként, az openpyxl önmagában is működik:

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: ugyanaz a feladat, hivatalos SDK

A Brevo közzéteszi a @getbrevo/brevo csomagot Node-ra. Kezeli a hitelesítést, az újrapróbálkozásokat és a típusos kérésformát:

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

Vagy ha nem akarod az SDK-t, sima fetch ugyanúgy működik:

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: one-liner ad hoc importokhoz

Amikor csak a végpontot akarod tesztelni, vagy egy kis fájlt szeretnél kézzel betolni:

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}"

A jq -Rs . az egész fájlt beolvassa és JSON-escape-eli, így nem kell kézzel escape-elned a sortöréseket és az idézőjeleket.

10 MB-nál nagyobb fájlok: használd a fileUrl-t

A fileBody 10 MB-ra van korlátozva. Ha a kapcsolat-export ennél nagyobb, töltsd fel a fájlt egy URL-re, amit a Brevo el tud érni, és add át azt:

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

Bármi működik, ami nyilvános HTTPS URL-en keresztül elérhető: pre-signed S3 URL-ek, GCS, saját statikus host, sőt egy GitHub raw URL is alkalmi importokra. A Brevo letölti a fájlt az URL-edről, majd futtatja az importot. Elfogadott formátumok: .csv, .txt, .json.

Küldj JSON-t CSV helyett

Ha már adatbázisból húzod a kapcsolatokat, nem kell CSV-n keresztül körbeküldened, küldd közvetlenül JSON-ként:

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

Ugyanaz a 10 MB-os korlát. Ugyanaz az aszinkron viselkedés.

Lekérdezés a befejezésig

Az import aszinkron, a processId a követéshez használt azonosító. Külön végpont van a folyamat állapotának ellenőrzésére:

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

Hosszú futású munkáknál a notifyUrl a tisztább minta: add meg egy HTTPS végpont URL-jét, amire a Brevo POST-ol az import befejezésekor, és ki is hagyhatod a lekérdezést.

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

Gyakori hibák és javításuk

400 Bad Request látható ok nélkül. Szinte mindig a pontosvessző és a vessző cseréje a CSV-ben. A Brevo importja ;-t vár, nem ,-t. Ellenőrizd a fileBody-t a konverziós lépés után.

Az egyéni attribútum értékei eltűnnek. Az attribútum nem létezik a fiókodban. Hozd létre a Contacts -> Settings -> Contact attributes alatt az import előtt, vagy használd az Attributes API-t a script részeként.

401 Unauthorized. Rossz fejlécnév. api-key (kisbetű, kötőjel), nem Authorization vagy X-API-Key.

Az import “sikeres” volt, de a kapcsolatok nem jelentek meg a listán. Ellenőrizd, hogy a listIds a megfelelő listát tartalmazza. Továbbá: ha az updateExistingContacts false, és a kapcsolatok már léteznek, a Brevo csendben kihagyja őket, ahelyett, hogy újra hozzáadná őket a listához.

Néhány sor importálódott, néhány nem. A Brevo e-mailben küld soronkénti hibajelentést az import befejezése után (kivéve, ha a disableNotification: true van beállítva). A jelentés megmondja, melyik soroknak voltak rossz e-mail címeik, hiányzó kötelező mezőik vagy formázási hibáik.

Mikor érdemes scriptet írni vs. felületet használni

A felület rendben van egyszeri, ezer sor alatti importokhoz. A script jobb, amint:

  • Egynél többször importálsz (pl. heti export a CRM-edből)
  • A forrásadatot tisztítani kell a Brevóba kerülés előtt (deduplikáció, telefonszámok formázása, teljes nevek szétbontása vezeték- és keresztnévre)
  • Azt szeretnéd, hogy ütemezve fusson, kattintgatás nélkül
  • A fájl nagyobb, mint amit a felület kényelmesen kezel

Csomagold be a fenti scriptet egy cron jobba vagy egy GitHub Actionbe, és máris automatizált kapcsolatszinkronod van. A sorozat következő bejegyzése azt mutatja be, hogyan csináld meg ugyanezt közvetlenül egy Google Sheetből Apps Scripttel, szerver nélkül.

További olvasmányok

Frequently Asked Questions

Mi a Brevo API végpontja a kapcsolatok tömeges importálásához?
POST https://api.brevo.com/v3/contacts/import. Elfogad CSV tartalmat (fileBody), távoli fájl URL-t (fileUrl) vagy JSON tömböt (jsonBody). A végpont aszinkron, azonnal visszaad egy processId-t és a háttérben fejezi be az importot.
Mekkora a maximális fájlméret?
10 MB az inline CSV (fileBody) vagy JSON (jsonBody) esetén. Nagyobb fájloknál tárold a fájlt egy elérhető helyen, és add meg az URL-jét a fileUrl paraméterben, ennek nincs dokumentált méretkorlátja.
Hogyan importálok .xlsx fájlt?
A Brevo import API csak .csv, .txt vagy .json formátumot fogad el. Először konvertáld az .xlsx fájlt CSV-re, ezt a pandas, az openpyxl vagy a LibreOffice headless egy sorban megoldja. Az ebben az útmutatóban szereplő script tartalmaz xlsx -> csv konverziót.
Felülírja a már létező kapcsolatokat?
Alapértelmezetten igen, az updateExistingContacts alapértéke true, és e-mail alapján egyezteti a kapcsolatokat. Állítsd false-ra, ha ki akarod hagyni a már létező kapcsolatokat. Az emptyContactsAttributes paramétert állítsd true-ra, ha az üres CSV cellák töröljék a meglévő értékeket (különben az üres cellákat figyelmen kívül hagyja).
Kezdje ingyen a Brevo-val