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.
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 :
- 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 ».
- 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 :
- Lit chaque ligne de la feuille active (en-tête en premier, un contact par ligne).
- Construit un tableau JSON formé pour le paramètre
jsonBodyde Brevo. - Le poste sur
https://api.brevo.com/v3/contacts/importavec la clé API stockée dans le classeur. - 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
| firstName | lastName | company | city | |
|---|---|---|---|---|
| [email protected] | Jane | Doe | Acme | Berlin |
| [email protected] | John | Smith | Globex | Paris |
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 firstName → FIRSTNAME, company → COMPANY. 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 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 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
ConfigureApiKeyet appuyez surF5, 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 :
- 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.
- Action : Excel Online → Exécuter le script, pointez-le sur votre classeur et le script ci-dessus. Sauvez la valeur de retour comme
contacts. - 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}
- Méthode :
- 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
| Besoin | Meilleure option |
|---|---|
| Bouton en un clic dans un classeur que votre équipe ouvre déjà tous les jours | Macro VBA (ce guide, partie haute) |
| Classeur dans OneDrive/SharePoint, auto-synchro horaire | Office Scripts + Power Automate (Premium nécessaire pour HTTP) |
| Mac Excel uniquement, VBA impossible | Office Scripts + Power Automate |
| Les données vivent dans Google Sheets, pas Excel | Apps Script (gratuit, déclencheurs planifiés intégrés) |
| Import unique, qui ne se reproduira jamais | Enregistrer sous → CSV et utiliser le script d’import CSV |
| Import en masse depuis un fichier de plus de 10 Mo | CSV 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.