Så skickar du Excel-kontakter till Brevo med ett VBA-makro (och alternativet med Office Scripts)

Ett fungerande VBA-makro som postar kontakter från ett Excel-ark till Brevos API med ett klick. Plus när du i stället bör använda Office Scripts + Power Automate, och avvägningarna mot en lösning med Google Apps Script.

Featured image for article: Så skickar du Excel-kontakter till Brevo med ett VBA-makro (och alternativet med Office Scripts)

Du har kontakter i Excel och du vill ha in dem i Brevo. Det snabba och fula svaret är att spara filen som .csv och importera den, vilket går bra en gång. För allt du gör återkommande, veckovis säljöverlämning, en arbetsbok ditt team uppdaterar varje dag, en partnerlista som fräschas upp, vill du ha en knapp inuti Excel som gör synken.

Den här guiden går igenom de två vägar som faktiskt är vettiga för det:

  1. Ett VBA-makro inbäddat i arbetsboken. Ingen licens, inget moln, fungerar offline, körs i samma stund som en användare klickar på en knapp. Rätt svar för ungefär 80 % av “Excel till Brevo”-fallen.
  2. Office Scripts + Power Automate. TypeScript i stället för VBA, körs i molnet, stöder schemalagda triggers. Rätt svar om arbetsboken ligger i OneDrive/SharePoint och du vill ha synk utan tillsyn, men var medveten om Power Automate-licensieringen.

Om du letar efter Google Sheets-motsvarigheten, se följeartikeln om Apps Script. Och om du bara vill ha en engångs-CSV-import från ett skript på din laptop har CSV-importguiden versioner i Python, Node.js och cURL.

Vad makrot gör

När användaren klickar på en knapp “Sync to Brevo” på arket:

  1. Läs varje rad från det aktiva arbetsbladet (rubrikrad först, en kontakt per rad).
  2. Bygg en JSON-array i den form Brevos jsonBody-parameter förväntar sig.
  3. Posta till https://api.brevo.com/v3/contacts/import med arbetsbokens lagrade API-nyckel.
  4. Visa en meddelanderuta med resultatet.

Det är allt. Cirka 120 rader VBA. Nedan följer hela den fungerande modulen.

Arklayout makrot förväntar sig

emailfirstNamelastNamecompanycity
[email protected]JaneDoeAcmeBerlin
[email protected]JohnSmithGlobexParis

email är obligatorisk. Varje annan kolumn blir ett Brevo-kontaktattribut, mappat efter kolumnrubriken (versaler) till attributnamnet. Så firstName blir FIRSTNAME, company blir COMPANY. Anpassade attribut (allt utöver standarduppsättningen) måste finnas i ditt Brevo-konto först. Definiera dem under Contacts → Settings → Contact attributes.

Steg 1: öppna VBA-editorn

I Excel: tryck Alt + F11. VBA-editorn öppnas. I Project-panelen till vänster, högerklicka på din arbetsbok och välj Insert → Module. En tom Module1 dyker upp.

Steg 2: klistra in hela makrot

Ersätt innehållet i Module1 med detta:

' ===========================================================================
' 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: spara arbetsboken som .xlsm

VBA-makron överlever bara i makroaktiverade arbetsböcker. Spara som, välj Excel Macro-Enabled Workbook (.xlsm). Det vanliga .xlsx-formatet rensar makron tyst. Många tappar kod på det sättet första gången.

Steg 4: konfigurera din API-nyckel

Kör ConfigureApiKey en gång. Antingen:

  • I VBA-editorn, klicka var som helst inuti ConfigureApiKey-sub:en och tryck F5, eller
  • I Excel, Developer → Macros, välj ConfigureApiKey, Run.

Klistra in din xkeysib-...-nyckel. Makrot lagrar den som en custom document property inuti själva arbetsboken. Den är inte i källkoden, inte i registret, och följer med filen (så var medveten: om du mejlar .xlsm-filen till någon följer API-nyckeln med).

Om du hellre vill lägga nyckeln utanför arbetsboken byter du lagringen till Windows-registret:

' 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 användare, inte per arbetsbok. Använd det om flera arbetsböcker ska dela en nyckel, eller om du inte vill ha nyckeln i filen.

Steg 5: lägg till en knapp på arket

Det här är vad som gör det till en ett-klicks-upplevelse för icke-tekniska användare.

Insert → Shapes → Rectangle, släpp en på arket, märk den “Sync to Brevo.” Högerklicka på formen, Assign Macro, välj SyncSheetToBrevo. Klart.

Eller, för ett mer polerat gränssnitt, lägg till en anpassad menyflik via Office Custom UI Editor. Men för de flesta interna verktyg räcker en form-som-knapp gott.

Steg 6: kör det

Klicka på knappen. Makrot läser raderna, batchar dem, postar varje batch till Brevo och visar en sammanfattningsruta. Brevos import är asynkron, så meddelandet att det lyckats betyder “Brevo har tagit emot batchen”. Själva kontaktskapandet sker på serversidan inom de närmaste sekunderna. Du får en e-postsammanfattning från Brevo när det är klart (om du inte satt disableNotification: true).

Vanliga fallgropar

Knappen gör ingenting och inget felmeddelande visas. Makron är inaktiverade. Titta på den gula säkerhetsraden överst på arket, klicka Enable Content. Om din organisation blockerar makron, se vägen via trust center och kodsignering nedan.

Compile error: User-defined type not defined. Du sitter på Mac Excel, som inte har MSXML2.XMLHTTP. Mac VBA kan inte göra HTTPS-anrop direkt. Använd Office Scripts-vägen nedan i stället.

400 Bad Request från Brevo utan tydlig orsak. Nästan alltid en av: (a) ett anpassat attribut i ditt ark finns inte i Brevo ännu, skapa det först; (b) JSON-escapingbug, citattecken eller bakåtsnedstreck i cellvärden som inte blev escapade. Funktionen EscapeJson i koden hanterar standardfallen. Om din data har konstiga tecken, logga payload till Immediate-fönstret (Debug.Print payload) och inspektera.

401 Unauthorized. Fel header. Det är api-key (gemener, bindestreck), inte Authorization. Makrot använder rätt namn, men om du kopierat ett snippet någon annanstans ifrån, dubbelkolla.

Excel fryser vid stora importer. Makrot körs synkront på UI-tråden. För 50 000+ rader får du se Excel hänga i 10 till 30 sekunder medan det bygger JSON och väntar på Brevo. Antingen accepterar du det, eller så byter du MSXML2.XMLHTTP till dess asynkrona variant. Men i den skalan har du det bättre i Power Automate (nästa avsnitt).

När VBA inte räcker: Office Scripts + Power Automate

VBA kan inte göra schemalagd molnsynk. Om du behöver:

  • Att arbetsboken synkar till Brevo varje timme utan att någon öppnar den
  • Att arbetsboken ligger i OneDrive/SharePoint, redigeras från webben
  • En IT-avdelning som förbjuder skrivbordsmakron

…då vill du ha Office Scripts (Microsofts molnmotsvarighet till Apps Script) plus Power Automate (deras schema- och HTTP-lager).

Uppdelningen: Office Scripts läser arket och returnerar kontaktdatan. Power Automate tar den datan och postar den till Brevo vid en trigger.

Office Script:et (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;
}

Power Automate-flödet:

  1. Trigger: Recurrence (varje 1 timme), eller manuell knapp, eller “When a row is modified” om du vill ha förändringsdriven synk.
  2. Action: Excel Online → Run script. Peka på din arbetsbok och skriptet ovan. Spara dess returvärde som contacts.
  3. Action: HTTP (det här är Premium-konnektorn, se licensnoten nedan).
    • 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. Om statuskod inte är 202, skicka en Teams- eller e-postvarning.

Verklighetscheck för licensiering: HTTP-actionen är en Power Automate Premium-konnektor. På planerna Microsoft 365 Business Basic/Standard får du standardkonnektorerna men inte Premium. Den billigaste vägen runt det är tillägget Power Automate Premium (cirka 15 USD/användare/månad i skrivande stund), eller att flytta HTTP till en liten Azure Function som det vanliga flödet kan anropa. Om du redan ligger på E3/E5 med Premium inkluderat är du klar.

Det är huvudskälet till att Apps Script-berättelsen är renare: Apps Scripts UrlFetchApp är gratis och utan begränsningar, medan Microsofts motsvarighet sätter nätverksanropet bakom en betald konnektornivå.

VBA mot Office Scripts mot Apps Script: när väljer du vad

BehovBästa val
Ett-klicks-knapp i en arbetsbok ditt team redan öppnar varje dagVBA-makro (den här guiden, övre halvan)
Arbetsbok i OneDrive/SharePoint, autosynk varje timmeOffice Scripts + Power Automate (kräver Premium för HTTP)
Bara Mac Excel, kan inte använda VBAOffice Scripts + Power Automate
Datan ligger i Google Sheets, inte ExcelApps Script (gratis, schemalagda triggers inbyggt)
Engångsimport, kommer aldrig behövas igenSpara som CSV och använd CSV-importskriptet
Massimport från en fil >10 MBCSV med fileUrl, se CSV-guiden

Varför det här slår Zapier och no-code-plattformar

För ett återkommande Excel-till-Brevo-jobb tar tredjepartsverktyg för automatisering (Zapier, Make, n8n) betalt per task och sätter en tredje part mellan din data och Brevo. VBA-vägen har noll löpande kostnad, inget tredjepartsdataflöde, och bor inuti filen. När arbetsboken flyttar, flyttar integrationen med. Office Scripts + Power Automate är likadant fast med Microsoft som tredje part (redan i din stack om du ligger på M365).

Hela poängen med Brevos endpoint POST /v3/contacts/import är att du inte behöver en limplattform. Dina verktyg vet redan hur man gör HTTP-anrop.

Vidare läsning

Frequently Asked Questions

Kan ett VBA-makro verkligen anropa Brevos API från Excel?
Ja. VBA kan göra HTTP-anrop via MSXML2.XMLHTTP, som följer med varje modern Windows-installation. Makrot postar JSON till api.brevo.com/v3/contacts/import, samma endpoint som ett Python- eller Node-skript skulle träffa. Mac Excel klarar det också via Office Scripts + Power Automate, men VBA på Mac-skrivbordet kan inte (inget MSXML).
Kan jag köra det här enligt schema som tidstriggers i Apps Script?
Inte från VBA ensamt. Excel måste vara öppen för att Application.OnTime ska fyra. För schemalagd synk utan tillsyn har du två alternativ: (1) Windows Task Scheduler som öppnar arbetsboken och kör makrot, eller (2) Office Scripts som triggas av ett schemalagt Power Automate-flöde (täcks senare i guiden).
Är VBA säkert? Mitt företag blockerar makron.
VBA-makron körs med åtkomst till filsystem och register, så att blockera dem som standard är en rimlig policy. Två vägar runt det: (1) signera makrot med ett kodsigneringscertifikat och lägg arbetsboken i en Trusted Location, eller (2) hoppa över VBA helt och använd Office Scripts (TypeScript, sandlådat, ingen filsystemsåtkomst). Office Scripts är den moderna Microsoft-välsignade vägen.
Hur står sig det här mot lösningen med Google Apps Script?
Apps Script är närmare set-and-forget: körs i Googles moln, schemalagda triggers inbyggt, ingen Excel- eller Power Automate-licens. VBA vinner för offlinearbete och ett-klicks manuell synk från en arbetsbok som ditt team redan har öppen. Office Scripts + Power Automate är moln- och schemavarianten på Microsoft-sidan, men Power Automate kräver ofta en betald premiumkonnektor för utgående HTTP.
Börja gratis med Brevo