VBAマクロでExcelの連絡先をBrevoにプッシュする方法(Office Scriptsという代替案も)
ExcelシートからBrevo APIへワンクリックで連絡先を投稿する動作する VBAマクロ。代わりにOffice Scripts + Power Automateを使うべき場合と、Google Apps Scriptセットアップとのトレードオフも解説します。
Excel に連絡先があり、それを Brevo に入れたい。手っ取り早い答えはファイルを .csv として保存してインポートすることで、1 回ならそれで構いません。繰り返し行うこと(週次のセールス引き継ぎ、チームが毎日更新するワークブック、定期的に更新されるパートナーリスト)には、Excel の中に同期を実行するボタンが欲しくなります。
このガイドでは、それに本当に意味のある 2 つのパスを取り上げます。
- ワークブックに埋め込まれた VBA マクロ。 ライセンスもクラウドもなく、オフラインで動作し、ユーザーがボタンをクリックした瞬間に実行されます。「Excel から Brevo」のケースの約 80 % にとっての正解です。
- Office Scripts + Power Automate。 VBA の代わりに TypeScript、クラウドで動作し、スケジュールトリガーをサポート。ワークブックが OneDrive/SharePoint にあり、無人同期を望む場合の正解ですが、Power Automate のライセンスに注意してください。
Google Sheets の同等品をお探しなら、Apps Script に関する関連記事を参照してください。ノート PC のスクリプトから一度きりの CSV インポートをしたいだけなら、CSV インポートガイドに Python、Node.js、cURL のバージョンがあります。
マクロが行うこと
ユーザーがシート上の「Sync to Brevo」ボタンをクリックしたとき。
- アクティブなワークシートのすべての行を読み取ります(最初にヘッダー行、1 行に 1 つの連絡先)。
- Brevo の
jsonBodyパラメータ用の JSON 配列を構築します。 - ワークブックに保存された API キーで
https://api.brevo.com/v3/contacts/importに POST します。 - 結果を表示するメッセージボックスを表示します。
それだけです。約 120 行の VBA。以下が完全な動作するモジュールです。
マクロが期待するシートレイアウト
| firstName | lastName | company | city | |
|---|---|---|---|---|
| [email protected] | Jane | Doe | Acme | Berlin |
| [email protected] | John | Smith | Globex | Paris |
email は必須です。それ以外のすべての列は Brevo の連絡先属性となり、列ヘッダー(大文字化)から属性名にマップされます。したがって firstName → FIRSTNAME、company → COMPANY です。カスタム属性(標準セット以外のもの)は、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 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ステップ 3: ワークブックを .xlsm として保存する
VBA マクロはマクロ有効ワークブックでのみ保持されます。Save As で Excel Macro-Enabled Workbook (.xlsm) を選択します。通常の .xlsx 形式はマクロを静かに削除します。多くの人が初めてこの方法でコードを失います。
ステップ 4: API キーを設定する
ConfigureApiKey を 1 回実行します。次のいずれか。
- 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/GetSetting は HKCU\Software\VB and VBA Program Settings\Brevo\Sync の下に書き込みます。ユーザーごとであり、ワークブックごとではありません。複数のワークブックで 1 つのキーを共有したい場合や、キーをファイルに含めたくない場合に使います。
ステップ 5: シートにボタンを追加する
これが、技術者でないユーザー向けのワンクリック体験に変える要素です。
Insert → Shapes → Rectangle、シートに 1 つドロップして「Sync to Brevo」とラベル付けします。図形を右クリック → Assign Macro → SyncSheetToBrevo を選択。完了です。
または、より洗練された UI を求めるなら、Office Custom UI Editor 経由でカスタムリボンタブを追加できますが、ほとんどの内部ツールでは図形をボタンとして使うので十分です。
ステップ 6: 実行する
ボタンをクリックします。マクロは行を読み取り、バッチ化し、各バッチを Brevo に POST し、サマリーメッセージボックスを表示します。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 を Immediate ウィンドウ(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 はスケジュールクラウド同期ができません。次のものが必要な場合。
- 誰も開かなくても 1 時間ごとに Brevo に同期するワークブック
- OneDrive/SharePoint にあり、Web から編集されるワークブック
- デスクトップマクロを禁止する IT 部門
…そんな場合は Office Scripts(Microsoft の Apps Script のクラウド相当品)と Power Automate(スケジューリングと HTTP のレイヤー)が欲しくなります。
分担: Office Scripts はシートを読み取り、連絡先データを返します。Power Automate はそのデータを受け取り、トリガー時に Brevo に POST します。
Office Script(Excel for the web → 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 フロー:
- Trigger: Recurrence(1 時間ごと)、または手動ボタン、または変更駆動型同期が欲しいなら “When a row is modified”。
- Action: Excel Online → Run script、ワークブックと上記スクリプトを指定します。返り値を
contactsとして保存。 - Action: HTTP(これは Premium コネクタです、以下のライセンスノートを参照)。
- Method:
POST - URI:
https://api.brevo.com/v3/contacts/import - Headers:
api-key: xkeysib-...、Content-Type: application/json - Body:
{"jsonBody": @{outputs('Run_script')?['body/result']},"listIds": [42],"updateExistingContacts": true}
- Method:
- Action: Condition → ステータスコードが 202 でなければ Teams/メールアラートを送信。
ライセンスの現実チェック: HTTP アクションは Power Automate Premium コネクタです。Microsoft 365 Business Basic/Standard プランでは、標準コネクタは得られますが Premium は得られません。最も安い回避策は Power Automate Premium アドオン(執筆時点で約 15 ドル/ユーザー/月)か、HTTP を標準フローから呼び出せる小さな Azure Function に移すことです。すでに E3/E5 に Premium が含まれているなら準備完了です。
これが Apps Script のストーリーがよりきれいである主な理由です。Apps Script の UrlFetchApp は無料で無制限ですが、Microsoft の同等品はネットワーク呼び出しを有料コネクタ層の背後に置きます。
VBA 対 Office Scripts 対 Apps Script: いつ何を選ぶか
| ニーズ | ベストオプション |
|---|---|
| チームが毎日すでに開いているワークブックでのワンクリックボタン | VBA マクロ(このガイド、上半分) |
| OneDrive/SharePoint のワークブック、毎時の自動同期 | Office Scripts + Power Automate(HTTP には Premium が必要) |
| Mac Excel のみ、VBA を使えない | Office Scripts + Power Automate |
| データが Excel ではなく Google Sheets にある | Apps Script(無料、スケジュールトリガー組み込み) |
| ワンショットインポート、二度と必要ない | Save As → CSV で CSV インポートスクリプトを使う |
| 10MB を超えるファイルからの一括インポート | fileUrl 付き CSV、CSV ガイドを参照 |
なぜこれが Zapier / ノーコードプラットフォームに勝るのか
繰り返しの Excel から Brevo へのジョブでは、サードパーティの自動化ツール(Zapier、Make、n8n)はタスクごとに課金し、データと Brevo の間にサードパーティを挟みます。VBA アプローチには継続的なコストがゼロで、サードパーティのデータフローがなく、ファイル内に住みます。ワークブックが移動すれば、統合も一緒に移動します。Office Scripts + Power Automate は Microsoft をサードパーティとして同様ですが(M365 を使っているならすでにスタックにあります)。
Brevo の POST /v3/contacts/import エンドポイントの全体的なポイントは、グルー プラットフォームが必要ないことです。あなたのツールはすでに HTTP リクエストの作り方を知っています。