CSV veya Excel Kişilerini Bir Komut Dosyasıyla Brevo'ya Aktarma (Python, Node.js, cURL)

import-contacts API'sini kullanarak CSV veya Excel dosyasındaki kişileri Brevo'ya toplu olarak aktarın. Çalıştırılmaya hazır Python ve Node.js komut dosyaları, cURL tek satırlık komutu, hata yönetimi ve 10 MB'dan büyük dosyalar için ipuçları içerir.

Featured image for article: CSV veya Excel Kişilerini Bir Komut Dosyasıyla Brevo'ya Aktarma (Python, Node.js, cURL)

Bir elektronik tablodan birkaç bin kişiyi Brevo’ya aktarmanız gerektiyse, manuel UI yolu hızla can sıkıcı hale gelir: dosyayı seçin, sütunları eşleyin, listeyi seçin, bekleyin, tekrarlayın. Bir komut dosyası aynı işi saniyeler içinde yapar ve daha da önemlisi, zamanlanmış olarak, bir veritabanı dışa aktarımından sonra veya CRM’iniz her yeni bir CSV ürettiğinde tekrar çalıştırabilirsiniz.

Bu kılavuz, Brevo’nun tam olarak bunun için sunduğu API uç noktasını, Python, Node.js ile tam çalışan komut dosyaları ve bir cURL tek satırlık komutuyla birlikte ele alır. Bu kılavuzdaki her şey POST /v3/contacts/import adresine gider.

Uç noktaya bir bakış

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
}

Yanıt hızlıca geri döner:

{ "processId": 78 }

Bu bir 202 Accepted: Brevo içe aktarmayı kabul etti ve arka planda işliyor. processId, tamamlanmayı sorgulamak veya bir notifyUrl webhook’u kurmak isterseniz takip tutamacınızdır.

Kod yazmadan önce dikkat edilmesi gereken birkaç şey:

  • Gövde CSV (fileBody), JSON (jsonBody) veya uzak bir URL (fileUrl) olabilir. Birini seçin. CSV biçimi sütunları ayırmak için noktalı virgül (;) kullanır, virgül değil. Bu yaygın bir tuzaktır.
  • fileBody ve jsonBody 10 MB ile sınırlıdır. Brevo, güvende olmak için 8 MB civarında kalmanızı önerir. Daha büyük herhangi bir şey için dosyayı S3, GCS veya herhangi bir HTTPS sunucusuna yükleyin ve bunun yerine fileUrl iletin.
  • Hesabınızda bulunmayan özel öznitelikler sessizce yok sayılır. Bunları kullanan satırları içe aktarmadan önce Brevo’nun arayüzünde (veya Attributes API üzerinden) oluşturun, aksi halde veriler kaybolur.
  • updateExistingContacts varsayılan olarak true değerindedir. false olarak ayarlarsanız Brevo, e-postası zaten mevcut olan kişileri atlar. “Yalnızca yeni ekle” işleri için kullanışlıdır.
  • emptyContactsAttributes, CSV’nizdeki boş hücrelerin mevcut değerleri silip silmeyeceğini kontrol eder. Varsayılan false (boş hücreler yok sayılır). CSV’niz doğruluk kaynağıysa ve boşlukların eski verileri temizlemesini istiyorsanız true olarak ayarlayın.

API anahtarı edinin

Brevo’ya giriş yapın → Ayarlar → SMTP & API → API Anahtarları → yeni bir anahtar oluşturun. xkeysib-... gibi görünür. Onu her istekte api-key HTTP üst bilgisi olarak ileteceksiniz. Bir parola gibi davranın, hesabınızda tam okuma/yazma yetkisine sahiptir.

Temiz bir desen: kaynak ağacınıza asla düşmeyecek şekilde bir ortam değişkenine koyun.

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

Python: bir CSV okuyun, Brevo’ya gönderin

Bu olabildiğince basit bir komut dosyasıdır: standart kütüphane ile yerel bir CSV’yi okuyun, gövdeyi doğrudan Brevo’ya gönderin. requests dışında üçüncü taraf bir SDK gerekmez.

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

Çalıştırın:

Terminal window
python import_csv_to_brevo.py contacts.csv

CSV’nizin ilk satırı başlıktır. Sütun adları Brevo özniteliklerine büyük harfle, tam eşleşmeyle eşlenir: EMAIL, FIRSTNAME, LASTNAME, ayrıca tanımladığınız her özel öznitelik. EMAIL zorunludur.

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

İşte tüm akış. Komut dosyası bir saniye içinde geri döner; gerçek içe aktarma sunucu tarafında çalışır ve hacme bağlı olarak birkaç saniye ile birkaç dakika arasında sürer.

Excel dosyaları: üç uygulanabilir yol

Brevo’nun içe aktarma uç noktası .xlsx dosyasını doğrudan okumaz, bu yüzden işin nerede yaşaması gerektiğine bağlı olarak üç gerçek seçeneğiniz vardır:

  1. Çalışma kitabının içinde bir VBA makrosu çalıştırın: Excel’in kendisinden tek tıkla senkronizasyon, harici komut dosyası yok. Dosya bir masaüstünde olduğunda ve ekibinizin sayfada bir düğme istediğinde doğru cevap budur. Tam kod Excel’den Brevo’ya VBA makrosu kılavuzunda.
  2. Office Scripts + Power Automate: çalışma kitabı OneDrive/SharePoint’te ise ve gözetimsiz zamanlanmış senkronizasyon istiyorsanız. Ayrıca Excel kılavuzunda kapsanmıştır.
  3. .xlsx’i bir komut dosyasından CSV’ye dönüştürün: bu bölümün geri kalanının kapsadığı şey. Zaten bir sunucuda Python veya Node çalıştırıyorsanız ve günde bir kez bir çalışma kitabını çekmeniz gerekiyorsa en iyisidir.

Seçenek 3 için pandas bunu tek satırlık yapar:

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

pandas’ı bağımlılık olarak istemiyorsanız, tek başına openpyxl da çalışır:

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: aynı iş, resmi SDK

Brevo, Node için @getbrevo/brevo paketini yayınlar. Kimlik doğrulama, yeniden denemeler ve türlenmiş istek şeklini yönetir:

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

Veya SDK istemiyorsanız, düz fetch aynı şekilde çalışır:

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: anlık içe aktarmalar için tek satırlık komut

Sadece uç noktayı test etmek veya küçük bir dosyayı elle göndermek istediğinizde:

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 . tüm dosyayı yutar ve JSON olarak escape eder. Yeni satırları ve tırnak işaretlerini elle escape etmekten kurtarır.

10 MB’dan büyük dosyalar: fileUrl kullanın

fileBody 10 MB ile sınırlıdır. Kişi dökümünüz daha büyükse, dosyayı Brevo’nun ulaşabileceği bir URL’de barındırın ve onu iletin:

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

Genel HTTPS URL’si üzerinden ulaşılabilen herhangi bir şey çalışır: önceden imzalanmış S3 URL’leri, GCS, kendi statik sunucunuz, hatta tek seferlik içe aktarmalar için bir GitHub raw URL’si. Brevo dosyayı URL’nizden alır, sonra içe aktarmayı çalıştırır. Kabul edilen biçimler: .csv, .txt, .json.

CSV yerine JSON gönderin

Kişileri zaten bir veritabanından çekiyorsanız, CSV üzerinden gidip gelmenize gerek yoktur, doğrudan JSON olarak gönderin:

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

Aynı 10 MB sınırı. Aynı asenkron davranış.

Tamamlanmayı sorgulama

İçe aktarma asenkrondur: processId onu izlemek için tutamacınızdır. Süreç durumunu kontrol etmek için ayrı bir uç nokta vardır:

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

Uzun süren işler için daha temiz desen notifyUrl kullanmaktır: içe aktarma bittiğinde Brevo’nun POST yapacağı bir HTTPS uç noktası iletin ve sorgulamayı atlayın.

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

Yaygın hatalar ve nasıl düzeltilir

Belirgin nedeni olmayan 400 Bad Request: Neredeyse her zaman CSV’deki noktalı virgül ve virgül meselesidir. Brevo’nun içe aktarması ; bekler, , değil. Dönüştürme adımınızdan sonra fileBody’yi tekrar kontrol edin.

Özel öznitelik değerleri kayboluyor: Öznitelik hesabınızda yok. Kişiler → Ayarlar → Kişi öznitelikleri altında onu içe aktarmadan önce oluşturun veya komut dosyanızın bir parçası olarak oluşturmak için Attributes API kullanın.

401 Unauthorized: Yanlış üst bilgi adı. api-key (küçük harf, tire), Authorization veya X-API-Key değil.

İçe aktarma “başarılı” ama kişiler listede görünmüyor: listIds’in doğru listeyi içerdiğini kontrol edin. Ayrıca: updateExistingContacts false ise ve kişiler zaten varsa, Brevo onları listeye yeniden eklemek yerine sessizce atlar.

Bazı satırlar içe aktarıldı, bazıları aktarılmadı: Brevo, içe aktarma bittikten sonra size satır başına bir hata raporu e-postayla gönderir (eğer disableNotification: true ayarlamadıysanız). Rapor hangi satırların hatalı e-postalara, eksik zorunlu alanlara veya biçimlendirme sorunlarına sahip olduğunu söyler.

Ne zaman komut dosyası yazmalı, ne zaman UI kullanmalı

UI, bin satırın altındaki tek seferlik içe aktarmalar için iyidir. Şu durumlarda bir komut dosyası kazanır:

  • Birden fazla kez içe aktarıyorsanız (örneğin CRM’inizden haftalık dışa aktarım)
  • Kaynak veriler Brevo’ya inmeden önce temizlenmesi gerekiyorsa (yinelenen kayıtların kaldırılması, telefon numaralarının biçimlendirilmesi, tam adların ad/soyad olarak ayrılması)
  • Kimsenin düğmelere tıklaması olmadan zamanlanmış olarak çalışmasını istiyorsanız
  • Dosya UI’nın rahat alanından daha büyükse

Yukarıdaki komut dosyasını bir cron işine veya bir GitHub Action’a sarın ve otomatik kişi senkronizasyonuna sahip olursunuz. Bu serideki bir sonraki yazı, aynı şeyi doğrudan bir Google Sheet’ten Apps Script kullanarak nasıl yapacağınızı gösterir, sunucu gerekmez.

Daha fazla okuma

Frequently Asked Questions

Brevo'nun toplu kişi içe aktarma API uç noktası nedir?
POST https://api.brevo.com/v3/contacts/import. CSV içeriği (fileBody), uzak bir dosya URL'si (fileUrl) veya bir JSON dizisi (jsonBody) kabul eder. Uç nokta asenkrondur, hemen bir processId döndürür ve içe aktarmayı arka planda tamamlar.
Maksimum dosya boyutu nedir?
Satır içi CSV (fileBody) veya JSON (jsonBody) için 10 MB. Daha büyük dosyalar için, dosyayı erişilebilir bir yerde barındırın ve URL'sini fileUrl üzerinden iletin. Bu yolun belgelenmiş bir boyut sınırı yoktur.
.xlsx dosyasını nasıl içe aktarırım?
Brevo'nun içe aktarma API'si yalnızca .csv, .txt veya .json kabul eder. Önce .xlsx'i .csv'ye dönüştürün. pandas, openpyxl veya LibreOffice headless bunu tek satırda yapabilir. Bu kılavuzdaki komut dosyası bir xlsx'ten csv'ye dönüştürme içerir.
Mevcut kişilerin üzerine yazar mı?
Varsayılan olarak evet. updateExistingContacts varsayılan olarak true değerindedir ve e-postaya göre eşleşir. Zaten mevcut olan kişileri atlamak için false olarak ayarlayın. Boş CSV hücrelerinin mevcut değerleri silmesini istiyorsanız emptyContactsAttributes değerini true olarak ayarlayın (aksi takdirde boş hücreler yok sayılır).
Brevo ile ücretsiz başlayın