---
title: "นำเข้าผู้ติดต่อ Google Sheets ไป Brevo ด้วย Apps Script"
description: "ตัวอย่าง Apps Script ที่เรียกซ้ำได้ ตรวจความยินยอม จับคู่ฟิลด์ รักษาการยกเลิกรับข่าวสาร และแสดงข้อผิดพลาด API"
url: https://tajo.io/th/blog/import-google-sheet-contacts-to-brevo-apps-script/
markdown: https://tajo.io/th/blog/import-google-sheet-contacts-to-brevo-apps-script.md
lang: th-TH
author: "Set Noa"
author_url: https://tajo.io/th/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, zh-CN: /zh-cn/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, 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/th/blog/?category=data-sync)

# นำเข้าผู้ติดต่อ Google Sheets ไป Brevo ด้วย Apps Script

ตัวอย่าง Apps Script ที่เรียกซ้ำได้ ตรวจความยินยอม จับคู่ฟิลด์ รักษาการยกเลิกรับข่าวสาร และแสดงข้อผิดพลาด API

google apps script brevo

นำรายชื่อจาก Sheets เข้า Brevo อย่างไร?

สร้างคอลัมน์ email, firstName, lastName และ consent ใน Sheet เก็บ BREVO\_API\_KEY ใน Script Properties ตั้ง ID รายการในโค้ด แล้วเรียก syncSheetToBrevo สคริปต์พิจารณาเฉพาะแถวที่ยินยอม ตรวจสถานะยกเลิกรับข่าวสารใน Brevo ลบอีเมลซ้ำ และหยุดเมื่อ API ผิดพลาด นี่คือ Apps Script ที่คุณดูแลเอง ไม่ใช่คอนเนกเตอร์ในตัว

[เรียนรู้เพิ่มเติม](https://tajo.io/th/blog/import-google-sheet-contacts-to-brevo-apps-script/#%E0%B9%80%E0%B8%95%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%A1-sheet-%E0%B9%81%E0%B8%A5%E0%B8%B0%E0%B8%A3%E0%B8%B2%E0%B8%A2%E0%B8%81%E0%B8%B2%E0%B8%A3)

| ฟิลด์ต้นทาง | ฟิลด์ปลายทาง | ค่าตัวอย่าง |
| --- | --- | --- |
| `email` | `email` | `alex@example.com` |
| `firstName` | `FNAME` | `Alex` |
| `lastName` | `LNAME` | `Example` |

การส่งออกรายชื่อผู้ลงทะเบียนงานสิบสองคนครั้งเดียวทำได้ง่าย แต่ครั้งที่สองอาจมีอีเมลซ้ำและมีคนยกเลิกรับข่าวสารใน Brevo การนำเข้าที่ทำซ้ำได้ต้องตรวจทั้งสองอย่าง

สคริปต์ใช้ [endpoint ของ Brevo สำหรับอ่าน สร้าง และอัปเดตผู้ติดต่อ](https://developers.brevo.com/reference/create-contact) เหมาะกับการนำเข้าขนาดเล็กตามเวลา ไม่ใช่เครื่องมือโหลดจำนวนมากหรือคอนเนกเตอร์ Google Sheets ในตัว ไม่ส่งอีเมล คุณต้องดูแลหลักฐานความยินยอมและการทำงานของสคริปต์

## เตรียม Sheet และรายการ

สร้างแท็บ `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` ตรวจว่ามีแอตทริบิวต์ `FNAME` และ `LNAME` ใน Brevo ตัวอย่างจับคู่แค่สองฟิลด์นี้ หาก Sheet ไม่พิสูจน์เวลาและวิธีที่ได้รับความยินยอม ให้เก็บบันทึกต้นทางแยกไว้ เซลล์ `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 และคำขอภายนอก ดู log `{written, skipped}` ใน **Executions** หากอ่านได้ 404 จะสร้างผู้ติดต่อ ส่วน 200 จะอัปเดต ข้อผิดพลาดอื่นหยุดงาน การเขียนผู้ติดต่อสำเร็จไม่ใช่การส่งแคมเปญ

สคริปต์ลบอีเมลซ้ำในครั้งเดียว และตรวจ Brevo ใหม่ในการเรียกครั้งถัดไป ไม่ตั้ง `emailBlacklisted` เป็น `false` และไม่เปลี่ยนที่อยู่ หาก Brevo แจ้งว่าบล็อกทั่วไปหรือยกเลิกจากรายการเป้าหมาย แถวจะถูกข้ามแม้ Sheet ยังเป็น `TRUE` อย่าใช้เพื่อยกเลิกการเลิกรับ [Brevo เตือน](https://developers.brevo.com/reference/update-contact) ว่าเปลี่ยนอีเมลของผู้ถูกบล็อกอาจปลดบล็อก

## ตรวจหนึ่งครั้งก่อนตั้งเวลา

ใช้รายการทดสอบและผู้ติดต่อที่คุณควบคุม เรียกด้วยแถว `TRUE` หนึ่งแถว `FALSE` หนึ่งแถว และอีเมลซ้ำ ควรเขียนหนึ่งและข้ามสอง ยกเลิกรับผู้ติดต่อทดสอบใน Brevo แล้วเรียกอีกครั้ง ต้องไม่มีการเขียนสำหรับคนนั้น หากต้องการทดสอบข้อผิดพลาด ให้ตั้ง `LIST_ID` ผิดชั่วคราว ดู HTTP error ใน **Executions** แล้วคืนค่าและลองใหม่ อย่าทดสอบกับข้อมูลลูกค้าจริง โค้ดนี้ผ่านการทดสอบในเครื่องด้วยการตอบกลับ Brevo จำลอง ไม่มีการเขียนจริง

เปิด **Apps Script → Triggers → Add Trigger** เลือก `syncSheetToBrevo` และช่วงเวลา [ทริกเกอร์ทำงานด้วยบัญชีของผู้สร้าง](https://developers.google.com/apps-script/guides/triggers/installable) ซึ่งต้องยังเข้าถึง Sheet ได้ เริ่มวันละครั้งสำหรับ Sheet เล็กและดูข้อผิดพลาด Google [จำกัดเวลารันและการใช้ URL Fetch](https://developers.google.com/apps-script/guides/services/quotas) แบ่งแหล่งใหญ่เป็นงานที่มีขอบเขต

เมื่อได้ 429 สคริปต์อ่าน `x-sib-ratelimit-reset` และลองใหม่ไม่เกินสองครั้ง ถ้าต้องรอเกิน 60 วินาที จะส่งคืน 429 ให้การเรียกครั้งหน้าแทนการลองก่อนเวลา ข้อผิดพลาดอื่นก็หยุด และครั้งถัดไปเริ่มจากต้น ผู้ติดต่ออาจยกเลิกรับระหว่างอ่านกับเขียน ใช้ตัวอย่างเมื่อยอมรับช่วงเวลาสั้นนี้ได้ หากต้องเข้มงวด ต้องกระทบยอดเหตุการณ์ มีแหล่งความยินยอมที่เชื่อถือได้ และตรวจครั้งสุดท้ายก่อนส่ง

Sheet ขนาดใหญ่ใช้ [การนำเข้าแบบอะซิงโครนัสของ Brevo](https://developers.brevo.com/reference/import-contacts) ซึ่งคืน `processId` นั่นหมายถึงรับงาน ไม่ใช่เสร็จงาน ตรวจผลก่อนแจ้งสำเร็จ วิธีเขียนทีละผู้ติดต่อในบทความนี้ช่วยระบุแถวที่ผิดพลาด

## คำถามที่พบบ่อย

**ต้องมีคอนเนกเตอร์ Google Sheets ในตัวหรือไม่?**

ไม่ต้อง ตัวอย่างทำงานในโครงการ Apps Script ที่ผูกกับ Sheet และเรียก API ผู้ติดต่อ Brevo คุณดูแลสคริปต์ คีย์ API และทริกเกอร์ตามเวลาเอง

**แถวใดถูกส่งไป Brevo?**

เฉพาะแถวที่ consent เป็น TRUE และอีเมลถูกต้อง สคริปต์ลบรายการซ้ำในแต่ละครั้งและตรวจ Brevo ก่อนเขียน

**เรียกซ้ำจะสมัครคนที่ยกเลิกรับแล้วอีกหรือไม่?**

สคริปต์ข้ามผู้ติดต่อที่ Brevo ระบุ emailBlacklisted หรือยกเลิกจากรายการเป้าหมาย ไม่ส่ง emailBlacklisted: false และไม่เปลี่ยนอีเมล ก่อนใช้งานจริงควรตรวจแหล่งความยินยอมและการบล็อกอื่นด้วย

**จะลองงานที่ล้มเหลวใหม่อย่างไร?**

อ่านข้อผิดพลาดใน Apps Script Executions แก้สาเหตุ แล้วเรียกฟังก์ชันเดิมอีกครั้ง การใช้ที่อยู่และ ID รายการเดิมทำให้แถวที่สำเร็จไม่สร้างผู้ติดต่อคนที่สอง

## บทความที่เกี่ยวข้อง

### [วิธีนำเข้ารายชื่อจาก CSV หรือ Excel ไปยัง Brevo ด้วยสคริปต์ (Python, Node.js, cURL)](https://tajo.io/th/blog/import-csv-contacts-to-brevo-with-a-script/)

30 เม.ย. 2569 · 3 นาทีอ่าน

CSV → Brevo

### [วิธีส่งรายชื่อจาก Excel ไปยัง Brevo ด้วย VBA Macro (และทางเลือก Office Scripts)](https://tajo.io/th/blog/import-excel-contacts-to-brevo-with-vba-macro/)

30 เม.ย. 2569 · 4 นาทีอ่าน

Microsoft Excel → Brevo

### [การผสาน Brevo: เลือกการเชื่อมต่อที่ตรวจสอบได้](https://tajo.io/th/blog/brevo-connector-guide/)

19 ส.ค. 2569 · 1 นาทีอ่าน

6 ส่วน
