CrewAI mạnh ở chỗ điều phối nhiều Agent làm việc cùng nhau, nhưng sức mạnh thật sự bộc lộ khi bạn kết nối nó với các công cụ hàng ngày: Slack, Gmail, Calendar… Thay vì mở email mỗi sáng rồi tự lọc, tự phân loại, bạn để crew làm chuyện đó. Crew đọc email, tóm tắt, phân loại theo mức ưu tiên, rồi gửi kết quả về Slack cho bạn.

Bài này hướng dẫn cách kết nối CrewAI với Slack và Gmail, kèm ví dụ crew tóm tắt email buổi sáng hoàn chỉnh. Nếu bạn chưa quen CrewAI, đọc bài giới thiệu CrewAI từ A-Z trước. Bài trước về triển khai CrewAI với Docker trên VPS cũng liên quan vì cuối bài mình sẽ nói về cách lên lịch chạy tự động.

Tự động hoá với CrewAI: bức tranh tổng quan

Tự động hoá với CrewAI: bức tranh tổng quan

Khi nói “tự động hoá” với CrewAI, mình đang nói về việc cho crew chạy tự động dựa trên trigger (sự kiện kích hoạt) hoặc lịch trình, thay vì phải gõ lệnh chạy thủ công mỗi lần.

Có 3 cách phổ biến để tự động hoá crew:

  • Trigger từ ứng dụng bên ngoài: Slack gửi tin nhắn mới, Gmail nhận email, webhook từ hệ thống khác. CrewAI Enterprise có sẵn tính năng Triggers cho Slack và Gmail. Với bản open-source, bạn tự viết code lắng nghe sự kiện
  • Chạy theo lịch (cron): Mỗi sáng 8h crew tự chạy, đọc email, tóm tắt, gửi kết quả về Slack. Dùng cron trên server hoặc scheduler trong Python
  • Qua no-code platform: Zapier, Make (Integromat) có sẵn integration với CrewAI. Bạn tạo workflow kéo thả: “Khi có email mới → kickoff crew → gửi kết quả về Slack”

Bài này tập trung vào cách tự code (open-source), vì nó linh hoạt nhất và bạn kiểm soát được toàn bộ logic. Cách tiếp cận: viết Python script kết nối Slack qua webhook, Gmail qua IMAP/API, rồi dùng CrewAI orchestrate phần xử lý.

Kết nối CrewAI với Slack

Kết nối CrewAI với Slack

Slack là kênh nhận kết quả phổ biến nhất khi chạy crew tự động. Bạn có thể dùng Slack theo 2 hướng: gửi kết quả crew về Slack (output), hoặc dùng Slack làm trigger kích hoạt crew (input).

Gửi kết quả về Slack qua Incoming Webhook

Cách đơn giản nhất: tạo Incoming Webhook trên Slack, rồi crew gửi HTTP POST về webhook URL đó.

Bước 1: Tạo Slack App và Webhook

  • Vào api.slack.com/apps → Create New App → From Scratch
  • Đặt tên app (ví dụ: “CrewAI Bot”), chọn workspace
  • Vào mục Incoming Webhooks → bật toggle → Add New Webhook to Workspace
  • Chọn channel nhận tin (ví dụ: #crewai-reports)
  • Copy Webhook URL, dạng: https://hooks.slack.com/services/T.../B.../xxx

Bước 2: Viết tool gửi Slack trong CrewAI

import os
import requests
from crewai.tools import tool

@tool("Gửi tin nhắn Slack") def send_slack_message(message: str) -> str: """Gửi tin nhắn về kênh Slack qua webhook.""" webhook_url = os.getenv("SLACK_WEBHOOK_URL") if not webhook_url: return "Lỗi: chưa cấu hình SLACK_WEBHOOK_URL"

# Slack webhook nhận JSON với key "text" response = requests.post( webhook_url, json={"text": message}, timeout=10 )

if response.status_code == 200: return "Đã gửi tin nhắn Slack thành công" return f"Lỗi gửi Slack: {response.status_code} - {response.text}"

Thêm biến SLACK_WEBHOOK_URL vào file .env. Agent nào cần gửi kết quả về Slack thì gắn tool này vào:

from crewai import Agent
reporter = Agent(
    role="Báo cáo viên",
    goal="Tóm tắt và gửi báo cáo về Slack",
    backstory="Chuyên tổng hợp thông tin thành bản tóm tắt ngắn gọn.",
    tools=[send_slack_message],
    verbose=True
)

Dùng Slack làm trigger khởi chạy crew

CrewAI Enterprise có sẵn Slack Trigger: bạn gõ /kickoff trong Slack channel, chọn crew, crew tự chạy và trả kết quả về channel. Rất tiện cho team dùng chung.

Với bản open-source, bạn cần tự build. Cách phổ biến nhất: chạy một Flask/FastAPI server nhận Slack Events (hoặc Slash Commands), rồi gọi crew.kickoff():

from fastapi import FastAPI, Request
from your_crew import MyCrew

app = FastAPI()

@app.post("/slack/events") async def handle_slack_event(request: Request): data = await request.json()

# Xác minh từ Slack (challenge verification) if "challenge" in data: return {"challenge": data["challenge"]}

event = data.get("event", {}) # Lọc tin nhắn có keyword "run crew" if event.get("type") == "message" and "run crew" in event.get("text", ""): # Chạy crew trong background (tránh timeout 3s của Slack) import threading thread = threading.Thread( target=lambda: MyCrew().crew().kickoff() ) thread.start() return {"ok": True}

return {"ok": True}

⚠️ Slack yêu cầu server phản hồi trong 3 giây. Nếu crew chạy lâu hơn (thường là vậy), bạn phải chạy crew trong background thread hoặc task queue (Celery, RQ). Phản hồi Slack ngay, rồi gửi kết quả sau qua webhook.

Kết nối CrewAI với Gmail

Kết nối CrewAI với Gmail

Gmail là nguồn dữ liệu đầu vào giàu nhất cho crew tự động. Bạn cho crew đọc email, phân loại (quan trọng, spam, newsletter…), tóm tắt nội dung, thậm chí tạo draft trả lời.

Cách 1: Dùng IMAP (đơn giản, không cần OAuth)

IMAP là giao thức đọc email chuẩn. Gmail hỗ trợ IMAP, bạn chỉ cần bật IMAP trong settings và tạo App Password (mật khẩu ứng dụng).

Tạo App Password cho Gmail:

  • Vào myaccount.google.com/security
  • Bật xác minh 2 bước (2-Step Verification) nếu chưa bật
  • Tìm mục “App passwords” → tạo password mới cho “Mail”
  • Copy password 16 ký tự, lưu vào .env
import imaplib
import email
from email.header import decode_header
import os

def fetch_recent_emails(num_emails=10): """Đọc email gần nhất từ Gmail qua IMAP.""" # Kết nối Gmail IMAP mail = imaplib.IMAP4_SSL("imap.gmail.com") mail.login( os.getenv("GMAIL_ADDRESS"), os.getenv("GMAIL_APP_PASSWORD") ) mail.select("inbox")

# Tìm email chưa đọc (hoặc ALL cho tất cả) status, messages = mail.search(None, "UNSEEN") email_ids = messages[0].split()[-num_emails:] # Lấy N email gần nhất

results = [] for eid in email_ids: _, msg_data = mail.fetch(eid, "(RFC822)") msg = email.message_from_bytes(msg_data[0][1])

# Giải mã tiêu đề subject, encoding = decode_header(msg["Subject"])[0] if isinstance(subject, bytes): subject = subject.decode(encoding or "utf-8")

sender = msg.get("From", "") date = msg.get("Date", "")

# Lấy nội dung text body = "" if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True).decode("utf-8", errors="ignore") break else: body = msg.get_payload(decode=True).decode("utf-8", errors="ignore")

results.append({ "subject": subject, "from": sender, "date": date, "body": body[:2000] # Giới hạn 2000 ký tự mỗi email })

mail.logout() return results

Cách 2: Dùng Gmail API (OAuth2, mạnh hơn)

Gmail API cho phép đọc, gửi, gắn label, tạo draft. Mạnh hơn IMAP nhưng setup phức tạp hơn vì cần OAuth2 consent flow. Phù hợp nếu bạn muốn crew thực hiện nhiều hành động trên Gmail (gắn label, archive, reply).

💡 Nếu chỉ cần đọc email và tóm tắt, IMAP là đủ và đơn giản hơn nhiều. Gmail API phù hợp khi bạn muốn crew tự gắn label, archive email, hoặc tạo draft trả lời.

Cách 3: CrewAI Enterprise Gmail Trigger

Nếu dùng CrewAI Enterprise (deploy trên CrewAI platform), bạn bật Gmail Trigger trong dashboard. Khi có email mới, platform tự gọi crew và truyền nội dung email vào qua crewai_trigger_payload. Test local bằng lệnh:

# Xem danh sách triggers có sẵn
crewai triggers list
# Giả lập Gmail trigger để test
crewai triggers run gmail/new_email_received

Cách này nhanh nhất nhưng yêu cầu trả phí CrewAI Enterprise. Bài này mình sẽ dùng IMAP vì miễn phí và ai cũng có thể làm.

Tạo crew tóm tắt email buổi sáng

Tạo crew tóm tắt email buổi sáng

Đây là ví dụ hoàn chỉnh: crew chạy mỗi sáng, đọc 20 email chưa đọc, phân loại theo mức ưu tiên, tóm tắt nội dung, rồi gửi báo cáo về Slack.

Cấu trúc project

morning-email-crew/
├── main.py              # Entry point
├── agents.py            # Định nghĩa agents
├── tasks.py             # Định nghĩa tasks
├── tools.py             # Gmail + Slack tools
├── requirements.txt
└── .env                 # API keys

File tools.py

import os
import json
import imaplib
import email
from email.header import decode_header
import requests
from crewai.tools import tool

@tool("Đọc email Gmail") def read_gmail_emails(num_emails: int = 20) -> str: """Đọc email chưa đọc từ Gmail, trả về danh sách JSON.""" mail = imaplib.IMAP4_SSL("imap.gmail.com") mail.login(os.getenv("GMAIL_ADDRESS"), os.getenv("GMAIL_APP_PASSWORD")) mail.select("inbox")

status, messages = mail.search(None, "UNSEEN") email_ids = messages[0].split()[-num_emails:]

results = [] for eid in email_ids: _, msg_data = mail.fetch(eid, "(RFC822)") msg = email.message_from_bytes(msg_data[0][1])

subject, enc = decode_header(msg["Subject"])[0] if isinstance(subject, bytes): subject = subject.decode(enc or "utf-8")

body = "" if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True).decode("utf-8", errors="ignore") break else: body = msg.get_payload(decode=True).decode("utf-8", errors="ignore")

results.append({ "subject": subject, "from": msg.get("From", ""), "date": msg.get("Date", ""), "body": body[:1500] })

mail.logout() return json.dumps(results, ensure_ascii=False, indent=2)

@tool("Gửi báo cáo Slack") def send_slack_report(report: str) -> str: """Gửi báo cáo tóm tắt email về Slack channel.""" webhook_url = os.getenv("SLACK_WEBHOOK_URL") if not webhook_url: return "Lỗi: chưa set SLACK_WEBHOOK_URL"

# Format tin nhắn Slack với blocks cho dễ đọc payload = { "text": f"📧 *Báo cáo email buổi sáng*\n\n{report}" } resp = requests.post(webhook_url, json=payload, timeout=10)

if resp.status_code == 200: return "Đã gửi báo cáo Slack thành công" return f"Lỗi: {resp.status_code}"

File agents.py

from crewai import Agent
from tools import read_gmail_emails, send_slack_report

# Agent đọc và phân loại email email_classifier = Agent( role="Chuyên gia phân loại email", goal="Đọc email và phân loại theo mức ưu tiên: cao, trung bình, thấp", backstory=( "Bạn là trợ lý email giàu kinh nghiệm. " "Bạn biết phân biệt email quan trọng (từ đối tác, khách hàng, " "deadline) với email ít quan trọng (newsletter, quảng cáo, thông báo tự động)." ), tools=[read_gmail_emails], verbose=True )

# Agent tóm tắt và gửi báo cáo summarizer = Agent( role="Chuyên gia tóm tắt", goal="Tóm tắt email thành báo cáo ngắn gọn và gửi về Slack", backstory=( "Bạn giỏi viết tóm tắt súc tích. " "Mỗi email chỉ cần 1-2 dòng nêu ý chính. " "Nhóm email theo mức ưu tiên để người đọc biết xử lý cái nào trước." ), tools=[send_slack_report], verbose=True )

File tasks.py

from crewai import Task
from agents import email_classifier, summarizer

# Task 1: Đọc và phân loại email classify_task = Task( description=( "Đọc 20 email chưa đọc gần nhất từ Gmail. " "Phân loại mỗi email thành 3 mức ưu tiên:\n" "- CAO: từ đối tác, khách hàng, có deadline, yêu cầu phản hồi gấp\n" "- TRUNG BÌNH: cần đọc nhưng không gấp\n" "- THẤP: newsletter, quảng cáo, thông báo tự động\n" "Với mỗi email, ghi lại: người gửi, tiêu đề, mức ưu tiên, lý do." ), expected_output=( "Danh sách email đã phân loại theo mức ưu tiên, " "mỗi email có: người gửi, tiêu đề, mức ưu tiên, lý do phân loại." ), agent=email_classifier )

# Task 2: Tóm tắt và gửi Slack summarize_task = Task( description=( "Dựa trên kết quả phân loại, viết báo cáo tóm tắt gồm:\n" "1. Số lượng email theo từng mức ưu tiên\n" "2. Danh sách email ưu tiên CAO (tóm tắt 1-2 dòng mỗi email)\n" "3. Danh sách email ưu tiên TRUNG BÌNH (chỉ tiêu đề + người gửi)\n" "4. Số lượng email ưu tiên THẤP (không cần liệt kê chi tiết)\n" "Gửi báo cáo này về Slack." ), expected_output="Báo cáo tóm tắt email đã được gửi về Slack.", agent=summarizer, context=[classify_task] # Nhận kết quả từ task phân loại )

File main.py

from crewai import Crew, Process
from dotenv import load_dotenv
from tasks import classify_task, summarize_task
from agents import email_classifier, summarizer

load_dotenv()

crew = Crew( agents=[email_classifier, summarizer], tasks=[classify_task, summarize_task], process=Process.sequential, # Phân loại xong mới tóm tắt verbose=True )

if __name__ == "__main__": result = crew.kickoff() print("Kết quả crew:") print(result)

File .env

# LLM provider
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx

# Gmail (IMAP) GMAIL_ADDRESS=your-email@gmail.com GMAIL_APP_PASSWORD=xxxx xxxx xxxx xxxx

# Slack webhook SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxx

Chạy thử:

# Cài dependencies
pip install crewai crewai-tools python-dotenv requests
# Chạy crew
python main.py

Kết quả: bạn nhận được tin nhắn Slack tóm tắt email buổi sáng, nhóm theo mức ưu tiên, biết ngay cần xử lý email nào trước. Nếu muốn tìm hiểu thêm về cách agent phối hợp trong crew, xem bài về CrewTask.

Lên lịch chạy tự động với cron và Docker

Chạy tự động với cron và Docker

Crew chạy thủ công thì chưa gọi là “tự động hoá”. Bạn cần lên lịch để nó chạy đều đặn mà không cần nhớ.

Cách 1: Cron trên server (đơn giản nhất)

# Mở crontab
crontab -e
# Chạy crew tóm tắt email mỗi sáng 7h30 (giờ Việt Nam)
30 7 * * * cd /opt/morning-email-crew && /usr/bin/python3 main.py >> /var/log/email-crew.log 2>&1

Cách 2: Cron + Docker (khuyên dùng cho production)

Nếu đã đóng gói crew bằng Docker (xem bài Docker + VPS), kết hợp cron với Docker Compose:

# Container chạy xong tự xoá, không tích lũy container thừa
30 7 * * * cd /opt/morning-email-crew && docker compose run --rm crewai-app >> /var/log/email-crew.log 2>&1

Cách 3: APScheduler trong Python (không cần cron)

Nếu muốn giữ logic lịch trình trong code Python (tiện khi deploy trên platform không có cron):

from apscheduler.schedulers.blocking import BlockingScheduler
from main import crew

scheduler = BlockingScheduler(timezone="Asia/Ho_Chi_Minh")

@scheduler.scheduled_job('cron', hour=7, minute=30) def morning_email_job(): print("Bắt đầu crew tóm tắt email...") result = crew.kickoff() print(f"Hoàn thành: {result}")

scheduler.start()

💡 Nếu bạn cần VPS ổn định để chạy crew tự động 24/7, AZDIGI Pro VPS là lựa chọn phù hợp: ổ NVMe tốc độ cao, uptime ổn định, hỗ trợ kỹ thuật 24/7.

Các kịch bản tự động hoá khác

Các kịch bản tự động hoá khác

Slack và Gmail chỉ là khởi đầu. CrewAI có thể kết nối với hầu như bất kỳ dịch vụ nào có API. Dưới đây là vài kịch bản thực tế mà mình thấy nhiều người áp dụng:

Google Calendar: chuẩn bị trước cuộc họp

Crew đọc lịch Calendar, tìm cuộc họp sắp tới, research thông tin về người tham dự và chủ đề, rồi gửi bản tóm tắt chuẩn bị về Slack 30 phút trước cuộc họp. CrewAI Enterprise có sẵn tính năng này (crew “prep-for-meeting”).

HubSpot/CRM: phân tích lead mới

Khi có lead mới vào CRM, crew tự động research công ty đó (website, LinkedIn, tin tức), đánh giá mức độ phù hợp, viết gợi ý email tiếp cận cho sales team. Dùng webhook từ HubSpot trigger crew.

Notion: tổng hợp báo cáo tuần

Crew đọc dữ liệu từ Notion database (tasks hoàn thành, KPIs), tổng hợp thành báo cáo tuần, tự tạo page mới trong Notion với nội dung báo cáo. Dùng Notion API để đọc/ghi dữ liệu.

Giám sát đối thủ tự động

Crew chạy hàng ngày, scrape website đối thủ, so sánh giá, phát hiện thay đổi, gửi báo cáo về Slack hoặc email. Kết hợp tools scraping với Flow để xử lý pipeline phức tạp.

ℹ️ Nguyên tắc chung: bất kỳ dịch vụ nào có REST API đều có thể viết thành custom tool cho CrewAI. Xem bài Tool trong CrewAI để biết cách tạo custom tool.

Bài tiếp theo trong serie sẽ nói về Testing và Training, giúp bạn đánh giá và cải thiện chất lượng agent theo thời gian.

Câu hỏi thường gặp

CrewAI kết nối Slack có cần Slack trả phí không?

Không. Incoming Webhooks hoạt động trên cả Slack free plan. Bạn tạo Slack App, bật Incoming Webhooks, lấy webhook URL là dùng được. Chỉ cần lưu ý free plan giới hạn lịch sử tin nhắn 90 ngày.

Dùng IMAP đọc Gmail có an toàn không?

An toàn nếu bạn dùng App Password thay vì mật khẩu chính. App Password chỉ cho phép truy cập email qua IMAP, không thể đăng nhập Google Account. Lưu App Password trong file .env, phân quyền chmod 600, và không đưa vào git.

Mỗi lần crew đọc email tốn bao nhiêu token?

Phụ thuộc vào số email và độ dài nội dung. Với 20 email ngắn (mỗi email ~200 từ), tổng input khoảng 5000-8000 token. Cộng output tóm tắt khoảng 1000-2000 token. Chi phí khoảng $0.01-0.05 mỗi lần chạy nếu dùng GPT-4o-mini, hoặc $0.05-0.20 nếu dùng GPT-4o.

CrewAI Enterprise khác gì bản open-source trong việc tự động hoá?

CrewAI Enterprise có sẵn Triggers (Slack, Gmail, webhook), dashboard quản lý, deploy một nút, monitoring tích hợp. Bản open-source bạn tự code phần trigger, tự deploy, tự monitor. Chức năng core (Agent, Task, Crew, Tools) giống nhau. Enterprise tiết kiệm thời gian setup, open-source linh hoạt hơn.

Có thể dùng email khác ngoài Gmail không (Outlook, Yahoo)?

Có. Code IMAP trong bài hoạt động với bất kỳ email provider nào hỗ trợ IMAP. Thay đổi IMAP server address: Outlook dùng outlook.office365.com, Yahoo dùng imap.mail.yahoo.com. Phần còn lại giữ nguyên.


Tự động hoá bằng CrewAI mở ra rất nhiều khả năng. Từ việc đơn giản như tóm tắt email mỗi sáng, đến phức tạp hơn như giám sát đối thủ hay chuẩn bị trước cuộc họp. Chìa khoá là xác định workflow lặp đi lặp lại hàng ngày, rồi biến nó thành crew chạy tự động.

Nếu bạn muốn crew chạy ổn định hơn, bài tiếp theo về Testing và Training trong CrewAI sẽ hướng dẫn cách đánh giá hiệu suất agent và cải thiện chất lượng output qua từng lần chạy. Ngoài ra, nếu cần VPS để chạy crew tự động, AZDIGI Pro VPS phù hợp cho workloads kiểu này: NVMe nhanh, uptime cao, hỗ trợ kỹ thuật 24/7.

Chia sẻ:
Bài viết đã được kiểm duyệt bởi AZDIGI Team

Về tác giả

Trần Thắng

Trần Thắng

Chuyên gia tại AZDIGI với nhiều năm kinh nghiệm trong lĩnh vực web hosting và quản trị hệ thống.

Hơn 10 năm phục vụ 80.000+ khách hàng

Bắt đầu dự án web của bạn với AZDIGI