Bỏ qua để đến nội dung chính
Điền NguyễnAZ

google-sheets

Cách gửi email tự động từ Google Sheets bằng Apps Script

14/09/2026· Điền Nguyễn AZ
Cách gửi email tự động từ Google Sheets bằng Apps Script

Vì sao cần gửi email tự động từ Google Sheets?

Nhiều công việc lặp đi lặp lại đang được làm bằng tay: copy từng địa chỉ email trong bảng danh sách, mở Gmail, soạn từng thư, gửi từng người. Với vài chục dòng dữ liệu, việc này tốn cả buổi và rất dễ gửi nhầm hoặc gửi sót.

Google Sheets kết hợp với Google Apps Script giải quyết được việc này: script đọc từng dòng dữ liệu trong bảng, tự soạn nội dung riêng cho từng người (mail merge), rồi gửi qua tài khoản Gmail của bạn — không cần công cụ gửi email hàng loạt bên thứ ba, không giới hạn số trường dữ liệu như các add-on miễn phí.

Bài này hướng dẫn 4 việc theo đúng thứ tự cần làm: gửi một email đơn giản, gửi hàng loạt cá nhân hóa theo từng dòng, tránh gửi trùng khi chạy lại script, và tự động chạy theo lịch hoặc khi có dữ liệu mới nộp vào.

Chuẩn bị dữ liệu trong Sheets

Ví dụ dữ liệu dùng xuyên suốt bài này — danh sách học viên cần gửi email nhắc lịch học:

A B C D
1 Họ tên Email Lớp Đã gửi
2 Nguyễn Văn A vana@gmail.com Excel cơ bản
3 Trần Thị B thib@gmail.com Word cơ bản
4 Lê Văn C vanc@gmail.com Excel cơ bản

Cột D ("Đã gửi") ban đầu để trống — cột này dùng để đánh dấu trạng thái, tránh gửi lại cho người đã nhận (giải thích ở Bước 3).

Bước 1: Gửi một email đơn giản bằng MailApp

Mở file Sheets → menu Tiện ích mở rộng (Extensions) → Apps Script, xóa nội dung mặc định trong Code.gs, dán đoạn sau để làm quen với hàm gửi email cơ bản nhất:

function guiThuDon() {
  MailApp.sendEmail(
    "vana@gmail.com",
    "Nhắc lịch học",
    "Chào bạn, lớp Excel cơ bản của bạn sẽ khai giảng vào thứ 2 tuần sau."
  );
}

MailApp.sendEmail(người_nhận, tiêu_đề, nội_dung) là cú pháp cơ bản nhất — 3 tham số theo đúng thứ tự này. Bấm Run (▶), cấp quyền khi được yêu cầu (Review permissions → Advanced → Go to... → Allow, chỉ hỏi một lần cho mỗi project), rồi kiểm tra hộp thư của địa chỉ nhận.

Bước 2: Gửi hàng loạt, cá nhân hóa theo từng dòng dữ liệu

Thay vì gõ cứng nội dung như trên, đọc dữ liệu trực tiếp từ bảng và lặp qua từng dòng:

function guiEmailHangLoat() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var duLieu = sheet.getDataRange().getValues();

  for (var i = 1; i < duLieu.length; i++) {
    var hoTen = duLieu[i][0];
    var email = duLieu[i][1];
    var lop = duLieu[i][2];

    if (!email) continue;

    var tieuDe = "Nhắc lịch học: " + lop;
    var noiDung =
      "Chào " + hoTen + ",\n\n" +
      "Lớp " + lop + " của bạn sẽ khai giảng vào thứ 2 tuần sau. " +
      "Vui lòng có mặt đúng giờ.\n\nCảm ơn bạn!";

    MailApp.sendEmail(email, tieuDe, noiDung);
  }
}

getDataRange().getValues() đọc toàn bộ bảng thành một mảng 2 chiều — duLieu[i][0] là cột A (Họ tên), duLieu[i][1] là cột B (Email), duLieu[i][2] là cột C (Lớp) của dòng thứ i. Vòng lặp bắt đầu từ i = 1 để bỏ qua dòng tiêu đề (dòng 0 trong mảng). Dòng if (!email) continue; bỏ qua những dòng chưa có email, tránh báo lỗi giữa chừng khi gặp ô trống.

Bước 3: Đánh dấu trạng thái để không gửi trùng

Nếu chạy lại guiEmailHangLoat() ở trên (ví dụ do thêm vài dòng mới), script sẽ gửi lại từ đầu cho cả những người đã nhận email trước đó. Dùng cột D ("Đã gửi") để đánh dấu và bỏ qua các dòng đã xử lý:

function guiEmailKhongTrungLap() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var duLieu = sheet.getDataRange().getValues();

  for (var i = 1; i < duLieu.length; i++) {
    var hoTen = duLieu[i][0];
    var email = duLieu[i][1];
    var lop = duLieu[i][2];
    var daGui = duLieu[i][3];

    if (!email || daGui === "Đã gửi") continue;

    var tieuDe = "Nhắc lịch học: " + lop;
    var noiDung = "Chào " + hoTen + ",\n\nLớp " + lop + " của bạn sẽ khai giảng vào thứ 2 tuần sau.";

    MailApp.sendEmail(email, tieuDe, noiDung);

    sheet.getRange(i + 1, 4).setValue("Đã gửi");
  }
}

Sau mỗi lần gửi thành công, sheet.getRange(i + 1, 4).setValue("Đã gửi") ghi chữ "Đã gửi" vào cột D cùng dòng đó (i + 1 vì getRange đếm dòng từ 1, còn mảng duLieu đếm từ 0). Lần chạy sau, những dòng đã có "Đã gửi" ở cột D sẽ bị bỏ qua ở điều kiện daGui === "Đã gửi".

Bước 4: Tự động chạy theo lịch hoặc khi có dữ liệu mới

Chạy tay bằng nút Run vẫn cần bạn nhớ mở file mỗi lần. Muốn thật sự tự động, gắn trigger (bộ kích hoạt) cho hàm guiEmailKhongTrungLap:

  1. Trong trình soạn thảo Apps Script, bấm biểu tượng đồng hồ ở thanh bên trái (Triggers).
  2. Bấm Add Trigger.
  3. Ở mục Choose which function to run, chọn guiEmailKhongTrungLap.
  4. Ở mục Select event source, chọn một trong hai kiểu tùy nhu cầu:
    • Time-driven: chạy theo lịch cố định (ví dụ mỗi ngày một lần, mỗi giờ một lần) — phù hợp khi dữ liệu được nhập rải rác trong ngày và bạn muốn gom lại gửi theo đợt.
    • From spreadsheet → On form submit: chạy ngay khi có người nộp Google Form gắn với Sheets này — phù hợp khi cần gửi email xác nhận tức thì sau khi ai đó đăng ký.
  5. Bấm Save, cấp quyền lại nếu được yêu cầu.

Từ giờ script tự chạy đúng lịch hoặc đúng sự kiện, không cần bạn mở file hay bấm Run nữa.

Dùng GmailApp khi cần định dạng HTML, đính kèm, CC/BCC

MailApp chỉ gửi được email dạng văn bản thuần và có giới hạn tính năng. Khi cần email trình bày đẹp hơn (định dạng HTML, logo, nút bấm) hoặc cần đính kèm file, CC/BCC, dùng GmailApp.sendEmail() với tham số tùy chọn:

GmailApp.sendEmail(email, tieuDe, "Phiên bản văn bản thuần dự phòng", {
  htmlBody: "<p>Chào <b>" + hoTen + "</b>,</p><p>Lớp " + lop + " khai giảng thứ 2 tuần sau.</p>",
  cc: "quanly@gmail.com",
  attachments: [DriveApp.getFileById("ID_FILE_DINH_KEM").getBlob()],
});

GmailApp và MailApp dùng chung một hạn mức gửi email hằng ngày (xem bảng bên dưới) — chọn GmailApp khi thực sự cần các tùy chọn trên, còn lại MailApp.sendEmail() đơn giản hơn và đủ dùng cho hầu hết nhu cầu nhắc lịch, thông báo thông thường.

Giới hạn số email được gửi mỗi ngày

Google giới hạn số email gửi qua Apps Script theo loại tài khoản, tính theo 24 giờ gần nhất (không reset đúng nửa đêm):

Loại tài khoản Giới hạn/ngày
Gmail cá nhân miễn phí 100 email
Google Workspace (trả phí, tùy gói) 1.500 email

Nếu danh sách gửi lớn hơn giới hạn, script sẽ báo lỗi khi vượt ngưỡng ở email tiếp theo. Cách xử lý phổ biến là kiểm tra số email còn được gửi trong ngày bằng MailApp.getRemainingDailyQuota() trước khi chạy vòng lặp, và dừng lại (hoặc để dành phần còn lại cho lần chạy sau) nếu số dòng cần gửi vượt quá số quota còn lại.

Lỗi thường gặp

Script chạy xong nhưng không có email nào được gửi Kiểm tra lại điều kiện if (!email) continue; — nếu ô email trong Sheets có khoảng trắng thừa hoặc sai định dạng, một số trình duyệt/Apps Script vẫn coi là có giá trị nên dòng đó không bị bỏ qua, nhưng MailApp sẽ báo lỗi ngầm khi địa chỉ không hợp lệ. Dùng Logger.log(email) trong vòng lặp rồi xem Executions (biểu tượng đồng hồ cát bên trái) để kiểm tra từng địa chỉ thực tế đã đọc được.

Lỗi "Service invoked too many times for one day" Đã vượt hạn mức gửi email trong 24 giờ (xem bảng ở trên). Đợi hạn mức reset hoặc giảm số lượng gửi mỗi lần chạy.

Gửi trùng lặp dù đã thêm cột "Đã gửi" Thường do sai công thức so sánh, ví dụ cột D có khoảng trắng thừa ("Đã gửi ") khiến daGui === "Đã gửi" không khớp. Dùng String(daGui).trim() === "Đã gửi" để loại khoảng trắng thừa trước khi so sánh.

Trigger "On form submit" không tự chạy Trigger này chỉ hoạt động khi Form được gắn trực tiếp với Sheets (Form tạo ra dòng dữ liệu mới trong chính Sheets đó). Nếu dữ liệu được nhập tay hoặc dán vào Sheets, phải dùng trigger Time-driven hoặc trigger onEdit (installable, không phải simple trigger) thay thế.

Email gửi đi nhưng vào mục Spam của người nhận Nội dung có quá nhiều chữ in hoa, nhiều dấu chấm than, hoặc gửi số lượng lớn cùng lúc dễ bị lọc là spam. Viết nội dung tự nhiên, gửi thử cho vài địa chỉ khác nhà cung cấp (Gmail, Outlook...) để kiểm tra trước khi gửi hàng loạt thật.

Khi nào nên dùng cách này?

  • Gửi email nhắc lịch học, lịch hẹn, lịch thanh toán cho danh sách khách hàng/học viên
  • Gửi email xác nhận tự động ngay sau khi ai đó nộp Google Form đăng ký
  • Gửi báo cáo định kỳ (theo ngày/tuần/tháng) tổng hợp từ dữ liệu trong Sheets
  • Thay thế các add-on gửi email hàng loạt có giới hạn số lượng ở bản miễn phí

Học Google Sheets thực chiến tại TP Vinh

Gửi email tự động là một ứng dụng thực tế của Google Apps Script sau khi đã nắm chắc cách đọc/ghi dữ liệu trong Sheets. Nếu bạn muốn học Google Sheets bài bản, từ các hàm và thao tác cơ bản đến tự động hóa nâng cao, tham khảo khóa học Google Sheets tại Điền Nguyễn AZ.

📞 Hotline / Zalo: 0362 465 361

👉 Xem chi tiết: Khóa học Google Sheets thực tế tại TP Vinh

#gửi email tự động#google apps script#mailapp#google sheets#gửi email hàng loạt

Tài liệu miễn phí

30 phím tắt Excel hay dùng nhất

Tổng hợp phím tắt giúp thao tác Excel nhanh hơn — điền thông tin để tải file PDF miễn phí về dùng ngay.