Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 3 — Kết nối hộp thư: IMAP, Gmail API & xác thực an toàn

Đã đọc 0/9 mục · còn khoảng 3 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Giờ ta chạm vào hộp thư thật. Bài này giúp bạn lấy được email mới một cách an toàn — nền tảng cho tầng Ingest và Normalize.

Chọn giao thức: IMAP hay Gmail API

Tiêu chíIMAPGmail API
Phổ quát (mọi provider)CóChỉ Gmail
Gắn nhãn / labelHạn chếMạnh, gốc rễ
Tạo nháp (draft)Không chuẩnCó endpoint riêng
Xác thựcApp passwordOAuth2
Độ khóThấpTrung bình
Lời khuyên: nếu bạn dùng Gmail/Google Workspace, hãy dùng Gmail API — nó hỗ trợ label và draft đúng chuẩn, cực hợp cho triage. IMAP tốt khi bạn phải hỗ trợ nhiều provider (Outlook, Yahoo, mail công ty).

Nguyên tắc xác thực an toàn

  • Không bao giờ nhúng mật khẩu vào code. Dùng biến môi trường hoặc secret manager.
  • Dùng App Password / OAuth, không dùng mật khẩu chính của tài khoản.
  • Chỉ xin quyền tối thiểu. Với Gmail API, gmail.modify đủ để đọc + gắn nhãn + tạo nháp mà KHÔNG cho quyền xóa vĩnh viễn.
  • Tài khoản test riêng cho giai đoạn phát triển.

Ví dụ: lấy email chưa đọc qua IMAP (Python)

import imaplib, email, os
from email.header import decode_header

M = imaplib.IMAP4_SSL("imap.gmail.com")
M.login(os.environ["MAIL_USER"], os.environ["MAIL_APP_PASS"])
M.select("INBOX")

# Chỉ lấy email CHƯA đọc để tránh xử lý lặp
status, ids = M.search(None, "UNSEEN")
for num in ids[0].split()[:20]:        # giới hạn 20/lần cho an toàn
    _, data = M.fetch(num, "(RFC822)")
    msg = email.message_from_bytes(data[0][1])
    subject = decode_header(msg["Subject"])[0][0]
    print(subject, "|", msg["From"])
M.logout()

Ví dụ: liệt kê email mới qua Gmail API

results = service.users().messages().list(
    userId="me",
    q="is:unread newer_than:1d",
    maxResults=20
).execute()
for m in results.get("messages", []):
    full = service.users().messages().get(
        userId="me", id=m["id"], format="full"
    ).execute()
    # full["payload"]["headers"] chứa From, Subject...

Chuẩn hóa (Normalize) email

Email thô rất bẩn: HTML, chữ ký dài, chuỗi "Re: Re: Fwd:", trích dẫn thư cũ. Trước khi đưa vào LLM, hãy:

  • Bóc plain text từ HTML (ưu tiên phần text/plain).
  • Cắt phần trích dẫn thư cũ (mọi dòng bắt đầu bằng > hoặc sau "On ... wrote:").
  • Cắt chữ ký (thường sau --).
  • Giới hạn độ dài body gửi vào LLM (vd 2000 ký tự đầu) để tiết kiệm token.
  • Giữ metadata: from, subject, ngày, có đính kèm không.

Các bước thực hành

  • Tạo App Password (Gmail) hoặc OAuth client (Gmail API).
  • Lưu credential vào biến môi trường, thêm .env vào .gitignore.
  • Viết hàm fetch_unread(limit=20) trả về danh sách email đã chuẩn hóa.
  • Đánh dấu email đã xử lý (đọc, hoặc gắn nhãn agent-seen) để không lặp.
  • Test: in ra 5 email chuẩn hóa, kiểm tra body sạch, không còn HTML.

Checklist kết nối

  • [ ] Credential nằm ngoài code (env / secret).
  • [ ] Dùng quyền tối thiểu (gmail.modify, không full).
  • [ ] Có cơ chế chống xử lý lặp (UNSEEN / label seen).
  • [ ] Body đã bóc HTML + cắt trích dẫn + cắt chữ ký.
  • [ ] Giới hạn số email mỗi lần chạy.

Sai lầm thường gặp

  • Commit mật khẩu/token lên Git. Rò rỉ tức thì. Luôn dùng env + .gitignore.
  • Xin quyền gmail.full hoặc quyền xóa khi chỉ cần đọc/gắn nhãn — vi phạm nguyên tắc quyền tối thiểu và rủi ro lớn nếu agent lỗi.
  • Gửi cả HTML thô vào LLM. Tốn token gấp 5–10 lần và làm LLM nhiễu, phân loại kém.
  • Không chống lặp, khiến mỗi lần cron chạy lại xử lý cùng email — spam nháp, gắn nhãn trùng.
  • Xử lý hàng trăm email cùng lúc ngay lần đầu. Giới hạn 20 để dễ quan sát và giới hạn thiệt hại nếu sai.
Bài sau: thiết kế prompt phân loại cho ra JSON ổn định và chính xác.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi