Slik dytter du Excel-kontakter til Brevo med en VBA-makro (og Office Scripts-alternativet)

En fungerende VBA-makro som poster kontakter fra et Excel-ark til Brevos API med ett klikk, pluss når du heller bør bruke Office Scripts + Power Automate, og avveiningene mot et Google Apps Script-oppsett.

Featured image for article: Slik dytter du Excel-kontakter til Brevo med en VBA-makro (og Office Scripts-alternativet)

Du har kontakter i Excel og du vil ha dem i Brevo. Det raske og skitne svaret er å lagre filen som .csv og importere den, det fungerer fint én gang. For alt du gjør gjentatte ganger, ukentlig salgsoverlevering, en arbeidsbok teamet ditt oppdaterer daglig, en partnerliste som blir oppfrisket, vil du ha en knapp rett inne i Excel som gjør synkroniseringen.

Denne guiden dekker de to veiene som faktisk gir mening for det:

  1. En VBA-makro innebygd i arbeidsboken, ingen lisensiering, ingen sky, fungerer offline, kjører i samme øyeblikk en bruker klikker en knapp. Riktig svar for omtrent 80% av “Excel-til-Brevo”-tilfeller.
  2. Office Scripts + Power Automate, TypeScript i stedet for VBA, kjører i skyen, støtter planlagte triggere. Riktig svar hvis arbeidsboken ligger i OneDrive/SharePoint og du vil ha uovervåket synkronisering, men vær oppmerksom på Power Automate-lisensieringen.

Hvis du ser etter Google Sheets-ekvivalenten, se følgeartikkelen om Apps Script. Og hvis du bare vil ha en engangs CSV-import fra et skript på laptopen din, har CSV-importguiden Python-, Node.js- og cURL-versjoner.

Hva makroen gjør

Når brukeren klikker en “Sync to Brevo”-knapp på arket:

  1. Les hver rad fra det aktive regnearket (header-rad først, én kontakt per rad).
  2. Bygg et JSON-array formet for Brevos jsonBody-parameter.
  3. POST det til https://api.brevo.com/v3/contacts/import med arbeidsbokens lagrede API-nøkkel.
  4. Vis en meldingsboks med resultatet.

Det er det. Omtrent 120 linjer med VBA. Under er den fullstendige, fungerende modulen.

Ark-layouten makroen forventer

emailfirstNamelastNamecompanycity
[email protected]JaneDoeAcmeBerlin
[email protected]JohnSmithGlobexParis

email er obligatorisk. Hver annen kolonne blir et Brevo-kontaktattributt, mappet av kolonneoverskriften (med store bokstaver) til attributtnavnet. Så firstName -> FIRSTNAME, company -> COMPANY. Egendefinerte attributter (alt utover standardsettet) må finnes i Brevo-kontoen din først, definer dem under Contacts -> Settings -> Contact attributes.

Steg 1: Åpne VBA-editoren

I Excel: trykk Alt + F11. VBA-editoren åpnes. I Project-panelet til venstre, høyreklikk arbeidsboken din og velg Insert -> Module. En tom Module1 dukker opp.

Steg 2: Lim inn hele makroen

Erstatt Module1’s innhold med dette:

' ===========================================================================
' 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

Steg 3: Lagre arbeidsboken som .xlsm

VBA-makroer består bare i makro-aktiverte arbeidsbøker. Save As -> velg Excel Macro-Enabled Workbook (.xlsm). Det vanlige .xlsx-formatet fjerner makroer stille, mange mister kode på denne måten første gang.

Steg 4: Konfigurer API-nøkkelen din

Kjør ConfigureApiKey én gang. Enten:

  • I VBA-editoren, klikk hvor som helst inne i ConfigureApiKey-suben og trykk F5, eller
  • I Excel, Developer -> Macros, velg ConfigureApiKey, Run.

Lim inn xkeysib-...-nøkkelen din. Makroen lagrer den som en egendefinert dokumentegenskap inne i selve arbeidsboken, den er ikke i kildekode, ikke i registeret, og reiser med filen (så vær obs: hvis du sender .xlsm-en til noen, går API-nøkkelen med).

Hvis du heller vil legge nøkkelen utenfor arbeidsboken, bytt lagringen til Windows-registeret:

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

SaveSetting/GetSetting skriver under HKCU\Software\VB and VBA Program Settings\Brevo\Sync, per bruker, ikke per arbeidsbok. Bruk dette hvis flere arbeidsbøker skal dele én nøkkel, eller hvis du ikke vil ha nøkkelen i filen.

Steg 5: Legg til en knapp på arket

Det er dette som gjør det til en ett-klikks-opplevelse for ikke-tekniske brukere.

Insert -> Shapes -> Rectangle, slipp en på arket, merk den “Sync to Brevo.” Høyreklikk formen -> Assign Macro -> velg SyncSheetToBrevo. Ferdig.

Eller, for et mer polert UI, legg til en egendefinert ribbon-fane via Office Custom UI Editor, men for de fleste interne verktøy er form-som-knapp mer enn nok.

Steg 6: Kjør den

Klikk knappen. Makroen leser radene, batcher dem, poster hver batch til Brevo, og viser en sammendragsmeldingsboks. Brevos import er asynkron, så suksessmeldingen betyr “Brevo aksepterte batchen”, den faktiske kontaktopprettelsen skjer serverside i de neste sekundene. Du får en e-postoppsummering fra Brevo når den er ferdig (med mindre du setter disableNotification: true).

Vanlige feller

Knappen gjør ingenting og det er ingen feil. Makroer er deaktivert. Se på den gule sikkerhetslinjen øverst på arket, klikk Enable Content. Hvis organisasjonen din blokkerer makroer, se trust-center / code-signing-veien under.

Compile error: User-defined type not defined. Du er på Mac Excel, som ikke har MSXML2.XMLHTTP. Mac VBA kan ikke gjøre HTTPS-forespørsler direkte; bruk Office Scripts-veien under i stedet.

400 Bad Request fra Brevo uten åpenbar årsak. Nesten alltid en av: (a) et egendefinert attributt i arket ditt finnes ikke i Brevo ennå, opprett det først; (b) JSON-escaping-bug, anførselstegn eller backslash i celleverdier som ikke ble escapet. EscapeJson-funksjonen i koden håndterer standardtilfellene; hvis dataen din har rare tegn, logg payload til Immediate-vinduet (Debug.Print payload) og inspiser.

401 Unauthorized. Feil header. Det er api-key (små bokstaver, bindestrek), ikke Authorization. Makroen bruker den riktige, men hvis du kopierte et utdrag fra et annet sted, dobbeltsjekk.

Excel fryser på store importer. Makroen kjører synkront på UI-tråden. For 50.000+ rader vil du se Excel henge i 10-30 sekunder mens den bygger JSON og venter på Brevo. Enten godta det, eller bytt MSXML2.XMLHTTP til async-varianten, men på den skalaen er du bedre tjent med Power Automate (neste seksjon).

Når VBA ikke er nok: Office Scripts + Power Automate

VBA kan ikke gjøre planlagt skysynkronisering. Hvis du trenger:

  • Arbeidsboken til å synkronisere til Brevo hver time uten at noen åpner den
  • Arbeidsboken i OneDrive/SharePoint, redigert fra web
  • En IT-avdeling som forbyr desktop-makroer

…da vil du ha Office Scripts (Microsofts skyekvivalent av Apps Script) pluss Power Automate (deres planleggings- og HTTP-lag).

Splitten: Office Scripts leser arket og returnerer kontaktdataen. Power Automate tar den dataen og POSTer den til Brevo på en trigger.

Office Script-en (Excel for nettet -> 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-flyten:

  1. Trigger: Recurrence (hver 1. time), eller manuell knapp, eller “When a row is modified” hvis du vil ha endringsdrevet synkronisering.
  2. Action: Excel Online -> Run script, pek den til arbeidsboken din og skriptet over. Lagre returverdien som contacts.
  3. Action: HTTP (dette er Premium-konnektoren, se lisensieringsnotatet under).
    • 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 -> hvis statuskode ikke er 202, send et Teams/e-postvarsel.

Lisensiering-realitetssjekk: HTTP-action er en Power Automate Premium-konnektor. På Microsoft 365 Business Basic/Standard-planer får du standardkonnektorene men ikke Premium. Den billigste løsningen er Power Automate Premium-tillegget (~$15/bruker/måned ved skrivetid), eller flytt HTTP til en liten Azure Function som standardflyten kan kalle. Hvis du allerede er på E3/E5 med Premium inkludert, er du klar.

Dette er hovedgrunnen til at Apps Script-historien er renere: Apps Scripts UrlFetchApp er gratis og uten begrensninger, mens Microsoft-ekvivalenten plasserer nettverkskallet bak et betalt konnektor-nivå.

VBA vs Office Scripts vs Apps Script: når velge hva

BehovBeste alternativ
Ett-klikks-knapp i en arbeidsbok teamet ditt allerede åpner dagligVBA-makro (denne guiden, øvre halvdel)
Arbeidsbok i OneDrive/SharePoint, automatisk synkronisering hver timeOffice Scripts + Power Automate (trenger Premium for HTTP)
Bare Mac Excel, kan ikke bruke VBAOffice Scripts + Power Automate
Dataen lever i Google Sheets, ikke ExcelApps Script (gratis, planlagte triggere innebygd)
Engangsimport, vil aldri trenges igjenSave As -> CSV og bruk CSV-importskriptet
Bulk-import fra en fil over 10 MBCSV med fileUrl, se CSV-guiden

Hvorfor dette slår Zapier / no-code-plattformer

For en gjentakende Excel-til-Brevo-jobb tar tredjeparts automatiseringsverktøy (Zapier, Make, n8n) betalt per oppgave og setter en tredjepart mellom dataen din og Brevo. VBA-tilnærmingen har null løpende kostnad, ingen tredjeparts dataflyt, og lever inne i filen, når arbeidsboken flyttes, flytter integrasjonen seg med. Office Scripts + Power Automate er likt men med Microsoft som tredjepart (allerede i stacken din hvis du er på M365).

Hele poenget med Brevo POST /v3/contacts/import-endepunktet er at du ikke trenger en lim-plattform, verktøyene dine vet allerede hvordan de skal gjøre HTTP-forespørsler.

Videre lesning

Frequently Asked Questions

Kan en VBA-makro virkelig kalle Brevos API fra inne i Excel?
Ja. VBA kan gjøre HTTP-forespørsler gjennom MSXML2.XMLHTTP, som følger med hver moderne Windows-installasjon. Makroen POSTer JSON til api.brevo.com/v3/contacts/import, samme endepunkt som et Python- eller Node-skript ville truffet. Mac Excel kan også gjøre det via Office Scripts + Power Automate, men desktop Mac VBA kan ikke (ingen MSXML).
Kan jeg kjøre dette etter en tidsplan som Apps Script-tidstriggere?
Ikke fra VBA alene, Excel må være åpen for at Application.OnTime skal fyre. For uovervåket planlagt synkronisering har du to alternativer: (1) Windows Task Scheduler som åpner arbeidsboken og kjører makroen, eller (2) Office Scripts trigget av en Power Automate-planlagt flyt (dekket senere i denne guiden).
Er VBA sikkert? Bedriften min blokkerer makroer.
VBA-makroer kjører med filsystem- og registertilgang, så å blokkere dem som standard er en fornuftig policy. To veier rundt det: (1) signer makroen med et code-signing-sertifikat og legg arbeidsboken i en Trusted Location, eller (2) hopp over VBA helt og bruk Office Scripts (TypeScript, sandbox, ingen filsystemtilgang). Office Scripts er den moderne Microsoft-velsignede veien.
Hvordan sammenlignes dette med Google Apps Script-tilnærmingen?
Apps Script er nærmere sett-og-glem, kjører i Googles sky, planlagte triggere innebygd, ingen Excel/Power Automate-lisens. VBA vinner for offline-arbeid og ett-klikks manuell synkronisering fra en arbeidsbok teamet ditt allerede har åpen. Office Scripts + Power Automate er sky/planlagt-ekvivalenten på Microsoft-siden, men Power Automate trenger ofte en betalt premium-konnektor for utgående HTTP.
Start gratis med Brevo