Comment pousser des contacts Excel vers Brevo avec une macro VBA (et l'alternative Office Scripts)

Une macro VBA fonctionnelle qui poste les contacts d'une feuille Excel vers l'API Brevo en un clic, plus quand utiliser Office Scripts + Power Automate à la place, et les compromis face à un setup Google Apps Script.

Featured image for article: Comment pousser des contacts Excel vers Brevo avec une macro VBA (et l'alternative Office Scripts)

Vous avez des contacts dans Excel et vous les voulez dans Brevo. La réponse rapide et sale est d’enregistrer le fichier en .csv et de l’importer, ce qui va bien une fois. Pour tout ce que vous faites de façon répétée (passation hebdomadaire de l’équipe vente, un classeur que votre équipe met à jour quotidiennement, une liste de partenaires régulièrement rafraîchie), vous voulez un bouton à l’intérieur d’Excel qui fait la synchronisation.

Ce guide couvre les deux voies qui ont vraiment du sens pour ça :

  1. Une macro VBA intégrée au classeur, sans licence, sans cloud, fonctionne hors ligne, se lance dès qu’un utilisateur clique sur un bouton. La bonne réponse pour environ 80 % des cas « Excel vers Brevo ».
  2. Office Scripts + Power Automate, TypeScript à la place de VBA, tourne dans le cloud, supporte les déclencheurs planifiés. La bonne réponse si le classeur vit dans OneDrive/SharePoint et que vous voulez une synchronisation sans surveillance, mais soyez attentif à la licence Power Automate.

Si vous cherchez l’équivalent Google Sheets, voyez l’article compagnon sur Apps Script. Et si vous voulez juste un import CSV unique depuis un script sur votre portable, le guide d’import CSV propose des versions Python, Node.js et cURL.

Ce que fait la macro

Quand l’utilisateur clique sur un bouton « Sync to Brevo » dans la feuille :

  1. Lit chaque ligne de la feuille active (en-tête en premier, un contact par ligne).
  2. Construit un tableau JSON formé pour le paramètre jsonBody de Brevo.
  3. Le poste sur https://api.brevo.com/v3/contacts/import avec la clé API stockée dans le classeur.
  4. Affiche une boîte de message avec le résultat.

C’est tout. Environ 120 lignes de VBA. Ci-dessous le module complet et fonctionnel.

Disposition de feuille attendue par la macro

emailfirstNamelastNamecompanycity
[email protected]JaneDoeAcmeBerlin
[email protected]JohnSmithGlobexParis

email est obligatoire. Toute autre colonne devient un attribut de contact Brevo, mappé par l’en-tête de colonne (en majuscules) au nom d’attribut. Donc firstNameFIRSTNAME, companyCOMPANY. Les attributs personnalisés (tout ce qui dépasse le set standard) doivent d’abord exister dans votre compte Brevo, définissez-les sous Contacts → Paramètres → Attributs de contact.

Étape 1 : ouvrir l’éditeur VBA

Dans Excel : appuyez sur Alt + F11. L’éditeur VBA s’ouvre. Dans le panneau Projet à gauche, clic droit sur votre classeur et choisissez Insertion → Module. Un Module1 vide apparaît.

Étape 2 : coller la macro complète

Remplacez le contenu de Module1 par ceci :

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

Étape 3 : enregistrer le classeur en .xlsm

Les macros VBA ne persistent que dans des classeurs activant les macros. Enregistrer sous → choisissez Classeur Excel prenant en charge les macros (.xlsm). Le format .xlsx standard supprime les macros silencieusement, beaucoup de gens perdent du code comme ça la première fois.

Étape 4 : configurer votre clé API

Lancez ConfigureApiKey une fois. Soit :

  • Dans l’éditeur VBA, cliquez n’importe où dans le sub ConfigureApiKey et appuyez sur F5, soit
  • Dans Excel, Développeur → Macros, choisissez ConfigureApiKey, Exécuter.

Collez votre clé xkeysib-.... La macro la stocke comme propriété personnalisée du document à l’intérieur du classeur, elle n’est pas dans le code source, pas dans le registre, et voyage avec le fichier (donc attention : si vous envoyez le .xlsm à quelqu’un, la clé API part avec).

Si vous préférez stocker la clé en dehors du classeur, basculez le stockage vers le registre Windows :

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

SaveSetting/GetSetting écrit sous HKCU\Software\VB and VBA Program Settings\Brevo\Sync, par utilisateur, pas par classeur. Utilisez ça si plusieurs classeurs doivent partager la même clé, ou si vous ne voulez pas la clé dans le fichier.

Étape 5 : ajouter un bouton à la feuille

C’est ce qui en fait une expérience en un clic pour les utilisateurs non techniques.

Insertion → Formes → Rectangle, déposez-en un sur la feuille, étiquetez-le « Sync to Brevo. » Clic droit sur la forme → Affecter une macro → choisissez SyncSheetToBrevo. Terminé.

Ou, pour une interface plus soignée, ajoutez un onglet de ruban personnalisé via l’Office Custom UI Editor, mais pour la plupart des outils internes, le bouton-en-forme suffit largement.

Étape 6 : exécuter

Cliquez sur le bouton. La macro lit les lignes, les met en lots, poste chaque lot sur Brevo et affiche une boîte de message récapitulative. L’import Brevo est asynchrone, donc le message de succès signifie « Brevo a accepté le lot », la création réelle des contacts se fait côté serveur dans les secondes qui suivent. Vous recevrez un e-mail récapitulatif de Brevo une fois l’opération terminée (sauf si vous mettez disableNotification: true).

Pièges courants

Le bouton ne fait rien et il n’y a pas d’erreur. Les macros sont désactivées. Regardez la barre de sécurité jaune en haut de la feuille, cliquez sur Activer le contenu. Si votre organisation bloque les macros, voyez la voie centre de confiance / signature de code plus bas.

Compile error: User-defined type not defined. Vous êtes sur Mac Excel, qui n’a pas MSXML2.XMLHTTP. Le VBA Mac ne peut pas faire de requêtes HTTPS directement, utilisez plutôt la voie Office Scripts ci-dessous.

400 Bad Request de Brevo sans cause évidente. Presque toujours l’une de ces deux : (a) un attribut personnalisé dans votre feuille n’existe pas encore dans Brevo, créez-le d’abord ; (b) un bug d’échappement JSON, des guillemets ou backslashes dans des valeurs de cellule qui n’ont pas été échappés. La fonction EscapeJson du code traite les cas standard, si vos données ont des caractères bizarres, loguez payload dans la fenêtre Exécution (Debug.Print payload) et inspectez.

401 Unauthorized. Mauvais en-tête. C’est api-key (en minuscules, avec tiret), pas Authorization. La macro utilise le bon, mais si vous avez copié un snippet d’ailleurs, revérifiez.

Excel se fige sur les gros imports. La macro tourne de façon synchrone sur le thread de l’interface. Pour 50 000 lignes et plus, vous verrez Excel rester figé 10 à 30 secondes pendant qu’il construit le JSON et attend Brevo. Acceptez-le, ou basculez MSXML2.XMLHTTP sur sa variante asynchrone, mais à cette échelle vous êtes mieux servi par Power Automate (section suivante).

Quand VBA ne suffit plus : Office Scripts + Power Automate

VBA ne peut pas faire de synchronisation cloud planifiée. Si vous avez besoin :

  • Que le classeur se synchronise vers Brevo toutes les heures sans que personne ne l’ouvre
  • Que le classeur soit dans OneDrive/SharePoint, édité depuis le web
  • D’un service IT qui interdit les macros bureau

…alors vous voulez Office Scripts (l’équivalent cloud d’Apps Script chez Microsoft) plus Power Automate (leur couche planification et HTTP).

La répartition : Office Scripts lit la feuille et renvoie les données de contact. Power Automate prend ces données et les poste sur Brevo via un déclencheur.

L’Office Script (Excel pour le web → Automatiser → Nouveau 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;
}

Le flux Power Automate :

  1. Déclencheur : Récurrence (toutes les heures), ou bouton manuel, ou « Quand une ligne est modifiée » si vous voulez une synchronisation pilotée par changements.
  2. Action : Excel Online → Exécuter le script, pointez-le sur votre classeur et le script ci-dessus. Sauvez la valeur de retour comme contacts.
  3. Action : HTTP (c’est le connecteur Premium, voir la note de licence ci-dessous).
    • Méthode : POST
    • URI : https://api.brevo.com/v3/contacts/import
    • En-têtes : api-key: xkeysib-..., Content-Type: application/json
    • Body :
      {
      "jsonBody": @{outputs('Run_script')?['body/result']},
      "listIds": [42],
      "updateExistingContacts": true
      }
  4. Action : Condition, si le code de statut ≠ 202, envoyez une alerte Teams ou e-mail.

Réalité des licences : l’action HTTP est un connecteur Premium de Power Automate. Sur les plans Microsoft 365 Business Basic/Standard, vous avez les connecteurs standard mais pas Premium. Le contournement le moins cher est l’add-on Power Automate Premium (environ 15 USD par utilisateur et par mois au moment de l’écriture), ou déplacer le HTTP dans une petite Azure Function que le flux standard peut appeler. Si vous êtes déjà en E3/E5 avec Premium inclus, c’est bon.

C’est la raison principale pour laquelle l’histoire d’Apps Script est plus propre : UrlFetchApp d’Apps Script est gratuit et sans restriction, alors que l’équivalent Microsoft place l’appel réseau derrière une couche de connecteur payante.

VBA, Office Scripts ou Apps Script : quand choisir quoi

BesoinMeilleure option
Bouton en un clic dans un classeur que votre équipe ouvre déjà tous les joursMacro VBA (ce guide, partie haute)
Classeur dans OneDrive/SharePoint, auto-synchro horaireOffice Scripts + Power Automate (Premium nécessaire pour HTTP)
Mac Excel uniquement, VBA impossibleOffice Scripts + Power Automate
Les données vivent dans Google Sheets, pas ExcelApps Script (gratuit, déclencheurs planifiés intégrés)
Import unique, qui ne se reproduira jamaisEnregistrer sous → CSV et utiliser le script d’import CSV
Import en masse depuis un fichier de plus de 10 MoCSV avec fileUrl, voir le guide CSV

Pourquoi cela bat Zapier et les plateformes no-code

Pour un job récurrent Excel vers Brevo, les outils d’automatisation tiers (Zapier, Make, n8n) facturent à la tâche et placent un tiers entre vos données et Brevo. L’approche VBA a zéro coût récurrent, aucun flux de données via tiers, et vit à l’intérieur du fichier, quand le classeur bouge, l’intégration bouge avec lui. Office Scripts + Power Automate est similaire mais avec Microsoft comme tiers (déjà dans votre stack si vous êtes sur M365).

Tout l’intérêt de l’endpoint POST /v3/contacts/import de Brevo est que vous n’avez pas besoin d’une plateforme de colle, vos outils savent déjà faire des requêtes HTTP.

Pour aller plus loin

Frequently Asked Questions

Une macro VBA peut-elle vraiment appeler l'API Brevo depuis Excel ?
Oui. VBA peut faire des requêtes HTTP via MSXML2.XMLHTTP, qui est livré avec toute installation Windows moderne. La macro POST du JSON vers api.brevo.com/v3/contacts/import, le même endpoint qu'un script Python ou Node ciblerait. Mac Excel le peut aussi via Office Scripts + Power Automate, mais le VBA Mac bureau ne le peut pas (pas de MSXML).
Puis-je l'exécuter de façon planifiée comme avec les déclencheurs temporels Apps Script ?
Pas depuis VBA seul, Excel doit être ouvert pour que Application.OnTime se déclenche. Pour une synchronisation planifiée et sans surveillance, vous avez deux options : (1) le Planificateur de tâches Windows qui ouvre le classeur et lance la macro, ou (2) Office Scripts déclenché par un flux planifié Power Automate (couvert plus loin dans ce guide).
VBA est-il sûr ? Mon entreprise bloque les macros.
Les macros VBA tournent avec accès au système de fichiers et au registre, donc les bloquer par défaut est une politique sensée. Deux contournements : (1) signer la macro avec un certificat de signature de code et placer le classeur dans un Trusted Location, ou (2) sauter VBA entièrement et utiliser Office Scripts (TypeScript, en sandbox, sans accès au système de fichiers). Office Scripts est la voie moderne recommandée par Microsoft.
Comment cela se compare-t-il à l'approche Google Apps Script ?
Apps Script est plus proche du set-and-forget, tourne dans le cloud Google, déclencheurs planifiés intégrés, pas de licence Excel ni Power Automate. VBA gagne pour le travail hors ligne et la synchronisation manuelle en un clic depuis un classeur que votre équipe a déjà ouvert. Office Scripts + Power Automate est l'équivalent cloud planifié côté Microsoft, mais Power Automate a souvent besoin d'un connecteur premium payant pour le HTTP sortant.
Commencez gratuitement avec Brevo