VBA 매크로로 Excel 연락처를 Brevo로 푸시하는 방법 (그리고 Office Scripts 대안)

한 번의 클릭으로 Excel 시트의 연락처를 Brevo의 API로 게시하는 작동하는 VBA 매크로, 그리고 언제 대신 Office Scripts와 Power Automate를 사용해야 하는지, Google Apps Script 설정 대비 트레이드오프를 다룹니다.

Featured image for article: VBA 매크로로 Excel 연락처를 Brevo로 푸시하는 방법 (그리고 Office Scripts 대안)

Excel에 연락처가 있고 Brevo로 가져오고 싶습니다. 빠르고 간단한 답변은 파일을 .csv로 저장하고 가져오는 것이며, 한 번이라면 괜찮습니다. 반복적으로 하는 작업의 경우(주간 영업 인계, 팀이 매일 업데이트하는 워크북, 새로 고쳐지는 파트너 리스트) Excel 내부에서 동기화를 수행하는 버튼이 필요합니다.

이 가이드는 그것에 실제로 의미가 있는 두 가지 경로를 다룹니다.

  1. 워크북에 내장된 VBA 매크로: 라이선스 없음, 클라우드 없음, 오프라인에서 작동, 사용자가 버튼을 클릭하는 순간 실행. “Excel-to-Brevo” 사례의 약 80%에 대한 정답입니다.
  2. Office Scripts와 Power Automate: VBA 대신 TypeScript, 클라우드에서 실행, 스케줄 트리거 지원. 워크북이 OneDrive/SharePoint에 있고 무인 동기화를 원할 때 정답이지만, Power Automate 라이선스에 주의하세요.

Google Sheets에 해당하는 것을 찾고 있다면 Apps Script에 관한 동반 글을 보세요. 그리고 노트북에서 스크립트로 일회성 CSV 가져오기만 원한다면, CSV 가져오기 가이드에 Python, Node.js, cURL 버전이 있습니다.

매크로가 하는 일

사용자가 시트의 “Sync to Brevo” 버튼을 클릭할 때.

  1. 활성 워크시트의 모든 행을 읽습니다(헤더 행이 먼저, 행당 연락처 하나).
  2. Brevo의 jsonBody 매개변수에 맞춰진 JSON 배열을 만듭니다.
  3. 워크북에 저장된 API 키와 함께 https://api.brevo.com/v3/contacts/import로 POST합니다.
  4. 결과와 함께 메시지 박스를 표시합니다.

그게 전부입니다. 약 120줄의 VBA. 아래는 완전한 작동 모듈입니다.

매크로가 기대하는 시트 레이아웃

emailfirstNamelastNamecompanycity
[email protected]JaneDoeAcmeBerlin
[email protected]JohnSmithGlobexParis

email은 필수입니다. 다른 모든 열은 Brevo 연락처 속성이 되며, 열 헤더(대문자화됨)에서 속성 이름으로 매핑됩니다. 따라서 firstNameFIRSTNAME, companyCOMPANY. 사용자 정의 속성(표준 세트 외의 모든 것)은 Brevo 계정에 먼저 존재해야 합니다. Contacts → Settings → Contact attributes 에서 정의하세요.

1단계: VBA 편집기 열기

Excel에서 Alt + F11을 누릅니다. VBA 편집기가 열립니다. 왼쪽의 Project 창에서 워크북을 마우스 오른쪽 버튼으로 클릭하고 Insert → Module 을 선택합니다. 빈 Module1이 나타납니다.

2단계: 전체 매크로 붙여넣기

Module1의 내용을 다음으로 교체합니다.

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

3단계: 워크북을 .xlsm으로 저장

VBA 매크로는 매크로 사용 워크북에서만 유지됩니다. Save As → Excel Macro-Enabled Workbook (.xlsm) 을 선택합니다. 일반 .xlsx 형식은 매크로를 자동으로 제거합니다. 많은 사람들이 처음 이렇게 코드를 잃습니다.

4단계: API 키 구성

ConfigureApiKey를 한 번 실행합니다. 다음 중 하나를 선택하세요.

  • VBA 편집기에서 ConfigureApiKey 서브 내부의 아무 곳이나 클릭하고 F5를 누르거나,
  • Excel에서 Developer → Macros, ConfigureApiKey 선택, Run.

xkeysib-... 키를 붙여넣습니다. 매크로는 그것을 워크북 내부의 사용자 정의 문서 속성으로 저장합니다. 소스 코드에 없고, 레지스트리에 없고, 파일과 함께 이동합니다(따라서 주의: .xlsm을 누군가에게 이메일로 보내면 API 키가 함께 갑니다).

워크북 외부에 키를 두고 싶다면, 저장소를 Windows 레지스트리로 바꾸세요.

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

SaveSetting/GetSettingHKCU\Software\VB and VBA Program Settings\Brevo\Sync 아래에 사용자별로 저장합니다(워크북별 아님). 여러 워크북이 하나의 키를 공유해야 하거나, 키를 파일에 두고 싶지 않은 경우 이것을 사용하세요.

5단계: 시트에 버튼 추가

이것이 비기술 사용자에게 원클릭 경험으로 바뀌게 만드는 부분입니다.

Insert → Shapes → Rectangle, 시트에 하나 떨어뜨리고, “Sync to Brevo” 라벨을 붙입니다. 도형을 마우스 오른쪽 버튼으로 클릭 → Assign MacroSyncSheetToBrevo 선택. 완료.

또는 더 세련된 UI를 위해 Office Custom UI Editor를 통해 사용자 정의 리본 탭을 추가할 수 있지만, 대부분의 내부 도구의 경우 도형-버튼 방식으로 충분합니다.

6단계: 실행

버튼을 클릭합니다. 매크로가 행을 읽고, 일괄 처리하고, 각 배치를 Brevo에 게시하고, 요약 메시지 박스를 표시합니다. Brevo의 가져오기는 비동기적이므로 성공 메시지는 “Brevo가 배치를 수락했다”는 의미입니다. 실제 연락처 생성은 다음 몇 초 동안 서버 측에서 발생합니다. 완료되면 Brevo로부터 이메일 요약을 받습니다(disableNotification: true로 설정하지 않은 경우).

일반적인 함정

버튼이 아무것도 하지 않고 오류가 없습니다. 매크로가 비활성화되어 있습니다. 시트 상단의 노란색 보안 막대를 보고 Enable Content 를 클릭합니다. 조직이 매크로를 차단하는 경우, 아래의 신뢰 센터/코드 서명 경로를 보세요.

Compile error: User-defined type not defined. Mac Excel을 사용 중이며, MSXML2.XMLHTTP가 없습니다. Mac VBA는 HTTPS 요청을 직접 보낼 수 없습니다. 대신 아래의 Office Scripts 경로를 사용하세요.

명백한 원인 없이 Brevo로부터 400 Bad Request. 거의 항상 다음 중 하나입니다. (a) 시트의 사용자 정의 속성이 아직 Brevo에 존재하지 않음(먼저 만드세요); (b) JSON 이스케이프 버그(셀 값의 따옴표나 백슬래시가 이스케이프되지 않음). 코드의 EscapeJson 함수가 표준 케이스를 처리합니다. 데이터에 이상한 문자가 있다면, payload를 즉시 창에 로깅(Debug.Print payload)하고 검사하세요.

401 Unauthorized. 잘못된 헤더. Authorization이 아니라 api-key(소문자, 하이픈)입니다. 매크로는 올바른 것을 사용하지만, 다른 곳에서 스니펫을 복사한 경우 다시 확인하세요.

Excel이 큰 가져오기에서 멈춥니다. 매크로는 UI 스레드에서 동기적으로 실행됩니다. 50,000+ 행의 경우 JSON을 빌드하고 Brevo를 기다리는 동안 Excel이 10-30초 동안 멈추는 것을 보게 됩니다. 그것을 받아들이거나 MSXML2.XMLHTTP를 비동기 변형으로 전환하세요. 하지만 그 규모에서는 Power Automate(다음 섹션)에서 더 잘 됩니다.

VBA로 충분하지 않을 때: Office Scripts와 Power Automate

VBA는 스케줄된 클라우드 동기화를 할 수 없습니다. 다음이 필요한 경우.

  • 누군가가 열지 않고도 매시간 Brevo에 동기화되는 워크북
  • OneDrive/SharePoint에 있고 웹에서 편집되는 워크북
  • 데스크톱 매크로를 금지하는 IT 부서

…그렇다면 Office Scripts (Apps Script의 Microsoft 클라우드 동등 솔루션)와 Power Automate (그들의 스케줄링 및 HTTP 계층)를 원합니다.

분할: Office Scripts가 시트를 읽고 연락처 데이터를 반환합니다. Power Automate가 그 데이터를 받아 트리거에서 Brevo에 POST합니다.

Office Script (웹용 Excel → 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 플로우:

  1. 트리거: Recurrence (1시간마다), 또는 수동 버튼, 또는 변경 기반 동기화를 원한다면 “When a row is modified”.
  2. 액션: Excel Online → Run script, 워크북과 위 스크립트를 가리키게 합니다. 반환 값을 contacts로 저장합니다.
  3. 액션: HTTP (이것은 프리미엄 커넥터입니다, 아래 라이선스 노트 참조).
    • 메서드: POST
    • URI: https://api.brevo.com/v3/contacts/import
    • 헤더: api-key: xkeysib-..., Content-Type: application/json
    • 본문:
      {
      "jsonBody": @{outputs('Run_script')?['body/result']},
      "listIds": [42],
      "updateExistingContacts": true
      }
  4. 액션: Condition → 상태 코드가 202가 아니면 Teams/이메일 알림을 보냅니다.

라이선스 현실 확인: HTTP 액션은 Power Automate Premium 커넥터입니다. Microsoft 365 Business Basic/Standard 플랜에서는 표준 커넥터를 받지만 프리미엄은 받지 않습니다. 가장 저렴한 우회 방법은 Power Automate Premium 추가 기능(작성 시점 기준 사용자당 월 약 $15) 또는 표준 플로우가 호출할 수 있는 작은 Azure Function으로 HTTP를 옮기는 것입니다. 이미 프리미엄이 포함된 E3/E5에 있다면 준비된 것입니다.

이것이 Apps Script 스토리가 더 깔끔한 주요 이유입니다. Apps Script의 UrlFetchApp은 무료이고 제한이 없는 반면, Microsoft 동등 솔루션은 네트워크 호출을 유료 커넥터 계층 뒤에 둡니다.

VBA vs Office Scripts vs Apps Script: 언제 어떤 것을 선택할까

필요최선의 옵션
팀이 이미 매일 여는 워크북의 원클릭 버튼VBA 매크로 (이 가이드, 상단 절반)
OneDrive/SharePoint의 워크북, 시간별 자동 동기화Office Scripts와 Power Automate (HTTP를 위해 프리미엄 필요)
Mac Excel만, VBA를 사용할 수 없음Office Scripts와 Power Automate
데이터가 Excel이 아닌 Google Sheets에 있음Apps Script (무료, 스케줄 트리거 내장)
일회성 가져오기, 다시 필요하지 않음Save As → CSV 그리고 CSV 가져오기 스크립트 사용
10MB 이상 파일에서 일괄 가져오기fileUrl이 있는 CSV, CSV 가이드 참조

이것이 Zapier / 노코드 플랫폼을 이기는 이유

반복적인 Excel-to-Brevo 작업의 경우, 서드파티 자동화 도구(Zapier, Make, n8n)는 작업당 요금을 부과하고 데이터와 Brevo 사이에 제3자를 둡니다. VBA 접근 방식은 진행 비용이 없고, 서드파티 데이터 흐름이 없으며, 파일 내부에 살아 있습니다. 워크북이 이동하면 통합도 함께 이동합니다. Office Scripts와 Power Automate는 비슷하지만 Microsoft가 제3자입니다(M365에 있다면 이미 스택에 있음).

Brevo POST /v3/contacts/import 엔드포인트의 핵심은 글루 플랫폼이 필요 없다는 것입니다. 도구가 이미 HTTP 요청을 보내는 방법을 알고 있습니다.

더 읽기

Frequently Asked Questions

VBA 매크로가 정말로 Excel 내부에서 Brevo의 API를 호출할 수 있습니까?
네. VBA는 모든 최신 Windows 설치에 포함되어 있는 MSXML2.XMLHTTP를 통해 HTTP 요청을 보낼 수 있습니다. 매크로는 Python이나 Node 스크립트가 호출하는 것과 같은 엔드포인트인 api.brevo.com/v3/contacts/import에 JSON을 POST합니다. Mac Excel은 Office Scripts와 Power Automate를 통해 가능하지만, 데스크톱 Mac VBA는 불가능합니다(MSXML 없음).
Apps Script의 시간 트리거처럼 스케줄로 실행할 수 있습니까?
VBA만으로는 안 됩니다. Application.OnTime이 발동하려면 Excel이 열려 있어야 합니다. 무인 스케줄 동기화의 경우 두 가지 옵션이 있습니다. (1) 워크북을 열고 매크로를 실행하는 Windows 작업 스케줄러, 또는 (2) Power Automate 스케줄 플로우에 의해 트리거되는 Office Scripts (이 가이드 뒷부분에서 다룸).
VBA는 안전합니까? 회사가 매크로를 차단합니다.
VBA 매크로는 파일 시스템과 레지스트리 접근 권한을 가지고 실행되므로, 기본적으로 차단하는 것은 합리적인 정책입니다. 두 가지 우회 방법이 있습니다. (1) 코드 서명 인증서로 매크로에 서명하고 워크북을 신뢰할 수 있는 위치에 배치하거나, (2) VBA를 완전히 건너뛰고 Office Scripts(TypeScript, 샌드박스, 파일 시스템 접근 없음)를 사용하세요. Office Scripts가 Microsoft가 권장하는 현대적 경로입니다.
Google Apps Script 접근 방식과 비교하면 어떻습니까?
Apps Script는 설정하고 잊는 방식에 더 가깝습니다. Google 클라우드에서 실행되고, 스케줄 트리거가 내장되어 있으며, Excel/Power Automate 라이선스가 필요 없습니다. VBA는 오프라인 작업과 팀이 이미 열어둔 워크북에서의 원클릭 수동 동기화에서 이깁니다. Office Scripts와 Power Automate는 Microsoft 측의 클라우드/스케줄 동등 솔루션이지만, Power Automate는 종종 외부 HTTP를 위해 유료 프리미엄 커넥터가 필요합니다.
Brevo로 무료로 시작하기