---
title: "用 Apps Script 将 Google Sheets 联系人导入 Brevo"
description: "可重复运行的 Apps Script 示例：检查同意记录、映射字段、保留退订状态并显示 API 错误。"
url: https://tajo.io/zh-cn/blog/import-google-sheet-contacts-to-brevo-apps-script/
markdown: https://tajo.io/zh-cn/blog/import-google-sheet-contacts-to-brevo-apps-script.md
lang: zh-CN
author: "Set Noa"
author_url: https://tajo.io/zh-cn/set-noa/
published: 2026-04-30
updated: 2026-10-09
alternates: {en-US: /blog/import-google-sheet-contacts-to-brevo-apps-script.md, bg-BG: /bg/blog/import-google-sheet-contacts-to-brevo-apps-script.md, cs-CZ: /cz/blog/import-google-sheet-contacts-to-brevo-apps-script.md, de-DE: /de/blog/import-google-sheet-contacts-to-brevo-apps-script.md, da-DK: /dk/blog/import-google-sheet-contacts-to-brevo-apps-script.md, es-ES: /es/blog/import-google-sheet-contacts-to-brevo-apps-script.md, fr-FR: /fr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, el-GR: /gr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, hi-IN: /hi/blog/import-google-sheet-contacts-to-brevo-apps-script.md, id-ID: /in/blog/import-google-sheet-contacts-to-brevo-apps-script.md, hr-HR: /hr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, hu-HU: /hu/blog/import-google-sheet-contacts-to-brevo-apps-script.md, it-IT: /it/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ja-JP: /jp/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ko-KR: /kr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ar-SA: /ar/blog/import-google-sheet-contacts-to-brevo-apps-script.md, nl-NL: /nl/blog/import-google-sheet-contacts-to-brevo-apps-script.md, no-NO: /no/blog/import-google-sheet-contacts-to-brevo-apps-script.md, pl-PL: /pl/blog/import-google-sheet-contacts-to-brevo-apps-script.md, pt-BR: /pt/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ro-RO: /ro/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ru-RU: /ru/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sv-SE: /se/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sl-SI: /sl/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sr-Latn-RS: /sr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, th-TH: /th/blog/import-google-sheet-contacts-to-brevo-apps-script.md, tr-TR: /tr/blog/import-google-sheet-contacts-to-brevo-apps-script.md, ur-PK: /ur/blog/import-google-sheet-contacts-to-brevo-apps-script.md, vi-VN: /vi/blog/import-google-sheet-contacts-to-brevo-apps-script.md, sk-SK: /sk/blog/import-google-sheet-contacts-to-brevo-apps-script.md}
---

[数据同步](https://tajo.io/zh-cn/blog/?category=data-sync)

# 用 Apps Script 将 Google Sheets 联系人导入 Brevo

可重复运行的 Apps Script 示例：检查同意记录、映射字段、保留退订状态并显示 API 错误。

google apps script brevo

如何把 Sheets 联系人导入 Brevo？

在表格中创建 email、firstName、lastName、consent 列。将 BREVO\_API\_KEY 放入 Script Properties，在代码中设置列表 ID，再运行 syncSheetToBrevo。脚本只处理已同意的行，检查 Brevo 的退订状态、去重，并在 API 错误时停止。这是需要自行维护的 Apps Script，不是内置连接器。

[了解更多](https://tajo.io/zh-cn/blog/import-google-sheet-contacts-to-brevo-apps-script/#%E5%87%86%E5%A4%87%E8%A1%A8%E6%A0%BC%E5%92%8C%E5%88%97%E8%A1%A8)

| 来源字段 | 目标字段 | 示例值 |
| --- | --- | --- |
| `email` | `email` | `alex@example.com` |
| `firstName` | `FNAME` | `Alex` |
| `lastName` | `LNAME` | `Example` |

一次导出十二条活动报名记录很简单。第二次导入时，可能出现重复邮箱，也可能有人已在 Brevo 退订。可重复运行的导入必须处理这两种情况。

脚本使用 [Brevo 联系人的读取、创建和更新端点](https://developers.brevo.com/reference/create-contact)。它面向小规模定时导入，不是批量加载器或 Google Sheets 内置连接器，也不会发送邮件。同意证据和脚本运行由你负责。

## 准备表格和列表

创建 `Contacts` 工作表，列标题必须如下。`consent` 使用复选框，只有获得对应营销用途的许可时才设为 `TRUE`。

| email | firstName | lastName | consent |
| --- | --- | --- | --- |
| [jane@example.com](mailto:jane@example.com) | Jane | Doe | TRUE |
| [alex@example.com](mailto:alex@example.com) | Alex | Lee | FALSE |

创建或选择 Brevo 列表，将其数字 ID 写入 `LIST_ID`。确认 Brevo 中已存在 `FNAME` 和 `LNAME` 属性；示例只映射这两个字段。如果表格无法证明何时及如何获得同意，请另行保存来源记录。单个 `TRUE` 单元格不是证据。

在 **Extensions → Apps Script → Project Settings → Script Properties** 中添加 `BREVO_API_KEY`。脚本属性对项目用户共享，应限制编辑权限。不要把密钥放在单元格或源码中。参见 [Google 的属性访问规则](https://developers.google.com/apps-script/guides/properties)。

## 脚本

用下例替换 `Code.gs`，首次运行前设置 `LIST_ID`。

```javascript
const LIST_ID = 42; // Replace with your existing Brevo list ID.
const TAB = 'Contacts';
const BASE = 'https://api.brevo.com/v3';

function syncSheetToBrevo() {
  const key = PropertiesService.getScriptProperties().getProperty('BREVO_API_KEY');
  if (!key) throw new Error('Set BREVO_API_KEY in Script Properties first');
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TAB);
  if (!sheet) throw new Error('Contacts tab missing');
  const values = sheet.getDataRange().getValues();
  const headers = values.shift().map(h => String(h).trim());
  const columns = ['email', 'firstName', 'lastName', 'consent']
    .map(name => headers.indexOf(name));
  if (columns.includes(-1)) throw new Error('Required header missing');
  const [emailCol, firstCol, lastCol, consentCol] = columns;
  const seen = new Set();
  const result = { written: 0, skipped: 0 };

  for (const row of values) {
    const email = String(row[emailCol] || '').trim().toLowerCase();
    if (row[consentCol] !== true || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || seen.has(email)) {
      result.skipped++;
      continue;
    }
    seen.add(email);
    const path = '/contacts/' + encodeURIComponent(email);
    const current = brevo_(key, path, 'get');
    if (current.code !== 200 && current.code !== 404) {
      throw new Error(`Contact read failed (${current.code}) for row ${result.written + result.skipped + 2}`);
    }
    if (current.code === 200) {
      const contact = JSON.parse(current.text);
      if (contact.emailBlacklisted || (contact.listUnsubscribed || []).includes(LIST_ID)) {
        result.skipped++;
        continue;
      }
    }
    const attributes = {};
    if (row[firstCol] !== '') attributes.FNAME = String(row[firstCol]);
    if (row[lastCol] !== '') attributes.LNAME = String(row[lastCol]);
    const body = { attributes, listIds: [LIST_ID] };
    const saved = current.code === 404
      ? brevo_(key, '/contacts', 'post', { email, ...body })
      : brevo_(key, path, 'put', body);
    if (![201, 204].includes(saved.code)) {
      throw new Error(`Contact write failed (${saved.code}) for ${email}: ${saved.text.slice(0, 200)}`);
    }
    result.written++;
  }
  Logger.log(JSON.stringify(result));
  return result;
}

function brevo_(key, path, method, body) {
  for (let attempt = 0; attempt < 3; attempt++) {
    const response = UrlFetchApp.fetch(BASE + path, {
      method,
      contentType: 'application/json',
      headers: { 'api-key': key },
      payload: body ? JSON.stringify(body) : undefined,
      muteHttpExceptions: true,
    });
    const code = response.getResponseCode();
    if (code !== 429) return { code, text: response.getContentText() };
    if (attempt === 2) return { code, text: response.getContentText() };
    const reset = Object.entries(response.getHeaders()).find(
      ([name]) => name.toLowerCase() === 'x-sib-ratelimit-reset'
    );
    const raw = Number(reset && reset[1]);
    const seconds = Number.isFinite(raw) && raw > 0 ? raw : 2 ** attempt;
    const waitSeconds = seconds + 2 ** attempt;
    if (waitSeconds > 60) return { code, text: response.getContentText() };
    Utilities.sleep(waitSeconds * 1000);
  }
}
```

保存，选择 `syncSheetToBrevo`，点击 **Run**。Google 会请求 Sheets 和外部请求权限。在 **Executions** 查看 `{written, skipped}` 日志。读取返回 404 会创建联系人，返回 200 会更新；其他错误会停止。联系人写入成功不代表营销邮件已发送。

脚本在一次运行中去除重复邮箱，下次运行还会重新查询 Brevo。它不会把 `emailBlacklisted` 设为 `false`，也不会修改邮箱。如果 Brevo 报告全局屏蔽或已退出目标列表，即使表格仍是 `TRUE`，该行也会跳过。不要用它撤销退订。[Brevo 提醒](https://developers.brevo.com/reference/update-contact)，修改被屏蔽联系人的邮箱可能解除屏蔽。

## 定时运行前检查一次

使用你控制的测试列表和联系人。一行 `TRUE`、一行 `FALSE` 加一个重复邮箱，应得到一次写入和两次跳过。让测试联系人在 Brevo 退订后重跑，该联系人不应再写入。测试错误时暂时设置无效的 `LIST_ID`，在 **Executions** 确认 HTTP 错误，再恢复 ID 并重试。不要用真实客户数据测试。本文代码已用模拟 Brevo 响应在本地验证，没有真实写入。

在 **Apps Script → Triggers → Add Trigger** 中选择 `syncSheetToBrevo` 和时间间隔。[触发器以创建者账户运行](https://developers.google.com/apps-script/guides/triggers/installable)，该账户须持续有表格权限。小表格可从每天一次开始，持续查看失败记录。Google [限制运行时间和 URL Fetch 使用量](https://developers.google.com/apps-script/guides/services/quotas)；大型数据源应拆成有界任务。

遇到 429，脚本读取 `x-sib-ratelimit-reset`，最多再试两次。如果需要等待超过 60 秒，就返回 429，留待下次运行，而不会提前重试。其他错误也会停止，下次运行从头开始。联系人可能在读取与写入之间退订；只有能接受这段短暂竞态时才适用。更严格的保护需要事件核对、可靠的同意记录，以及发送前的最后检查。

大表格可使用 [Brevo 异步导入端点](https://developers.brevo.com/reference/import-contacts)，它返回 `processId`，表示任务已接收，而不是已完成。报告成功前应检查结果。本文逐联系人处理可以定位失败的行。

## 常见问题

**需要原生 Google Sheets 连接器吗？**

不需要。示例在绑定表格的 Apps Script 项目中运行，并调用 Brevo 联系人 API。脚本、API 密钥和定时触发器都由你维护。

**哪些行会发送给 Brevo？**

只有 consent 为 TRUE 且邮箱有效的行。每次运行都会去重，写入前还会查询 Brevo。

**重复运行会重新订阅已退订者吗？**

不会。脚本跳过 Brevo 标记为 emailBlacklisted 或已退出目标列表的联系人，不会发送 emailBlacklisted: false，也不会改邮箱。上线前还应检查其他同意与屏蔽来源。

**运行失败后如何重试？**

查看 Apps Script 执行错误，修复原因后重跑同一函数。写入使用相同邮箱和列表 ID，已成功的行不会创建第二个联系人。

## 相关文章

### [如何使用脚本（Python、Node.js、cURL）将 CSV 或 Excel 联系人导入 Brevo](https://tajo.io/zh-cn/blog/import-csv-contacts-to-brevo-with-a-script/)

2026年4月30日 · 4 分钟阅读

CSV → Brevo

### [如何用 VBA 宏将 Excel 联系人推送到 Brevo（以及 Office Scripts 替代方案）](https://tajo.io/zh-cn/blog/import-excel-contacts-to-brevo-with-vba-macro/)

2026年4月30日 · 5 分钟阅读

Microsoft Excel → Brevo

### [Brevo 集成：选择能够验证的连接方式](https://tajo.io/zh-cn/blog/brevo-connector-guide/)

2026年8月19日 · 4 分钟阅读

6 个章节
