Mở đầu — vì sao bài này quan trọng
Suốt mấy bài trước, bạn và tôi đã đi qua khá nhiều lý thuyết: RPA là gì, kiến trúc UiPath gồm những thành phần nào, Power Automate vận hành ra sao trong hệ sinh thái Microsoft. Tất cả đều cần thiết, nhưng có một sự thật mà người mới hay quên: bạn không thực sự hiểu RPA cho đến khi bạn nhìn thấy một con bot chạy từ đầu đến cuối một quy trình thật.
Bài này chính là khoảnh khắc đó. Chúng ta sẽ lấy một kịch bản kinh điển — bot đọc danh sách khách hàng từ file Excel rồi gửi email cá nhân hóa cho từng người — và mổ xẻ nó từng dòng. Đây không phải ví dụ "đồ chơi". Đây là một trong những use case được triển khai nhiều nhất ở các doanh nghiệp Việt Nam khi họ bắt đầu hành trình tự động hóa: gửi thông báo lịch hẹn, nhắc nợ, gửi mã ưu đãi, xác nhận đơn hàng. Nếu bạn nắm được logic của bài này, bạn đã có trong tay một mẫu (template) áp dụng được cho hàng chục quy trình khác.
Điều tôi muốn bạn rút ra không chỉ là "cách kéo thả activity". Quan trọng hơn là tư duy khi xây một bot: bạn đọc dữ liệu vào đâu, lặp qua nó thế nào, xử lý ngoại lệ ra sao, và làm sao để con bot không gửi nhầm 5.000 email lúc 3 giờ sáng. Đó mới là thứ phân biệt một người biết dùng công cụ với một người làm RPA chuyên nghiệp.
Khái niệm cốt lõi
Trước khi viết một dòng workflow nào, hãy hình dung bài toán dưới dạng một dòng chảy dữ liệu (data flow). Mọi bot RPA kiểu "đọc dữ liệu rồi hành động" đều có chung một bộ xương:
- Đọc nguồn dữ liệu — ở đây là một bảng Excel.
- Đưa dữ liệu vào bộ nhớ — thường là một biến kiểu DataTable (bảng trong RAM).
- Lặp qua từng dòng — mỗi dòng là một khách hàng.
- Lấy giá trị từng cột — tên, email, số tiền, ngày hẹn...
- Ghép nội dung cá nhân hóa — thay placeholder bằng dữ liệu thật.
- Thực hiện hành động — gửi email qua SMTP hoặc Outlook.
- Ghi log / xử lý lỗi — đánh dấu dòng nào thành công, dòng nào hỏng.
DataTable — trái tim của bot đọc dữ liệu
Khi UiPath đọc một dải ô (range) trong Excel, nó không lưu từng ô riêng lẻ mà gói toàn bộ thành một DataTable — bạn cứ tưởng tượng như một bảng tính nằm trong bộ nhớ máy tính. Mỗi DataRow là một dòng, và bạn truy cập giá trị bằng tên cột: row("Email").ToString. Hiểu được DataTable là hiểu được 80% các bot xử lý dữ liệu, vì hầu hết quy trình văn phòng đều xoay quanh việc đọc bảng và xử lý từng dòng.
Read Range và tham số AddHeaders
Activity Excel Read Range (hoặc Read Range Workbook) có một lựa chọn nhỏ nhưng cực quan trọng: AddHeaders. Nếu bật, dòng đầu tiên của Excel được hiểu là tên cột (header), và bạn truy cập dữ liệu bằng tên — dễ đọc, ít lỗi. Nếu tắt, bạn phải dùng chỉ số cột (row(0), row(1)) — vừa khó đọc vừa dễ sai khi ai đó chèn thêm cột. Lời khuyên của tôi: luôn dùng AddHeaders.
For Each Row — vòng lặp định mệnh
Activity For Each Row in DataTable là nơi bot duyệt từng khách hàng. Bên trong vòng lặp, biến CurrentRow (UiPath đặt tên mặc định) đại diện cho dòng đang xử lý. Đây là chỗ bạn lấy email, ghép nội dung và gửi đi. Cũng chính là chỗ bạn phải đặt khối Try-Catch để một email hỏng không làm sập cả bot.
Gửi email — SMTP vs ứng dụng email
Có hai cách gửi:
- Send SMTP Mail Message: bot kết nối thẳng tới máy chủ SMTP (ví dụ
smtp.gmail.com,smtp.office365.comhoặc SMTP nội bộ của công ty). Nhanh, không cần mở Outlook, phù hợp khi chạy trên server không có giao diện. - Send Outlook Mail Message: bot điều khiển Outlook đang cài trên máy. Tiện vì dùng luôn tài khoản đã đăng nhập, email nằm trong Sent Items, nhưng phụ thuộc vào việc máy có Outlook và đã login.
Pseudo-code của toàn bộ workflow
Để bạn thấy bức tranh tổng thể trước khi đi vào chi tiết, đây là phiên bản giả lập (gần với UiPath nhưng đã đơn giản hóa):
<Sequence>
<ExcelApplicationScope WorkbookPath="KhachHang.xlsx">
<ExcelReadRange Range="" AddHeaders="True" Output="dtCustomers" />
</ExcelApplicationScope> <ForEachRow DataTable="dtCustomers" CurrentRow="row">
<TryCatch>
<Try>
<Assign To="strTo" Value='row("Email").ToString.Trim' />
<Assign To="strName" Value='row("HoTen").ToString.Trim' />
<Assign To="strBody"
Value='"Kính gửi anh/chị " + strName +
", đơn hàng của bạn đã được xác nhận."' />
<SendSMTPMail To="strTo"
Subject="Xac nhan don hang"
Body="strBody" />
<Assign To='row("TrangThai")' Value='"Sent"' />
</Try>
<Catch Exception="ex">
<Assign To='row("TrangThai")' Value='"Loi: " + ex.Message' />
<LogMessage Level="Error" Message='strTo + " that bai"' />
</Catch>
</TryCatch>
</ForEachRow>
<ExcelWriteRange DataTable="dtCustomers" SheetName="KetQua" />
</Sequence>
Bạn để ý: cấu trúc rất ngắn gọn nhưng đã có đủ đọc, lặp, ghép, gửi, bắt lỗi và ghi kết quả. Đó là khung xương bạn nên thuộc nằm lòng.
Tình huống thực tế
Tình huống 1 — Phòng khám nha khoa nhắc lịch hẹn (TP.HCM)
Một chuỗi phòng khám nha khoa có 4 cơ sở tại TP.HCM mỗi ngày có khoảng 120 lượt hẹn. Trước đây, lễ tân phải mở file Excel lịch hẹn của ngày hôm sau, copy từng email, dán vào Gmail và sửa tên thủ công. Trung bình mất 3 phút mỗi email, 120 hẹn là 6 giờ làm việc — và thực tế họ bỏ qua phân nửa vì không kịp.
Họ xây một bot UiPath đơn giản: cuối mỗi ngày lúc 18h, bot đọc file LichHen_NgayMai.xlsx (các cột: HoTen, Email, GioHen, BacSi, CoSo), lặp qua từng dòng, ghép câu nhắc kiểu "Chào anh/chị Minh, anh/chị có lịch hẹn lúc 9h30 ngày mai với BS. Hương tại cơ sở Quận 3", rồi gửi qua SMTP của Google Workspace công ty.
Diễn giải: điểm hay là họ thêm một cột TrangThai để bot ghi lại "Sent" hay "Loi". Sáng hôm sau lễ tân chỉ cần lọc các dòng "Loi" (thường là email gõ sai) để gọi điện nhắc tay. Tỷ lệ bệnh nhân quên hẹn (no-show) giảm từ 22% xuống còn 9% trong hai tháng.
Bài học: một bot "đọc Excel gửi email" tưởng tầm thường lại tạo ra giá trị kinh doanh rõ ràng (giảm no-show = tăng doanh thu). Và cột trạng thái biến bot từ "hộp đen" thành công cụ minh bạch, kiểm soát được.
Tình huống 2 — Công ty phân phối FMCG gửi sao kê công nợ (Hà Nội)
Một nhà phân phối hàng tiêu dùng có gần 800 đại lý. Mỗi đầu tháng, kế toán phải gửi cho từng đại lý một bảng sao kê công nợ riêng. Đây là kịch bản nâng cao hơn ví dụ 1, vì email cần đính kèm file PDF riêng cho từng đại lý.
Bot của họ làm thế này: đọc file CongNo_Thang.xlsx (cột MaDaiLy, TenDaiLy, Email, SoTienNo, FilePDF — trong đó FilePDF chứa đường dẫn tới file sao kê đã được tạo sẵn). Với mỗi dòng, bot kiểm tra file PDF có tồn tại không (File.Exists), nếu có thì đính kèm và gửi; nếu không thì ghi log và bỏ qua. Bot còn thêm một bước nghỉ 2 giây giữa mỗi email (Delay) để tránh bị máy chủ SMTP chặn vì gửi quá nhanh.
Diễn giải: với 800 email, nếu gửi ào ạt không nghỉ, Google hoặc Microsoft sẽ tạm khóa tài khoản vì nghi ngờ spam. Bước Delay và việc dùng tài khoản có giới hạn gửi đủ lớn (hoặc dịch vụ SMTP chuyên dụng như SendGrid, Amazon SES) là khác biệt giữa bot chạy được một lần và bot chạy được lâu dài.
Bài học: khi quy mô tăng, vấn đề không còn là logic mà là giới hạn hệ thống bên ngoài (rate limit, dung lượng đính kèm, danh tiếng người gửi). Một RPA developer giỏi phải nghĩ tới những ràng buộc này ngay từ đầu.
Tình huống 3 — Startup EdTech gửi mã kích hoạt khóa học
Một startup giáo dục trực tuyến chạy chương trình khuyến mãi, mỗi ngày có vài trăm học viên đăng ký và cần nhận mã kích hoạt qua email. Đội ngũ dùng Power Automate (vì họ đã có Microsoft 365) thay vì UiPath. Flow của họ: trigger theo lịch mỗi 30 phút, đọc một bảng Excel lưu trên OneDrive bằng action "List rows present in a table", lọc các dòng DaGui = No, gửi email qua Outlook, rồi cập nhật ô DaGui = Yes.
Diễn giải: điểm tinh tế nằm ở cột DaGui. Vì flow chạy mỗi 30 phút, nếu không đánh dấu dòng đã xử lý, lần chạy sau sẽ gửi lại mã cho cùng một học viên — gây trùng lặp và bối rối. Cột đánh dấu này (gọi là idempotency flag — cờ đảm bảo chạy lại không gây tác dụng kép) là kỹ thuật bắt buộc với mọi bot chạy theo lịch.
Bài học: UiPath hay Power Automate chỉ là công cụ; nguyên lý "đọc bảng, lọc việc chưa làm, làm, đánh dấu đã làm" là chung. Hiểu nguyên lý, bạn chuyển công cụ trong vài giờ.
Hướng dẫn từng bước
Hãy cùng dựng bot ví dụ 1 (nhắc lịch hẹn) trên UiPath Studio. Tôi sẽ mô tả theo trình tự thao tác để bạn làm theo được ngay.
Bước 1 — Chuẩn bị file Excel mẫu. Tạo KhachHang.xlsx với các cột ở dòng đầu: HoTen, Email, GioHen, BacSi. Nhập vài dòng dữ liệu thật (dùng email của chính bạn để test). Thêm một cột trống TrangThai.
Bước 2 — Tạo project mới. Mở UiPath Studio, chọn New > Process. Đặt tên rõ nghĩa như Bot_NhacLichHen.
Bước 3 — Đọc Excel. Kéo activity Excel Process Scope, bên trong đặt Use Excel File trỏ tới KhachHang.xlsx. Thêm Read Range, chọn Sheet1, để Range trống (đọc toàn bộ), bật AddHeaders, và lưu kết quả vào biến dtCustomers (kiểu DataTable).
Bước 4 — Lặp qua từng dòng. Kéo For Each Row in DataTable, nguồn là dtCustomers. Bên trong, các bước tiếp theo sẽ xử lý từng CurrentRow.
Bước 5 — Bọc bằng Try Catch. Ngay trong vòng lặp, đặt một Try Catch. Toàn bộ logic gửi email nằm trong khối Try. Mục tiêu: một email lỗi không làm chết cả bot.
Bước 6 — Lấy và làm sạch dữ liệu. Dùng Assign:
strTo = CurrentRow("Email").ToString.TrimstrName = CurrentRow("HoTen").ToString.TrimstrGio = CurrentRow("GioHen").ToString
.Trim xóa khoảng trắng thừa — nguyên nhân số một khiến email bị từ chối.Bước 7 — Kiểm tra email hợp lệ. Thêm một If: nếu String.IsNullOrEmpty(strTo) thì bỏ qua dòng này (gán TrangThai = "Thieu email" và Continue). Đừng để bot cố gửi tới ô trống.
Bước 8 — Ghép nội dung. Assign:
strBody = "Chào anh/chị " + strName + ", anh/chị có lịch hẹn lúc " + strGio + " với " + CurrentRow("BacSi").ToString + ". Vui lòng đến trước 10 phút. Xin cảm ơn!"
Bước 9 — Gửi email. Kéo Send SMTP Mail Message. Cấu hình Server (smtp.gmail.com), Port (587), bật SSL, nhập tài khoản và App Password (không phải mật khẩu thường — Gmail yêu cầu mật khẩu ứng dụng riêng). Trường To = strTo, Subject = "Nhac lich hen", Body = strBody.
Bước 10 — Ghi trạng thái. Sau khi gửi thành công, Assign CurrentRow("TrangThai") = "Sent". Trong khối Catch, gán CurrentRow("TrangThai") = "Loi: " + exception.Message và dùng Log Message mức Error.
Bước 11 — Ghi kết quả về Excel. Sau vòng lặp, dùng Write Range ghi dtCustomers trở lại file (hoặc một sheet "KetQua") để bạn xem dòng nào Sent, dòng nào Loi.
Bước 12 — Test với dữ liệu nhỏ rồi mới chạy thật. Chạy với 3 dòng (email của bạn) trước. Khi chắc chắn nội dung và định dạng đúng, mới mở rộng ra danh sách thật.
Lỗi thường gặp & mẹo
Quên Trim dữ liệu. Email copy từ Excel rất hay dính khoảng trắng đầu/cuối hoặc ký tự xuống dòng ẩn. " an@gmail.com " sẽ bị máy chủ từ chối. Luôn .Trim.
Truy cập sai tên cột. row("email") khác row("Email") — UiPath phân biệt hoa thường ở tên cột. Sai một chữ là lỗi "Column does not belong to table". Mẹo: copy chính xác tên header từ Excel.
Không có Try-Catch trong vòng lặp. Đây là lỗi kinh điển của người mới: dòng thứ 47 có email rỗng, bot ngã, 800 dòng còn lại không được gửi. Try-Catch bên trong vòng lặp giúp bot "vấp rồi đi tiếp".
Dùng mật khẩu thường cho Gmail/Outlook. Cả hai đều bắt buộc App Password hoặc OAuth. Nhập mật khẩu đăng nhập thường sẽ báo lỗi xác thực. Hãy tạo App Password trong phần bảo mật tài khoản.
Gửi quá nhanh dẫn tới bị chặn. Như ví dụ 2, thêm Delay 1–2 giây giữa các email, hoặc dùng dịch vụ SMTP chuyên gửi số lượng lớn (SendGrid, Amazon SES, Mailgun) khi vượt vài trăm email/ngày.
Không đánh dấu dòng đã gửi. Với bot chạy theo lịch, thiếu cờ DaGui/TrangThai sẽ gây gửi trùng. Luôn cập nhật trạng thái và lọc dòng chưa xử lý.
Hardcode đường dẫn và mật khẩu. Đừng nhúng C:\Users\Khang\... hay mật khẩu thẳng vào workflow. Dùng UiPath Assets/Orchestrator hoặc biến cấu hình để bot chạy được trên máy khác và an toàn hơn.
Mẹo nghiệm thu: trước khi chạy thật, sửa tạm trường To thành email của bạn cho mọi dòng để "diễn tập" — xem nội dung ghép có đúng không mà không làm phiền khách hàng thật.
Bài tập thực hành
- Dựng bot cơ bản: Tạo file Excel 5 dòng (dùng các email bạn kiểm soát được) và xây bot UiPath hoặc Power Automate gửi email cá nhân hóa "Chào anh/chị [Tên]". Chụp lại Inbox để xác nhận đã nhận đủ 5 email với đúng tên.
- Thêm xử lý lỗi: Cố tình để một dòng có email rỗng và một dòng email sai định dạng (
abc@). Bổ sung Try-Catch và cột TrangThai sao cho bot vẫn gửi 3 email hợp lệ và ghi rõ 2 dòng lỗi.
- Đính kèm file: Nâng cấp bot để mỗi khách hàng nhận một file PDF đính kèm theo đường dẫn trong cột FilePDF. Thêm bước kiểm tra
File.Existstrước khi gửi.
- Chạy theo lịch + chống trùng: Thêm cột
DaGui. Cấu hình bot chỉ gửi các dòngDaGui = Novà cập nhật thànhYessau khi gửi. Chạy bot hai lần liên tiếp và xác nhận lần hai không gửi lại email nào.
- Suy ngẫm: Viết ngắn (5–7 câu) về một quy trình trong công việc hoặc trường học của bạn có thể thay bằng bot "đọc Excel gửi email". Ước lượng nó tiết kiệm bao nhiêu giờ mỗi tuần.
Tóm tắt
Bài này biến lý thuyết RPA thành một bot chạy thật: đọc Excel vào DataTable, lặp qua từng dòng bằng For Each Row, lấy giá trị theo tên cột, ghép nội dung cá nhân hóa và gửi qua SMTP. Khung xương "đọc — lặp — lấy — ghép — gửi — ghi log" là mẫu tái sử dụng được cho hàng loạt quy trình văn phòng.
Ba điều cần khắc cốt: (1) luôn bọc logic gửi trong Try-Catch bên trong vòng lặp để một dòng hỏng không kéo sập cả bot; (2) luôn có cột trạng thái và cờ chống gửi trùng để bot minh bạch và an toàn khi chạy lại; (3) khi quy mô lớn, bài toán chuyển từ logic sang ràng buộc hệ thống — rate limit, App Password, dịch vụ SMTP chuyên dụng.
Ba tình huống thực tế — phòng khám nha khoa, nhà phân phối FMCG, startup EdTech — cho thấy cùng một nguyên lý áp dụng được trên cả UiPath lẫn Power Automate, và tạo ra giá trị kinh doanh đo đếm được. Nắm chắc bài này, bạn đã có một công cụ thật sự đầu tiên trong hộp đồ nghề RPA của mình.