Jak wysłać kontakty Excel do Brevo za pomocą makra VBA (i alternatywa Office Scripts)

Działające makro VBA, które wysyła kontakty z arkusza Excel do API Brevo jednym kliknięciem, plus kiedy zamiast tego użyć Office Scripts + Power Automate, oraz porównanie z konfiguracją Google Apps Script.

Featured image for article: Jak wysłać kontakty Excel do Brevo za pomocą makra VBA (i alternatywa Office Scripts)

Masz kontakty w Excelu i chcesz je w Brevo. Szybko-i-brudna odpowiedź to zapisanie pliku jako .csv i import, co jest w porządku raz. Dla wszystkiego, co robisz wielokrotnie (cotygodniowe przekazanie sprzedaży, skoroszyt, który Twój zespół aktualizuje codziennie, lista partnerów, która jest odświeżana), chcesz mieć przycisk wewnątrz Excela, który wykonuje synchronizację.

Ten przewodnik omawia dwie ścieżki, które naprawdę mają sens dla tego:

  1. Makro VBA osadzone w skoroszycie. Bez licencji, bez chmury, działa offline, uruchamia się w momencie kliknięcia przycisku przez użytkownika. Właściwa odpowiedź dla około 80% przypadków “Excel-do-Brevo”.
  2. Office Scripts + Power Automate. TypeScript zamiast VBA, działa w chmurze, obsługuje wyzwalacze zaplanowane. Właściwa odpowiedź, jeśli skoroszyt znajduje się w OneDrive/SharePoint i chcesz nienadzorowanej synchronizacji, ale uważaj na licencjonowanie Power Automate.

Jeśli szukasz odpowiednika Google Sheets, zobacz towarzyszący artykuł o Apps Script. A jeśli chcesz po prostu jednorazowy import CSV ze skryptu na laptopie, przewodnik importu CSV ma wersje w Pythonie, Node.js i cURL.

Co robi makro

Gdy użytkownik kliknie przycisk “Sync to Brevo” na arkuszu:

  1. Odczytuje każdy wiersz aktywnego arkusza (najpierw wiersz nagłówka, jeden kontakt na wiersz).
  2. Buduje tablicę JSON ukształtowaną dla parametru jsonBody Brevo.
  3. POST-uje ją do https://api.brevo.com/v3/contacts/import z kluczem API zapisanym w skoroszycie.
  4. Pokazuje okno komunikatu z wynikiem.

Tyle. Około 120 linii VBA. Poniżej pełny, działający moduł.

Układ arkusza, którego oczekuje makro

emailfirstNamelastNamecompanycity
[email protected]JaneDoeAcmeBerlin
[email protected]JohnSmithGlobexParis

email jest obowiązkowy. Każda inna kolumna staje się atrybutem kontaktu Brevo, mapowanym przez nagłówek kolumny (wielkimi literami) do nazwy atrybutu. Więc firstNameFIRSTNAME, companyCOMPANY. Niestandardowe atrybuty (wszystko poza standardowym zestawem) muszą najpierw istnieć w Twoim koncie Brevo. Zdefiniuj je w Contacts → Settings → Contact attributes.

Krok 1: Otwórz edytor VBA

W Excelu: naciśnij Alt + F11. Otwiera się edytor VBA. W panelu Project po lewej kliknij prawym przyciskiem myszy swój skoroszyt i wybierz Insert → Module. Pojawi się pusty Module1.

Krok 2: Wklej pełne makro

Zastąp zawartość Module1 tym:

' ===========================================================================
' Brevo contact sync for Excel
' Reads the active sheet's rows and POSTs them to Brevo's import API.
' ===========================================================================
Option Explicit
Private Const BREVO_API_BASE As String = "https://api.brevo.com/v3"
Private Const BREVO_LIST_ID As Long = 42 ' <- your Brevo list ID
Private Const BATCH_SIZE As Long = 1000
' --- Public entry points (the ones you assign to ribbon buttons) -----------
Public Sub SyncSheetToBrevo()
Dim apiKey As String
apiKey = GetApiKey()
If apiKey = "" Then
MsgBox "No API key configured. Run ConfigureApiKey first.", _
vbExclamation, "Brevo Sync"
Exit Sub
End If
Dim ws As Worksheet
Set ws = ActiveSheet
Dim emailCol As Long
emailCol = FindEmailColumn(ws)
If emailCol = 0 Then
MsgBox "Sheet must have an 'email' column in row 1.", _
vbExclamation, "Brevo Sync"
Exit Sub
End If
Dim lastRow As Long, lastCol As Long
lastRow = ws.Cells(ws.Rows.Count, emailCol).End(xlUp).Row
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
If lastRow < 2 Then
MsgBox "No contact rows found.", vbInformation, "Brevo Sync"
Exit Sub
End If
Dim contacts As Collection
Set contacts = New Collection
Dim r As Long, c As Long
For r = 2 To lastRow
Dim email As String
email = LCase(Trim(CStr(ws.Cells(r, emailCol).Value)))
If email <> "" And InStr(email, "@") > 0 Then
Dim json As String
json = "{""email"":""" & EscapeJson(email) & """,""attributes"":{"
Dim attrFirst As Boolean
attrFirst = True
For c = 1 To lastCol
If c <> emailCol Then
Dim val As String
val = CStr(ws.Cells(r, c).Value)
If val <> "" Then
If Not attrFirst Then json = json & ","
Dim attrName As String
attrName = UCase(Trim(CStr(ws.Cells(1, c).Value)))
json = json & """" & attrName & """:""" & EscapeJson(val) & """"
attrFirst = False
End If
End If
Next c
json = json & "}}"
contacts.Add json
End If
Next r
If contacts.Count = 0 Then
MsgBox "No valid contact rows found.", vbInformation, "Brevo Sync"
Exit Sub
End If
Dim totalSent As Long
Dim batchNum As Long
Dim okCount As Long, failCount As Long
Dim batchStart As Long
For batchStart = 1 To contacts.Count Step BATCH_SIZE
batchNum = batchNum + 1
Dim batchEnd As Long
batchEnd = batchStart + BATCH_SIZE - 1
If batchEnd > contacts.Count Then batchEnd = contacts.Count
Dim payload As String
payload = "{""jsonBody"":["
Dim i As Long
For i = batchStart To batchEnd
If i > batchStart Then payload = payload & ","
payload = payload & contacts(i)
Next i
payload = payload & "],""listIds"":[" & BREVO_LIST_ID & _
"],""updateExistingContacts"":true,""emptyContactsAttributes"":false}"
Dim ok As Boolean
ok = PostToBrevo(apiKey, payload)
If ok Then
okCount = okCount + 1
totalSent = totalSent + (batchEnd - batchStart + 1)
Else
failCount = failCount + 1
End If
Next batchStart
MsgBox "Sent " & totalSent & " contact(s) in " & batchNum & " batch(es)." _
& vbCrLf & "Successful batches: " & okCount _
& vbCrLf & "Failed batches: " & failCount, _
vbInformation, "Brevo Sync"
End Sub
Public Sub ConfigureApiKey()
Dim key As String
key = InputBox("Paste your Brevo API key (xkeysib-...):", "Brevo API Key")
If key = "" Then Exit Sub
key = Trim(key)
If Left(key, 8) <> "xkeysib-" Then
MsgBox "That doesn't look like a Brevo API key (should start with xkeysib-).", _
vbExclamation, "Brevo API Key"
Exit Sub
End If
On Error Resume Next
ThisWorkbook.CustomDocumentProperties("BrevoApiKey").Delete
On Error GoTo 0
ThisWorkbook.CustomDocumentProperties.Add _
Name:="BrevoApiKey", _
LinkToContent:=False, _
Type:=msoPropertyTypeString, _
Value:=key
ThisWorkbook.Save
MsgBox "API key saved inside the workbook.", vbInformation, "Brevo API Key"
End Sub
' --- Private helpers --------------------------------------------------------
Private Function GetApiKey() As String
On Error Resume Next
GetApiKey = ThisWorkbook.CustomDocumentProperties("BrevoApiKey").Value
On Error GoTo 0
End Function
Private Function FindEmailColumn(ws As Worksheet) As Long
Dim lastCol As Long, c As Long
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
For c = 1 To lastCol
If LCase(Trim(CStr(ws.Cells(1, c).Value))) = "email" Then
FindEmailColumn = c
Exit Function
End If
Next c
FindEmailColumn = 0
End Function
Private Function PostToBrevo(apiKey As String, payload As String) As Boolean
Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "POST", BREVO_API_BASE & "/contacts/import", False
http.SetRequestHeader "api-key", apiKey
http.SetRequestHeader "Content-Type", "application/json"
http.SetRequestHeader "Accept", "application/json"
http.Send payload
PostToBrevo = (http.Status = 202)
If Not PostToBrevo Then
Debug.Print "Brevo error " & http.Status & ": " & http.responseText
End If
End Function
Private Function EscapeJson(s As String) As String
Dim r As String
r = Replace(s, "\", "\\")
r = Replace(r, """", "\""")
r = Replace(r, vbCrLf, "\n")
r = Replace(r, vbLf, "\n")
r = Replace(r, vbCr, "\n")
r = Replace(r, vbTab, "\t")
EscapeJson = r
End Function

Krok 3: Zapisz skoroszyt jako .xlsm

Makra VBA są zachowywane tylko w skoroszytach z włączoną obsługą makr. Save As, wybierz Excel Macro-Enabled Workbook (.xlsm). Zwykły format .xlsx po cichu usuwa makra. Wiele osób za pierwszym razem traci kod w ten sposób.

Krok 4: Skonfiguruj swój klucz API

Uruchom ConfigureApiKey raz. Albo:

  • W edytorze VBA kliknij gdziekolwiek wewnątrz subprocedury ConfigureApiKey i naciśnij F5, lub
  • W Excelu, Developer → Macros, wybierz ConfigureApiKey, Run.

Wklej swój klucz xkeysib-.... Makro przechowuje go jako niestandardową właściwość dokumentu wewnątrz samego skoroszytu. Nie jest w kodzie źródłowym, nie jest w rejestrze i podróżuje z plikiem (więc bądź świadomy: jeśli wyślesz .xlsm e-mailem do kogoś, klucz API idzie z nim).

Jeśli wolisz umieścić klucz poza skoroszytem, zmień przechowywanie na rejestr Windows:

' Replace the body of ConfigureApiKey with:
SaveSetting "Brevo", "Sync", "ApiKey", key
' And GetApiKey with:
GetApiKey = GetSetting("Brevo", "Sync", "ApiKey", "")

SaveSetting/GetSetting zapisuje pod HKCU\Software\VB and VBA Program Settings\Brevo\Sync. Per użytkownik, nie per skoroszyt. Użyj tego, jeśli wiele skoroszytów ma dzielić jeden klucz, lub jeśli nie chcesz klucza w pliku.

Krok 5: Dodaj przycisk na arkuszu

To zamienia to w doświadczenie jednego kliknięcia dla użytkowników nietechnicznych.

Insert → Shapes → Rectangle, upuść jeden na arkuszu, nazwij go “Sync to Brevo.” Kliknij prawym przyciskiem myszy kształt → Assign Macro → wybierz SyncSheetToBrevo. Gotowe.

Lub, dla bardziej dopracowanego UI, dodaj niestandardową kartę wstążki przez Office Custom UI Editor. Ale dla większości narzędzi wewnętrznych kształt-jako-przycisk wystarczy.

Krok 6: Uruchom to

Kliknij przycisk. Makro odczytuje wiersze, batchuje je, wysyła każdy batch do Brevo i pokazuje podsumowujące okno komunikatu. Import Brevo jest asynchroniczny, więc komunikat o sukcesie oznacza “Brevo zaakceptowało batch”. Faktyczne tworzenie kontaktów odbywa się po stronie serwera w ciągu kilku następnych sekund. Otrzymasz e-mail z podsumowaniem od Brevo, gdy się skończy (chyba że ustawisz disableNotification: true).

Częste pułapki

Przycisk nic nie robi i nie ma błędu. Makra są wyłączone. Spójrz na żółty pasek bezpieczeństwa u góry arkusza, kliknij Enable Content. Jeśli Twoja organizacja blokuje makra, zobacz ścieżkę trust-center / code-signing poniżej.

Compile error: User-defined type not defined. Jesteś na Mac Excel, który nie ma MSXML2.XMLHTTP. Mac VBA nie może wykonywać żądań HTTPS bezpośrednio; zamiast tego użyj ścieżki Office Scripts poniżej.

400 Bad Request od Brevo bez oczywistej przyczyny. Prawie zawsze jeden z: (a) niestandardowy atrybut w Twoim arkuszu nie istnieje jeszcze w Brevo, najpierw go utwórz; (b) bug escape’owania JSON, cudzysłowy lub backslashe w wartościach komórek, które nie zostały zaescape’owane. Funkcja EscapeJson w kodzie obsługuje standardowe przypadki; jeśli Twoje dane mają dziwne znaki, zaloguj payload do okna Immediate (Debug.Print payload) i sprawdź.

401 Unauthorized. Zły nagłówek. To api-key (małe litery, łącznik), a nie Authorization. Makro używa właściwego, ale jeśli skopiowałeś snippet skądinąd, sprawdź dwukrotnie.

Excel zamarza na dużych importach. Makro działa synchronicznie na wątku UI. Dla 50 000+ wierszy będziesz patrzeć, jak Excel zawisa na 10 do 30 sekund, podczas gdy buduje JSON i czeka na Brevo. Albo to zaakceptuj, albo przełącz MSXML2.XMLHTTP na jego wariant async. Ale na tej skali jesteś lepiej w Power Automate (następna sekcja).

Kiedy VBA nie wystarcza: Office Scripts + Power Automate

VBA nie potrafi zaplanowanej synchronizacji w chmurze. Jeśli potrzebujesz:

  • Skoroszyt synchronizujący się z Brevo co godzinę bez otwierania go przez kogokolwiek
  • Skoroszyt w OneDrive/SharePoint, edytowany z poziomu webu
  • Dział IT, który zabrania makr desktopowych

…wtedy chcesz Office Scripts (chmurowy odpowiednik Apps Script od Microsoft) plus Power Automate (ich warstwę planowania i HTTP).

Podział: Office Scripts odczytuje arkusz i zwraca dane kontaktów. Power Automate bierze te dane i POST-uje je do Brevo na wyzwalacz.

Office Script (Excel for the web → Automate → New Script):

function main(workbook: ExcelScript.Workbook): {email: string, attributes: Record<string, string>}[] {
const sheet = workbook.getActiveWorksheet();
const range = sheet.getUsedRange();
if (!range) return [];
const values = range.getValues() as string[][];
if (values.length < 2) return [];
const headers = values[0].map(h => String(h).trim());
const emailIdx = headers.findIndex(h => h.toLowerCase() === "email");
if (emailIdx === -1) throw new Error("Sheet must have an 'email' column");
const contacts: {email: string, attributes: Record<string, string>}[] = [];
for (let r = 1; r < values.length; r++) {
const row = values[r];
const email = String(row[emailIdx] ?? "").trim().toLowerCase();
if (!email || !email.includes("@")) continue;
const attributes: Record<string, string> = {};
for (let c = 0; c < headers.length; c++) {
if (c === emailIdx) continue;
const v = row[c];
if (v === null || v === "") continue;
attributes[headers[c].toUpperCase()] = String(v);
}
contacts.push({ email, attributes });
}
return contacts;
}

Flow Power Automate:

  1. Trigger: Recurrence (co 1 godzinę), albo ręczny przycisk, albo “When a row is modified”, jeśli chcesz synchronizacji wyzwalanej zmianami.
  2. Action: Excel Online → Run script, wskaż go na swój skoroszyt i powyższy skrypt. Zapisz jego wartość zwrotną jako contacts.
  3. Action: HTTP (to konektor Premium, zobacz notę o licencjonowaniu poniżej).
    • Method: POST
    • URI: https://api.brevo.com/v3/contacts/import
    • Headers: api-key: xkeysib-..., Content-Type: application/json
    • Body:
      {
      "jsonBody": @{outputs('Run_script')?['body/result']},
      "listIds": [42],
      "updateExistingContacts": true
      }
  4. Action: Condition → jeśli kod statusu ≠ 202, wyślij alert Teams/email.

Sprawdzenie rzeczywistości licencjonowania: akcja HTTP to konektor Power Automate Premium. Na planach Microsoft 365 Business Basic/Standard otrzymujesz standardowe konektory, ale nie Premium. Najtańszy obejście to dodatek Power Automate Premium (około 15 USD/użytkownik/miesiąc w czasie pisania) lub przeniesienie HTTP do małej Azure Function, którą może wywołać standardowy flow. Jeśli już jesteś na E3/E5 z Premium w cenie, masz to ustawione.

To jest główny powód, dla którego historia Apps Script jest czystsza: UrlFetchApp Apps Script jest darmowy i nieograniczony, podczas gdy odpowiednik Microsoft umieszcza wywołanie sieciowe za płatną warstwą konektora.

VBA kontra Office Scripts kontra Apps Script: kiedy co wybrać

PotrzebaNajlepsza opcja
Przycisk jednego kliknięcia w skoroszycie, który Twój zespół już codziennie otwieraMakro VBA (ten przewodnik, górna połowa)
Skoroszyt w OneDrive/SharePoint, godzinna automatyczna synchronizacjaOffice Scripts + Power Automate (potrzebny Premium dla HTTP)
Tylko Mac Excel, nie można użyć VBAOffice Scripts + Power Automate
Dane żyją w Google Sheets, nie ExceluApps Script (darmowy, wbudowane wyzwalacze zaplanowane)
Jednorazowy import, nigdy więcej niepotrzebnySave As → CSV i użyj skryptu importu CSV
Masowy import z pliku >10 MBCSV z fileUrl, zobacz przewodnik CSV

Dlaczego to bije Zapier / platformy no-code

Dla powtarzającego się zadania Excel-do-Brevo zewnętrzne narzędzia automatyzacji (Zapier, Make, n8n) liczą za zadanie i umieszczają trzecią stronę między Twoimi danymi a Brevo. Podejście VBA ma zerowe bieżące koszty, brak przepływu danych przez trzecią stronę i żyje wewnątrz pliku. Gdy skoroszyt się przemieszcza, integracja przemieszcza się z nim. Office Scripts + Power Automate są podobne, ale z Microsoft jako trzecią stroną (już w Twoim stacku, jeśli jesteś na M365).

Cały sens endpointu POST /v3/contacts/import Brevo polega na tym, że nie potrzebujesz platformy klejącej. Twoje narzędzia już wiedzą, jak wykonywać żądania HTTP.

Dalsza lektura

Frequently Asked Questions

Czy makro VBA naprawdę może wywołać API Brevo z wnętrza Excela?
Tak. VBA może wykonywać żądania HTTP przez MSXML2.XMLHTTP, który jest dostarczany z każdą nowoczesną instalacją Windows. Makro POST-uje JSON do api.brevo.com/v3/contacts/import, tego samego endpointu, który trafiłby skrypt Pythona lub Node. Mac Excel też potrafi to przez Office Scripts + Power Automate, ale desktopowe Mac VBA nie (brak MSXML).
Czy mogę uruchomić to według harmonogramu, jak wyzwalacze czasowe Apps Script?
Nie z samego VBA. Excel musi być otwarty, by Application.OnTime zadziałało. Dla nienadzorowanej zaplanowanej synchronizacji masz dwie opcje: (1) Harmonogram zadań Windows, który otwiera skoroszyt i uruchamia makro, lub (2) Office Scripts wyzwalane przez zaplanowany flow Power Automate (omówione później w tym przewodniku).
Czy VBA jest bezpieczne? Moja firma blokuje makra.
Makra VBA działają z dostępem do systemu plików i rejestru, więc blokowanie ich domyślnie jest rozsądną polityką. Dwie ścieżki obejścia: (1) podpisz makro certyfikatem code-signing i umieść skoroszyt w Trusted Location, lub (2) całkowicie pomiń VBA i użyj Office Scripts (TypeScript, sandboxed, bez dostępu do systemu plików). Office Scripts to nowoczesna ścieżka błogosławiona przez Microsoft.
Jak wypada to porównanie z podejściem Google Apps Script?
Apps Script jest bliżej set-and-forget. Działa w chmurze Google, wbudowane wyzwalacze zaplanowane, brak licencji Excel/Power Automate. VBA wygrywa dla pracy offline i ręcznej synchronizacji jednym kliknięciem ze skoroszytu, który Twój zespół już ma otwarty. Office Scripts + Power Automate to chmurowy/zaplanowany odpowiednik po stronie Microsoft, ale Power Automate często wymaga płatnego konektora premium dla wychodzącego HTTP.
Zacznij za darmo z Brevo