Como empurrar contatos do Excel para a Brevo com uma macro VBA (e a alternativa Office Scripts)
Uma macro VBA que funciona e que posta contatos de uma planilha Excel para a API da Brevo num clique, mais quando usar Office Scripts + Power Automate no lugar e os trade-offs em relação a um setup com Google Apps Script.
Você tem contatos no Excel e quer eles na Brevo. A resposta rápida e suja é salvar o arquivo como .csv e importar, o que está bom para uma vez. Para qualquer coisa que você está fazendo de forma repetida (entrega semanal de vendas, uma pasta de trabalho que seu time atualiza todo dia, uma lista de parceiros que é renovada), você quer um botão dentro do Excel que faça a sincronização.
Esta guia cobre os dois caminhos que realmente fazem sentido para isso:
- Uma macro VBA embutida na pasta de trabalho: sem licenciamento, sem nuvem, funciona offline, roda no momento em que o usuário clica num botão. A resposta certa para uns 80% dos casos de “Excel para Brevo”.
- Office Scripts + Power Automate: TypeScript no lugar de VBA, roda na nuvem, suporta triggers agendados. A resposta certa se a pasta de trabalho vive no OneDrive/SharePoint e você quer sincronização sem assistência, mas fique atento ao licenciamento do Power Automate.
Se você procura o equivalente do Google Sheets, veja o artigo companheiro sobre Apps Script. E se você só quer uma importação de CSV única de um script no seu laptop, o guia de importação CSV tem versões em Python, Node.js e cURL.
O que a macro faz
Quando o usuário clica num botão “Sync to Brevo” na planilha:
- Lê toda linha da planilha ativa (linha de cabeçalho primeiro, um contato por linha).
- Monta um array JSON no formato do parâmetro
jsonBodyda Brevo. - Faz POST em
https://api.brevo.com/v3/contacts/importcom a API key armazenada na pasta de trabalho. - Mostra uma caixa de mensagem com o resultado.
É isso. Cerca de 120 linhas de VBA. Embaixo está o módulo completo, funcional.
Layout de planilha que a macro espera
| firstName | lastName | company | city | |
|---|---|---|---|---|
| [email protected] | Jane | Doe | Acme | Berlin |
| [email protected] | John | Smith | Globex | Paris |
email é obrigatório. Cada outra coluna vira um atributo de contato da Brevo, mapeado pelo cabeçalho da coluna (em maiúsculas) para o nome do atributo. Então firstName → FIRSTNAME, company → COMPANY. Atributos personalizados (qualquer coisa além do conjunto padrão) precisam existir na sua conta da Brevo antes, defina eles em Contatos → Configurações → Atributos do contato.
Passo 1: abrir o editor VBA
No Excel: aperte Alt + F11. O editor VBA abre. No painel Project à esquerda, clique direito na sua pasta de trabalho e escolha Insert → Module. Um Module1 em branco aparece.
Passo 2: colar a macro completa
Substitua o conteúdo de Module1 por isto:
' ===========================================================================' 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 FunctionPasso 3: salve a pasta de trabalho como .xlsm
Macros VBA só persistem em pastas de trabalho com macro habilitada. Salvar como → escolha Pasta de Trabalho Habilitada para Macro do Excel (.xlsm). O formato .xlsx simples remove macros em silêncio, muita gente perde código assim na primeira vez.
Passo 4: configure sua API key
Rode ConfigureApiKey uma vez. Ou:
- No editor VBA, clique em qualquer lugar dentro do sub
ConfigureApiKeye aperteF5, ou - No Excel, Desenvolvedor → Macros, escolha
ConfigureApiKey, Executar.
Cole sua chave xkeysib-.... A macro guarda como propriedade de documento personalizada dentro da própria pasta de trabalho, não está no código fonte, não está no registro, e viaja com o arquivo (então atenção: se você mandar o .xlsm por email para alguém, a API key vai junto).
Se você prefere colocar a chave fora da pasta de trabalho, troque o armazenamento para o registro do Windows:
' Replace the body of ConfigureApiKey with:SaveSetting "Brevo", "Sync", "ApiKey", key
' And GetApiKey with:GetApiKey = GetSetting("Brevo", "Sync", "ApiKey", "")SaveSetting/GetSetting escreve embaixo de HKCU\Software\VB and VBA Program Settings\Brevo\Sync, por usuário, não por pasta de trabalho. Use isso se múltiplas pastas de trabalho devem compartilhar uma chave, ou se você não quer a chave no arquivo.
Passo 5: adicione um botão na planilha
É isso que transforma a coisa numa experiência de um clique para usuários não técnicos.
Inserir → Formas → Retângulo, jogue um na planilha, rotule “Sync to Brevo.” Clique direito na forma → Atribuir Macro → escolha SyncSheetToBrevo. Pronto.
Ou, para uma UI mais polida, adicione uma aba personalizada da faixa via Office Custom UI Editor, mas para a maioria das ferramentas internas, a forma como botão é mais que suficiente.
Passo 6: rode
Clique no botão. A macro lê as linhas, divide em lotes, posta cada lote para a Brevo e mostra uma caixa de mensagem com resumo. A importação da Brevo é assíncrona, então a mensagem de sucesso significa “Brevo aceitou o lote”, a criação real do contato acontece no servidor nos próximos segundos. Você recebe um email de resumo da Brevo quando termina (a não ser que você coloque disableNotification: true).
Pegadinhas comuns
O botão não faz nada e não tem erro. Macros estão desabilitadas. Olhe a barra amarela de segurança no topo da planilha, clique em Habilitar Conteúdo. Se sua organização bloqueia macros, veja o caminho de central de confiança / assinatura de código abaixo.
Compile error: User-defined type not defined. Você está no Excel para Mac, que não tem MSXML2.XMLHTTP. O VBA do Mac não consegue fazer requisições HTTPS direto, use o caminho do Office Scripts abaixo no lugar.
400 Bad Request da Brevo sem causa óbvia. Quase sempre é uma de duas coisas: (a) um atributo personalizado na sua planilha ainda não existe na Brevo, crie ele primeiro; (b) bug de escape de JSON, aspas ou contrabarras em valores de células que não foram escapados. A função EscapeJson do código cuida dos casos padrão; se seus dados têm caracteres estranhos, logue payload na janela Imediato (Debug.Print payload) e inspecione.
401 Unauthorized. Header errado. É api-key (minúsculo, com hífen), não Authorization. A macro usa o certo, mas se você copiou um trecho de outro lugar, confira de novo.
Excel trava em importações grandes. A macro roda síncrona na thread da UI. Para 50.000+ linhas, você vai ver o Excel travar por 10 a 30 segundos enquanto monta o JSON e espera a Brevo. Aceite isso, ou troque o MSXML2.XMLHTTP para a variante assíncrona, mas nessa escala você está melhor no Power Automate (próxima seção).
Quando o VBA não basta: Office Scripts + Power Automate
VBA não consegue fazer sincronização agendada na nuvem. Se você precisa de:
- A pasta de trabalho sincronizando com a Brevo toda hora sem ninguém abrir
- A pasta de trabalho no OneDrive/SharePoint, editada da web
- Um departamento de TI que proíbe macros desktop
…então você quer Office Scripts (o equivalente em nuvem da Microsoft para o Apps Script) mais Power Automate (a camada de agendamento e HTTP deles).
A divisão: o Office Scripts lê a planilha e devolve os dados de contato. O Power Automate pega esses dados e faz POST na Brevo num trigger.
O Office Script (Excel para web → Automatizar → Novo 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;}O fluxo do Power Automate:
- Trigger: Recorrência (a cada 1 hora), ou botão manual, ou “Quando uma linha é modificada” se você quer sincronização orientada por mudança.
- Ação: Excel Online → Executar script, aponte para sua pasta de trabalho e o script acima. Salve o valor de retorno como
contacts. - Ação: HTTP (este é o conector Premium, veja a nota de licenciamento abaixo).
- Método:
POST - URI:
https://api.brevo.com/v3/contacts/import - Headers:
api-key: xkeysib-...,Content-Type: application/json - Corpo:
{"jsonBody": @{outputs('Run_script')?['body/result']},"listIds": [42],"updateExistingContacts": true}
- Método:
- Ação: Condição → se o código de status não for 202, mande um alerta no Teams/email.
Checagem de realidade do licenciamento: a ação HTTP é um conector Premium do Power Automate. Em planos Microsoft 365 Business Basic/Standard você ganha os conectores padrão mas não os Premium. A saída mais barata é o complemento Power Automate Premium (aproximadamente US$ 15/usuário/mês na hora que escrevemos), ou mover o HTTP para uma pequena Azure Function que o fluxo padrão pode chamar. Se você já está em E3/E5 com Premium incluso, está pronto.
Esse é o motivo principal pelo qual a história do Apps Script é mais limpa: o UrlFetchApp do Apps Script é grátis e sem restrições, enquanto o equivalente da Microsoft coloca a chamada de rede atrás de uma camada paga de conector.
VBA vs Office Scripts vs Apps Script: quando escolher o quê
| Necessidade | Melhor opção |
|---|---|
| Botão de um clique numa pasta de trabalho que seu time já abre todo dia | macro VBA (este guia, metade de cima) |
| Pasta de trabalho no OneDrive/SharePoint, sincronização automática a cada hora | Office Scripts + Power Automate (precisa de Premium para HTTP) |
| Só Excel para Mac, não dá para usar VBA | Office Scripts + Power Automate |
| Os dados vivem no Google Sheets, não no Excel | Apps Script (grátis, triggers agendados embutidos) |
| Importação única, nunca vai precisar de novo | Salvar como → CSV e usar o script de importação CSV |
| Importação em massa de arquivo > 10 MB | CSV com fileUrl, veja o guia CSV |
Por que isto bate Zapier / plataformas no-code
Para um trabalho recorrente de Excel para Brevo, ferramentas de automação de terceiros (Zapier, Make, n8n) cobram por tarefa e colocam um terceiro entre seus dados e a Brevo. A abordagem VBA tem zero custo recorrente, zero fluxo de dados de terceiros, e vive dentro do arquivo, quando a pasta de trabalho se mexe, a integração se mexe junto. Office Scripts + Power Automate é parecido mas com a Microsoft como terceiro (já no seu stack se você está em M365).
A graça inteira do endpoint POST /v3/contacts/import da Brevo é que você não precisa de uma plataforma cola, suas ferramentas já sabem fazer requisições HTTP.