Jak poslat kontakty z Excelu do Brevo pomocí VBA makra (a alternativa Office Scripts)
Funkční VBA makro, které posílá kontakty z Excel listu do API Brevo jedním kliknutím. Plus kdy použít Office Scripts + Power Automate a kompromisy oproti nastavení s Google Apps Script.
Máte kontakty v Excelu a chcete je v Brevo. Rychlá a špinavá odpověď je uložit soubor jako .csv a importovat ho, což je v pohodě jednou. Pro cokoli, co děláte opakovaně, týdenní předání obchodu, sešit, který váš tým denně aktualizuje, partnerský seznam, který se obnovuje, chcete tlačítko přímo v Excelu, které synchronizaci udělá.
Tato příručka pokrývá dvě cesty, které pro to skutečně dávají smysl:
- VBA makro vložené v sešitu. Bez licencí, bez cloudu, funguje offline, spustí se v okamžiku, kdy uživatel klikne na tlačítko. Správná odpověď pro asi 80 % případů „Excel do Brevo”.
- Office Scripts + Power Automate. TypeScript místo VBA, běží v cloudu, podporuje plánované triggery. Správná odpověď, pokud sešit žije v OneDrive/SharePoint a chcete bezobslužnou synchronizaci. Pozor ale na licencování Power Automate.
Pokud hledáte ekvivalent pro Google Sheets, podívejte se na doprovodný článek o Apps Script. A pokud chcete jen jednorázový CSV import ze skriptu na svém notebooku, příručka pro CSV import má verze v Pythonu, Node.js a cURL.
Co makro dělá
Když uživatel klikne na tlačítko „Sync to Brevo” na listu:
- Načte každý řádek z aktivního pracovního listu (nejprve hlavička, jeden kontakt na řádek).
- Sestaví JSON pole tvarované pro parametr
jsonBodyBrevo. - POSTne ho na
https://api.brevo.com/v3/contacts/imports API klíčem uloženým v sešitu. - Zobrazí message box s výsledkem.
To je vše. Asi 120 řádků VBA. Níže je plný funkční modul.
Rozvržení listu, které makro očekává
| firstName | lastName | company | city | |
|---|---|---|---|---|
| [email protected] | Jane | Doe | Acme | Berlin |
| [email protected] | John | Smith | Globex | Paris |
email je povinný. Každý další sloupec se stane atributem kontaktu Brevo, mapovaným podle hlavičky sloupce (uppercase) na název atributu. Takže firstName → FIRSTNAME, company → COMPANY. Vlastní atributy (cokoli mimo standardní sadu) musí ve vašem Brevo účtu nejprve existovat. Definujte je pod Contacts → Settings → Contact attributes.
Krok 1: Otevřete VBA editor
V Excelu: stiskněte Alt + F11. Otevře se VBA editor. V panelu Project vlevo klikněte pravým tlačítkem na sešit a vyberte Insert → Module. Objeví se prázdný Module1.
Krok 2: Vložte plné makro
Nahraďte obsah Module1 tímto:
' ===========================================================================' 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 IDPrivate 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 0End 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 = 0End 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 IfEnd 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 = rEnd FunctionKrok 3: Uložte sešit jako .xlsm
VBA makra přetrvávají pouze v sešitech s povolenými makry. Save As → vyberte Excel Macro-Enabled Workbook (.xlsm). Obyčejný formát .xlsx makra tiše odstraní. Mnoho lidí přijde o kód takto poprvé.
Krok 4: Nakonfigurujte svůj API klíč
Spusťte ConfigureApiKey jednou. Buď:
- Ve VBA editoru klikněte kamkoli uvnitř subu
ConfigureApiKeya stiskněteF5, nebo - V Excelu Developer → Macros, vyberte
ConfigureApiKey, Run.
Vložte svůj xkeysib-... klíč. Makro ho ukládá jako vlastní vlastnost dokumentu uvnitř samotného sešitu, není ve zdrojovém kódu, není v registru a cestuje se souborem (takže pozor: pokud .xlsm pošlete e-mailem někomu jinému, API klíč jde s ním).
Pokud byste raději klíč uložili mimo sešit, přepněte úložiště na registry 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, na uživatele, ne na sešit. Použijte to, pokud má více sešitů sdílet jeden klíč nebo pokud nechcete klíč v souboru.
Krok 5: Přidejte tlačítko na list
Tohle z toho dělá zážitek na jedno kliknutí pro netechnické uživatele.
Insert → Shapes → Rectangle, hoďte jeden na list, popište ho „Sync to Brevo.” Pravý klik na tvar → Assign Macro → vyberte SyncSheetToBrevo. Hotovo.
Nebo, pro vyleštěnější UI, přidejte vlastní záložku na pásu karet přes Office Custom UI Editor. Ale pro většinu interních nástrojů je tvar jako tlačítko úplně dost.
Krok 6: Spusťte to
Klikněte na tlačítko. Makro načte řádky, dávkuje je, POSTne každou dávku do Brevo a zobrazí souhrnný message box. Import Brevo je asynchronní, takže zpráva o úspěchu znamená „Brevo dávku přijalo”. Samotné vytváření kontaktů se děje na serveru v dalších několika sekundách. Až skončí, dostanete od Brevo souhrnný e-mail (pokud nenastavíte disableNotification: true).
Časté nástrahy
Tlačítko nedělá nic a žádná chyba. Makra jsou zakázána. Podívejte se na žlutý bezpečnostní pruh v horní části listu a klikněte Enable Content. Pokud vaše organizace blokuje makra, podívejte se na cestu trust-center / code-signing níže.
Compile error: User-defined type not defined. Jste na Mac Excelu, který nemá MSXML2.XMLHTTP. Mac VBA neumí dělat HTTPS požadavky přímo, použijte místo toho cestu Office Scripts níže.
400 Bad Request od Brevo bez zjevné příčiny. Téměř vždy jedna z: (a) vlastní atribut ve vašem listu v Brevo zatím neexistuje, vytvořte ho nejdřív; (b) chyba v JSON escapování, uvozovky nebo zpětná lomítka v hodnotách buněk, které nebyly escapovány. Funkce EscapeJson v kódu řeší standardní případy. Pokud máte v datech zvláštní znaky, zalogujte payload do Immediate window (Debug.Print payload) a prohlédněte si to.
401 Unauthorized. Špatná hlavička. Je to api-key (malá písmena, pomlčka), ne Authorization. Makro používá tu správnou, ale pokud jste si zkopírovali snippet odjinud, zkontrolujte to znovu.
Excel zamrzá při velkých importech. Makro běží synchronně na UI vlákně. Pro 50 000+ řádků budete sledovat, jak Excel visí 10 až 30 sekund, zatímco staví JSON a čeká na Brevo. Buď to přijměte, nebo přepněte MSXML2.XMLHTTP na asynchronní variantu, ale v tomto měřítku jste lépe v Power Automate (další sekce).
Když VBA nestačí: Office Scripts + Power Automate
VBA neumí plánovanou cloudovou synchronizaci. Pokud potřebujete:
- Sešit, který se synchronizuje s Brevo každou hodinu, aniž by ho někdo otevíral
- Sešit v OneDrive/SharePoint, editovaný z webu
- IT oddělení, které zakazuje desktopová makra
…pak chcete Office Scripts (cloudový ekvivalent Apps Script od Microsoftu) plus Power Automate (jejich vrstva pro plánování a HTTP).
Rozdělení: Office Scripts načte list a vrátí data kontaktů. Power Automate ta data vezme a POSTne je do Brevo na trigger.
Office Script (Excel pro 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;}Power Automate flow:
- Trigger: Recurrence (každou 1 hodinu), nebo ruční tlačítko, nebo „When a row is modified”, pokud chcete synchronizaci řízenou změnami.
- Action: Excel Online → Run script, namiřte na svůj sešit a skript výše. Uložte jeho návratovou hodnotu jako
contacts. - Action: HTTP (toto je Premium konektor, viz poznámka o licencování níže).
- 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}
- Method:
- Action: Condition → pokud status code ≠ 202, pošlete upozornění do Teams/e-mailem.
Realita licencování: akce HTTP je Premium konektor Power Automate. V plánech Microsoft 365 Business Basic/Standard dostáváte standardní konektory, ale ne Premium. Nejlevnější obchvat je doplněk Power Automate Premium (asi 15 USD/uživatel/měsíc v době psaní), nebo přesunout HTTP do malé Azure Function, kterou standardní flow může zavolat. Pokud už jste na E3/E5 s Premium v ceně, máte to.
Tohle je hlavní důvod, proč je příběh Apps Script čistší: UrlFetchApp v Apps Script je zdarma a neomezený, zatímco ekvivalent Microsoftu staví síťové volání za placený konektor.
VBA vs Office Scripts vs Apps Script: kdy co zvolit
| Potřeba | Nejlepší volba |
|---|---|
| Tlačítko jedním kliknutím v sešitu, který váš tým denně otevírá | VBA makro (tato příručka, horní polovina) |
| Sešit v OneDrive/SharePoint, hodinová auto-sync | Office Scripts + Power Automate (pro HTTP potřeba Premium) |
| Pouze Mac Excel, nemůžete VBA | Office Scripts + Power Automate |
| Data žijí v Google Sheets, ne v Excelu | Apps Script (zdarma, plánované triggery v ceně) |
| Jednorázový import, už nikdy ho nebudete potřebovat | Save As → CSV a skript pro CSV import |
| Hromadný import ze souboru >10 MB | CSV s fileUrl, viz příručka CSV |
Proč to vyhrává nad Zapierem / no-code platformami
Pro opakovanou úlohu Excel do Brevo si automatizační nástroje třetích stran (Zapier, Make, n8n) účtují za úkol a staví třetí stranu mezi vaše data a Brevo. Přístup VBA má nulové průběžné náklady, žádný tok dat přes třetí stranu a žije uvnitř souboru. Když se sešit přesouvá, integrace se přesouvá s ním. Office Scripts + Power Automate je podobné, ale s Microsoftem jako třetí stranou (už ve vašem stacku, pokud jste na M365).
Celý smysl endpointu Brevo POST /v3/contacts/import je, že nepotřebujete lepicí platformu, vaše nástroje už umí dělat HTTP požadavky.