Hướng dẫn

Google Sheets + Zalo OA: Tự Động Gửi Tin Nhắn Hàng Loạt [Hướng Dẫn 2026]

Tuân HoangTuân Hoang
9 tháng 6, 2026
10 phút đọc
Ảnh minh họa bài viết: Google Sheets + Zalo OA: Tự Động Gửi Tin Nhắn Hàng Loạt [Hướng Dẫn 2026]

Tại Sao Zalo Là Kênh Tốt Nhất Để Gửi Thông Báo Tại Việt Nam?

Với hơn 75 triệu người dùng tại Việt Nam, Zalo không chỉ là ứng dụng nhắn tin — đây là kênh truyền thông trực tiếp đến khách hàng hiệu quả nhất mà bạn có thể khai thác. Tỷ lệ mở tin nhắn Zalo OA đạt 70–80%, gấp 5–6 lần so với email marketing thông thường. Trong khi email chìm vào hòm thư spam, tin nhắn Zalo hiện ngay trên màn hình điện thoại của khách hàng.

Đặc biệt với doanh nghiệp vừa và nhỏ (SMB) tại Việt Nam — salon tóc, phòng khám, cửa hàng bán lẻ, bất động sản, logistics — đang quản lý danh sách khách hàng bằng Google Sheets, việc kết nối trực tiếp với Zalo OA API tạo ra một hệ thống thông báo tự động cực kỳ mạnh mẽ mà không cần mua phần mềm CRM đắt tiền.

Combo Google Sheets + Zalo OA cho phép bạn:

  • Tự động nhắc lịch hẹn cho từng khách hàng đúng giờ, đúng ngày
  • Gửi thông báo đơn hàng, giao hàng theo thời gian thực
  • Chăm sóc sinh nhật khách hàng kèm voucher tự động
  • Nhắc công nợ lịch sự, đúng hạn mà không cần nhân viên gọi tay
  • Broadcast khuyến mãi đến toàn bộ danh sách không tốn chi phí SMS

Nguyên Lý Hoạt Động

Luồng tự động hóa đơn giản theo 4 bước:

  1. Google Sheets lưu danh sách khách hàng với Zalo ID, thông tin liên hệ, ngày hẹn, trạng thái đơn hàng...
  2. Apps Script chạy theo lịch (trigger time-driven) — ví dụ mỗi ngày lúc 8h sáng — đọc dữ liệu từ Sheets
  3. Apps Script gọi Zalo OA API (endpoint openapi.zalo.me) với Access Token xác thực
  4. Tin nhắn đến khách hàng qua Zalo — hiển thị tức thì trên điện thoại

Toàn bộ hệ thống chạy hoàn toàn miễn phí (trong giới hạn quota) và không cần server hay hosting riêng.

Bước 1: Tạo Zalo Official Account (OA)

Zalo OA là tài khoản doanh nghiệp trên Zalo — tương tự Facebook Page. Bạn tạo miễn phí tại oa.zalo.me.

  1. Truy cập oa.zalo.me → Tạo OA mới
  2. Chọn loại OA phù hợp: Doanh nghiệp / Cá nhân kinh doanh
  3. Điền thông tin: tên thương hiệu, danh mục ngành, logo, mô tả
  4. Xác thực tài khoản (cần CMND/CCCD hoặc giấy phép kinh doanh)
  5. Sau khi duyệt (1–3 ngày làm việc), OA của bạn sẽ có biểu tượng xanh lá xác thực

Lưu ý: Gói OA miễn phí cho phép gửi tối đa 100 tin nhắn CS (Customer Service) mỗi ngày. Để gửi nhiều hơn hoặc dùng template tin nhắn quảng cáo, cần nâng cấp lên gói trả phí.

Bước 2: Lấy Access Token Zalo OA API

Access Token là "chìa khóa" để Apps Script giao tiếp với Zalo API. Các bước lấy token:

  1. Đăng ký tài khoản Developer tại developers.zalo.me
  2. Tạo ứng dụng mới → lấy App IDSecret Key
  3. Vào OA của bạn → Cài đặt → Tích hợp API
  4. Liên kết ứng dụng với OA → tạo Access Token
  5. Lưu Access Token vào Apps Script Properties (không hard-code trong script)

Quan trọng về thời hạn token: Access Token Zalo có hạn 90 ngày. Sau đó cần dùng Refresh Token để gia hạn tự động, hoặc vào Developer Console tạo token mới thủ công. Nên lưu cả Refresh Token để tự động hóa hoàn toàn.

// Lưu token an toàn vào Script Properties
// Vào Apps Script → Project Settings → Script Properties
// Key: ZALO_TOKEN | Value: [access_token_của_bạn]

function layToken() {
  const token = PropertiesService.getScriptProperties().getProperty('ZALO_TOKEN');
  return token;
}

Bước 3: Cấu Trúc Google Sheets

Tạo bảng theo cấu trúc chuẩn để Apps Script đọc được chính xác. Ví dụ cho use-case nhắc lịch hẹn:

STT Zalo ID Tên KH Số điện thoại Ngày hẹn Giờ hẹn Dịch vụ Đã gửi
1 12345678 Nguyễn Thị Lan 0901234567 10/06/2026 10:00 Cắt tóc, nhuộm FALSE
2 87654321 Trần Văn Nam 0987654321 11/06/2026 14:30 Khám răng định kỳ FALSE

Cột "Đã gửi" rất quan trọng — đây là cơ chế chống gửi trùng. Sau khi gửi tin thành công, script sẽ tự động đánh dấu TRUE để những lần chạy sau bỏ qua hàng đó.

Cách lấy Zalo ID của khách hàng:

  • Khi khách nhắn tin vào OA → hệ thống tự ghi lại user_id trong webhook
  • Dùng Zalo Login widget trên website → lấy user_id khi khách đăng nhập
  • Quan trọng: Chỉ gửi được cho user đã quan tâm OA hoặc đã tương tác trong vòng 7 ngày gần nhất

Bước 4: Code Apps Script — Hàm Gửi Tin Nhắn Cơ Bản

Đây là hàm nền tảng — tất cả các use-case đều dùng hàm này để gửi tin qua Zalo OA API v3:

/**
 * Gửi tin nhắn Zalo OA tới một user cụ thể
 * @param {string} userId - Zalo User ID của khách hàng
 * @param {string} noiDung - Nội dung tin nhắn (tối đa 2000 ký tự)
 * @returns {object} Response từ Zalo API
 */
function guiZaloOA(userId, noiDung) {
  const ACCESS_TOKEN = PropertiesService.getScriptProperties().getProperty('ZALO_TOKEN');

  if (!ACCESS_TOKEN) {
    throw new Error('ZALO_TOKEN chưa được cấu hình trong Script Properties');
  }

  const url = 'https://openapi.zalo.me/v3.0/oa/message/cs';

  const payload = {
    recipient: { user_id: userId },
    message: { text: noiDung }
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: { 'access_token': ACCESS_TOKEN },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const result = JSON.parse(response.getContentText());

    if (result.error !== 0) {
      console.error(`Lỗi Zalo API: ${result.message} (code: ${result.error})`);
      return null;
    }

    return result;
  } catch (e) {
    console.error(`Lỗi khi gọi API: ${e.message}`);
    return null;
  }
}

Bước 5: Code Tự Động Nhắc Lịch Hẹn

Use-case phổ biến nhất cho salon tóc, phòng khám, spa, trung tâm tư vấn BĐS:

/**
 * Tự động nhắc lịch hẹn cho khách hàng vào ngày hôm sau
 * Chạy trigger: mỗi ngày lúc 8:00 sáng
 */
function nhacLichHen() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const data = sheet.getDataRange().getValues();

  // Tính ngày mai
  const ngayMai = new Date();
  ngayMai.setDate(ngayMai.getDate() + 1);
  const chuoiNgayMai = ngayMai.toLocaleDateString('vi-VN', {
    day: '2-digit', month: '2-digit', year: 'numeric'
  });

  let daDem = 0;

  // Duyệt từ hàng 2 (bỏ header)
  for (let i = 1; i < data.length; i++) {
    const zaloId  = String(data[i][1]).trim(); // Cột B: Zalo ID
    const tenKH   = data[i][2];                // Cột C: Tên KH
    const ngayHen = new Date(data[i][4]);      // Cột E: Ngày hẹn
    const gioHen  = data[i][5];                // Cột F: Giờ hẹn
    const dichVu  = data[i][6];                // Cột G: Dịch vụ
    const daGui   = data[i][7];                // Cột H: Đã gửi

    // Bỏ qua hàng trống hoặc đã gửi
    if (!zaloId || daGui === true || daGui === 'TRUE') continue;

    // Kiểm tra có phải ngày mai không
    const chuoiNgayHen = ngayHen.toLocaleDateString('vi-VN', {
      day: '2-digit', month: '2-digit', year: 'numeric'
    });

    if (chuoiNgayHen !== chuoiNgayMai) continue;

    // Soạn nội dung tin nhắn
    const noiDung = `Xin chào ${tenKH}! 🗓️\n\nNhắc nhở: Bạn có lịch hẹn vào:\n📅 ${chuoiNgayHen} lúc ${gioHen}\n💼 Dịch vụ: ${dichVu}\n\nVui lòng liên hệ nếu cần thay đổi lịch. Cảm ơn bạn!`;

    // Gửi tin nhắn
    const ketQua = guiZaloOA(zaloId, noiDung);

    if (ketQua) {
      // Đánh dấu đã gửi
      sheet.getRange(i + 1, 8).setValue(true);
      daDem++;
      console.log(`Đã nhắc: ${tenKH} - ${chuoiNgayHen} ${gioHen}`);
    }

    // Nghỉ 500ms giữa các tin để tránh rate limit
    Utilities.sleep(500);
  }

  console.log(`Hoàn tất: Đã gửi ${daDem} tin nhắn nhắc lịch`);
}

6 Use-Case Thực Tế Cho Doanh Nghiệp Việt Nam

1. Thông Báo Đơn Hàng (Cửa Hàng Bán Lẻ)

Khi trạng thái đơn hàng trong Sheets thay đổi (Chờ xác nhận → Đã xác nhận → Đang giao), tự động gửi Zalo:

function thongBaoDonHang() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    const zaloId     = String(data[i][0]).trim();
    const tenKH      = data[i][1];
    const maDon      = data[i][2];
    const trangThai  = data[i][3];
    const daThongBao = data[i][4];

    if (!zaloId || daThongBao) continue;

    let noiDung = '';

    if (trangThai === 'Đã xác nhận') {
      noiDung = `Xin chào ${tenKH}! ✅\nĐơn hàng #${maDon} của bạn đã được xác nhận.\nChúng tôi sẽ chuẩn bị hàng trong 24h.`;
    } else if (trangThai === 'Đang giao') {
      noiDung = `Xin chào ${tenKH}! 🚚\nĐơn hàng #${maDon} đang trên đường giao.\nDự kiến nhận hàng trong hôm nay.`;
    } else if (trangThai === 'Đã giao') {
      noiDung = `Xin chào ${tenKH}! 📦\nĐơn hàng #${maDon} đã giao thành công.\nCảm ơn bạn đã mua hàng! Hãy để lại đánh giá nhé.`;
    }

    if (noiDung) {
      const ketQua = guiZaloOA(zaloId, noiDung);
      if (ketQua) sheet.getRange(i + 1, 5).setValue(true);
      Utilities.sleep(500);
    }
  }
}

2. Chăm Sóc Sinh Nhật + Gửi Voucher

Đặc biệt hiệu quả cho spa, salon, nhà hàng — gửi lời chúc sinh nhật kèm mã giảm giá:

function chucSinhNhat() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const homNay = new Date();

  for (let i = 1; i < data.length; i++) {
    const zaloId   = String(data[i][0]).trim();
    const tenKH    = data[i][1];
    const ngaySinh = new Date(data[i][2]); // Cột ngày sinh
    const voucher  = data[i][3];           // Cột mã voucher
    const daGui    = data[i][4];

    if (!zaloId || daGui) continue;

    // Kiểm tra ngày và tháng (không cần năm)
    const trungNgay  = ngaySinh.getDate()  === homNay.getDate();
    const trungThang = ngaySinh.getMonth() === homNay.getMonth();

    if (trungNgay && trungThang) {
      const noiDung = `🎂 Chúc mừng sinh nhật ${tenKH}!\n\nNhân dịp đặc biệt này, tặng bạn voucher giảm 20%:\n🎁 Mã: ${voucher}\n⏰ Hiệu lực đến: 31/12/2026\n\nChúc bạn một ngày sinh nhật thật vui!`;

      const ketQua = guiZaloOA(zaloId, noiDung);
      if (ketQua) sheet.getRange(i + 1, 5).setValue(true);
      Utilities.sleep(500);
    }
  }
}

3. Nhắc Thanh Toán Công Nợ (B2B / Nhà Cung Cấp)

Phù hợp cho doanh nghiệp có khách hàng doanh nghiệp, nhà cung cấp cần nhắc đến hạn thanh toán lịch sự:

function nhacThanhToan() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const homNay = new Date();

  for (let i = 1; i < data.length; i++) {
    const zaloId    = String(data[i][0]).trim();
    const tenKH     = data[i][1];
    const soTien    = data[i][2].toLocaleString('vi-VN');
    const ngayHan   = new Date(data[i][3]);
    const soHoaDon  = data[i][4];
    const daGui     = data[i][5];

    if (!zaloId || daGui) continue;

    // Tính số ngày còn lại
    const soNgay = Math.ceil((ngayHan - homNay) / (1000 * 60 * 60 * 24));

    if (soNgay === 3) { // Nhắc trước 3 ngày
      const chuoiNgay = ngayHan.toLocaleDateString('vi-VN');
      const noiDung = `Kính gửi ${tenKH},\n\nNhắc nhở thân thiện: Hóa đơn #${soHoaDon} số tiền ${soTien} VNĐ sẽ đến hạn thanh toán vào ${chuoiNgay} (còn 3 ngày).\n\nVui lòng liên hệ nếu cần hỗ trợ. Trân trọng!`;

      const ketQua = guiZaloOA(zaloId, noiDung);
      if (ketQua) sheet.getRange(i + 1, 6).setValue(true);
      Utilities.sleep(500);
    }
  }
}

4. Broadcast Khuyến Mãi

Gửi thông báo chương trình mới đến toàn bộ danh sách khách hàng (lưu ý giới hạn 100 tin/ngày với gói free):

function broadcastKhuyenMai(noiDungChung) {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  let daDem = 0;

  for (let i = 1; i < data.length; i++) {
    const zaloId = String(data[i][0]).trim();
    const tenKH  = data[i][1];
    const daGui  = data[i][2]; // Cột "Đã gửi đợt này"

    if (!zaloId || daGui) continue;
    if (daDem >= 95) { // Giữ dưới 100 để an toàn
      console.log('Đạt giới hạn 95 tin/ngày, dừng lại');
      break;
    }

    // Cá nhân hóa tên
    const noiDung = `Xin chào ${tenKH}!\n${noiDungChung}`;

    const ketQua = guiZaloOA(zaloId, noiDung);
    if (ketQua) {
      sheet.getRange(i + 1, 3).setValue(true);
      daDem++;
    }

    Utilities.sleep(1000); // 1 giây giữa mỗi tin
  }

  console.log(`Broadcast hoàn tất: ${daDem} tin đã gửi`);
}

// Gọi: broadcastKhuyenMai("🎉 Sale 50% cuối tuần này! Mua ngay tại shop.example.com");

5. Thông Báo Trạng Thái Giao Hàng

Tích hợp với sheet theo dõi đơn vận chuyển, tự động cập nhật khi trạng thái thay đổi:

function thongBaoGiaoHang() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    const zaloId       = String(data[i][0]).trim();
    const tenKH        = data[i][1];
    const maVanDon     = data[i][2];
    const trangThai    = data[i][3];
    const trangThaiCu  = data[i][4]; // Trạng thái lần gửi trước

    if (!zaloId || trangThai === trangThaiCu) continue;

    const noiDung = `Cập nhật vận đơn ${maVanDon}:\n📦 Trạng thái: ${trangThai}\n\nTheo dõi đơn hàng của ${tenKH} tại: track.example.com/${maVanDon}`;

    const ketQua = guiZaloOA(zaloId, noiDung);
    if (ketQua) {
      sheet.getRange(i + 1, 5).setValue(trangThai); // Cập nhật trạng thái cũ
      Utilities.sleep(500);
    }
  }
}

6. Nhắc Tái Khám / Tái Mua Hàng

Dành cho phòng khám, spa, cửa hàng thực phẩm chức năng — nhắc khách tái khám hoặc mua lại sau X ngày:

function nhacTaiKham() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  const homNay = new Date();

  for (let i = 1; i < data.length; i++) {
    const zaloId    = String(data[i][0]).trim();
    const tenKH     = data[i][1];
    const ngayKham  = new Date(data[i][2]); // Ngày khám/mua lần cuối
    const chuKy     = parseInt(data[i][3]); // Chu kỳ tái khám (ngày)
    const daGui     = data[i][4];

    if (!zaloId || daGui) continue;

    const ngayNhac = new Date(ngayKham);
    ngayNhac.setDate(ngayNhac.getDate() + chuKy);

    // Nếu đến ngày nhắc
    if (homNay >= ngayNhac) {
      const noiDung = `Xin chào ${tenKH}!\n\nĐã ${chuKy} ngày kể từ lần khám trước. Bạn có muốn đặt lịch tái khám không?\n\nGọi: 0901234567 hoặc nhắn tin vào đây để đặt lịch!`;

      const ketQua = guiZaloOA(zaloId, noiDung);
      if (ketQua) sheet.getRange(i + 1, 5).setValue(true);
      Utilities.sleep(500);
    }
  }
}

Bước 6: Cài Đặt Trigger Tự Động

Để script chạy tự động mà không cần bạn mở Sheets mỗi ngày:

  1. Trong Apps Script, nhấp vào biểu tượng đồng hồ (⏰) Triggers ở thanh bên trái
  2. Nhấn + Add Trigger ở góc phải dưới
  3. Cấu hình:
    • Function to run: nhacLichHen (hoặc hàm bạn muốn)
    • Event source: Time-driven
    • Time-based trigger type: Day timer
    • Time of day: 8am to 9am
  4. Nhấn Save → Trigger sẽ chạy mỗi ngày tự động

Mẹo: Tạo nhiều trigger cho các hàm khác nhau — ví dụ nhắc lịch hẹn lúc 8h sáng, thông báo công nợ lúc 9h, broadcast khuyến mãi lúc 10h. Mỗi trigger độc lập, không ảnh hưởng nhau.

Giới Hạn và Lưu Ý Quan Trọng

Điểm cần biết Chi tiết Giải pháp
Gói OA miễn phí 100 tin CS message/ngày Nâng cấp OA trả phí nếu cần nhiều hơn
Điều kiện gửi tin Chỉ gửi được cho user đã quan tâm OA hoặc tương tác trong 7 ngày Khuyến khích KH quan tâm OA qua QR code / link
Tin nhắn quảng cáo Cần dùng template được duyệt trước bởi Zalo Submit template qua Developer Console, chờ 3–5 ngày
Access Token hết hạn Token có hạn 90 ngày Lưu Refresh Token, tự động gia hạn qua API
Rate limiting Zalo giới hạn tốc độ gửi Thêm Utilities.sleep(500) giữa các tin
Apps Script quota Google giới hạn 6h chạy/ngày với tài khoản cá nhân Workspace Business tăng lên 6h/ngày/user

So Sánh Các Kênh Gửi Thông Báo

Tiêu chí Zalo OA SMS Email Facebook Messenger
Tỷ lệ mở 70–80% 95–98% 10–15% 60–70%
Chi phí Miễn phí (CS msg) Tốn tiền/tin Miễn phí cơ bản Hạn chế sau 24h
Phổ biến tại VN Nhất Phổ biến Ít dùng cá nhân Phổ biến
Bị spam/block Thấp Cao Rất cao Trung bình
Kết hợp Sheets Dễ (Apps Script) Cần dịch vụ SMS API Dễ (MailApp) Phức tạp hơn
Cá nhân hóa Cao Trung bình Cao Cao

Kết luận so sánh: Với doanh nghiệp Việt Nam, Zalo OA là kênh tối ưu nhất khi kết hợp chi phí thấp, tỷ lệ mở cao và sự phổ biến của nền tảng. SMS chỉ nên dùng cho các tin khẩn không thể bỏ lỡ (OTP, xác nhận thanh toán). Email phù hợp cho thông tin dài, formal.

Kết Luận

Bạn vừa có đầy đủ blueprint để xây dựng hệ thống gửi tin nhắn Zalo tự động từ Google Sheets — hoàn toàn miễn phí, không cần server, không cần CRM đắt tiền. Với 6 use-case thực tế đã cung cấp code đầy đủ, bạn có thể triển khai ngay hôm nay cho:

  • Salon / Spa: Nhắc lịch hẹn + chúc sinh nhật + tái dịch vụ
  • Phòng khám: Nhắc tái khám + kết quả xét nghiệm
  • Cửa hàng bán lẻ: Thông báo đơn hàng + giao hàng
  • Bất động sản: Nhắc lịch xem nhà + cập nhật dự án
  • B2B / Nhà cung cấp: Nhắc thanh toán công nợ lịch sự

Bước tiếp theo: Tạo Zalo OA → lấy Access Token → copy code vào Apps Script → đặt trigger 8h sáng mỗi ngày. Chỉ mất 30–60 phút để có hệ thống chạy tự động 365 ngày.

Nếu cần hỗ trợ tùy chỉnh code theo quy trình riêng của doanh nghiệp bạn, hãy tham khảo thêm tại Zalo Developer Portal hoặc để lại bình luận bên dưới.

Nguồn tham khảo: Zalo Developer Portal | Zalo Official Account

Chia sẻ bài viết:

Tuân Hoang

Tuân Hoang

Đội ngũ SheetStore

Google SheetsGoogle Apps ScriptCRMAutomationPhần mềm quản lý doanh nghiệp

Google Workspace Certified, 5+ years experience

Bạn thấy bài viết hữu ích?

Đăng ký nhận thông báo khi có bài viết mới.

Nhận thông báo khi có bài viết mới. Không spam, hứa luôn! 😊

Bình luận (0)

Vui lòng đăng nhập để tham gia thảo luận