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.

Featured image for article: Como empurrar contatos do Excel para a Brevo com uma macro VBA (e a alternativa Office Scripts)

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:

  1. 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”.
  2. 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:

  1. Lê toda linha da planilha ativa (linha de cabeçalho primeiro, um contato por linha).
  2. Monta um array JSON no formato do parâmetro jsonBody da Brevo.
  3. Faz POST em https://api.brevo.com/v3/contacts/import com a API key armazenada na pasta de trabalho.
  4. 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

emailfirstNamelastNamecompanycity
[email protected]JaneDoeAcmeBerlin
[email protected]JohnSmithGlobexParis

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 firstNameFIRSTNAME, companyCOMPANY. 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 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

Passo 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 ConfigureApiKey e aperte F5, 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:

  1. 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.
  2. Ação: Excel Online → Executar script, aponte para sua pasta de trabalho e o script acima. Salve o valor de retorno como contacts.
  3. 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
      }
  4. 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ê

NecessidadeMelhor opção
Botão de um clique numa pasta de trabalho que seu time já abre todo diamacro VBA (este guia, metade de cima)
Pasta de trabalho no OneDrive/SharePoint, sincronização automática a cada horaOffice Scripts + Power Automate (precisa de Premium para HTTP)
Só Excel para Mac, não dá para usar VBAOffice Scripts + Power Automate
Os dados vivem no Google Sheets, não no ExcelApps Script (grátis, triggers agendados embutidos)
Importação única, nunca vai precisar de novoSalvar como → CSV e usar o script de importação CSV
Importação em massa de arquivo > 10 MBCSV 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.

Leitura adicional

Frequently Asked Questions

Uma macro VBA consegue mesmo chamar a API da Brevo de dentro do Excel?
Sim. O VBA consegue fazer requisições HTTP através do MSXML2.XMLHTTP, que vem em qualquer instalação moderna do Windows. A macro faz POST de JSON em api.brevo.com/v3/contacts/import, o mesmo endpoint que um script Python ou Node bateria. O Excel para Mac também consegue via Office Scripts + Power Automate, mas o VBA do Mac no desktop não consegue (sem MSXML).
Posso rodar isso num agendamento como os triggers de tempo do Apps Script?
Só com VBA, não. O Excel precisa estar aberto para que Application.OnTime dispare. Para sincronização agendada sem assistência tem duas opções: (1) o Agendador de Tarefas do Windows que abre a pasta de trabalho e roda a macro, ou (2) Office Scripts disparado por um fluxo agendado do Power Automate (coberto mais adiante neste guia).
VBA é seguro? Minha empresa bloqueia macros.
Macros VBA rodam com acesso ao sistema de arquivos e ao registro, então bloquear por padrão é uma política sensata. Dois caminhos para contornar: (1) assinar a macro com um certificado de assinatura de código e colocar a pasta de trabalho num Local Confiável, ou (2) pular o VBA inteiro e usar Office Scripts (TypeScript, em sandbox, sem acesso ao sistema de arquivos). Office Scripts é o caminho moderno abençoado pela Microsoft.
Como isso se compara ao caminho do Google Apps Script?
Apps Script chega mais perto de configurar e esquecer, roda na nuvem do Google, triggers agendados embutidos, sem licença de Excel/Power Automate. VBA ganha para trabalho offline e sincronização manual de um clique a partir de uma pasta de trabalho que seu time já tem aberta. Office Scripts + Power Automate é o equivalente em nuvem agendado do lado da Microsoft, mas o Power Automate em geral precisa de um conector premium pago para HTTP de saída.
Comece grátis com Brevo