Google Sheets + Zalo OA: Tự Động Gửi Tin Nhắn Hàng Loạt [Hướng Dẫn 2026]
![Ả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]](/og-image.jpg)
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:
- 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...
- 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
- Apps Script gọi Zalo OA API (endpoint
openapi.zalo.me) với Access Token xác thực - 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.
- Truy cập oa.zalo.me → Tạo OA mới
- Chọn loại OA phù hợp: Doanh nghiệp / Cá nhân kinh doanh
- Điền thông tin: tên thương hiệu, danh mục ngành, logo, mô tả
- Xác thực tài khoản (cần CMND/CCCD hoặc giấy phép kinh doanh)
- 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:
- Đăng ký tài khoản Developer tại developers.zalo.me
- Tạo ứng dụng mới → lấy App ID và Secret Key
- Vào OA của bạn → Cài đặt → Tích hợp API
- Liên kết ứng dụng với OA → tạo Access Token
- 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:
- Trong Apps Script, nhấp vào biểu tượng đồng hồ (⏰) Triggers ở thanh bên trái
- Nhấn + Add Trigger ở góc phải dưới
- 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
- 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 | 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
Đội ngũ SheetStore
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.
