Explore all courses in this category.
Explore all courses in this category.
Nguyễn Đình Cường
0 comment
09 Nov, 2026
Mỗi sáng bạn phải gửi cùng một báo cáo cho nhóm? Python có thể làm việc đó thay bạn: soạn nội dung, đính kèm file và gửi email theo lịch. Bài này hướng dẫn dùng thư viện chuẩn smtplib và email, kèm các nguyên tắc để giữ mật khẩu an toàn.
SMTP là giao thức gửi thư. Chương trình của bạn kết nối đến máy chủ SMTP của nhà cung cấp email, xác thực bằng tài khoản, rồi chuyển thư đi. Với kết nối mã hóa, cổng 465 dùng SSL ngay từ đầu, còn cổng 587 dùng STARTTLS để nâng cấp kết nối. Thông số chính xác (máy chủ, cổng) tùy nhà cung cấp, hãy xem tài liệu của họ.
Nhiều dịch vụ email không cho dùng mật khẩu chính của tài khoản cho ứng dụng bên thứ ba, mà yêu cầu bật xác minh hai bước rồi tạo mật khẩu ứng dụng riêng, hoặc dùng cơ chế OAuth. Hãy dùng tài khoản email dành riêng cho việc gửi tự động, tuyệt đối không viết mật khẩu vào mã nguồn. Ta sẽ đọc nó từ biến môi trường.
import os
import smtplib
import ssl
from email.message import EmailMessage
from pathlib import Path
SMTP_HOST = os.environ["SMTP_HOST"] # ví dụ: smtp.example.com
SMTP_PORT = int(os.environ.get("SMTP_PORT", "465"))
SMTP_USER = os.environ["SMTP_USER"]
SMTP_PASS = os.environ["SMTP_PASS"]Đặt biến môi trường trước khi chạy (ví dụ trên Linux hoặc macOS dùng export SMTP_PASS=..., trên PowerShell dùng $env:SMTP_PASS = "..."). Nếu thiếu biến, chương trình báo KeyError ngay từ đầu, dễ phát hiện lỗi cấu hình.
def send_email(to, subject, text, html=None, attachments=()):
msg = EmailMessage()
msg["From"] = SMTP_USER
msg["To"] = to
msg["Subject"] = subject
msg.set_content(text)
if html:
msg.add_alternative(html, subtype="html")
for path in attachments:
p = Path(path)
data = p.read_bytes()
msg.add_attachment(
data,
maintype="application",
subtype="octet-stream",
filename=p.name,
)
context = ssl.create_default_context()
with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT, context=context) as server:
server.login(SMTP_USER, SMTP_PASS)
server.send_message(msg)Giải thích: EmailMessage xử lý mã hóa tiếng Việt UTF-8 giúp bạn. Bản văn bản thuần là bắt buộc, còn bản HTML là tùy chọn; client email sẽ chọn bản phù hợp. Ngữ cảnh SSL mặc định kiểm tra chứng chỉ của máy chủ. Nếu nhà cung cấp dùng cổng 587 với STARTTLS, thay khối with bằng smtplib.SMTP, gọi starttls(context=context) rồi mới login.
Giả sử báo cáo là thống kê đơn giản từ file CSV. Ví dụ bên dưới đọc số dòng và tạo bản tóm tắt:
import csv
from datetime import date
def build_report(csv_path):
with open(csv_path, newline="", encoding="utf-8-sig") as f:
rows = list(csv.DictReader(f))
total = len(rows)
return total
if __name__ == "__main__":
total = build_report("orders.csv")
today = date.today().strftime("%d/%m/%Y")
send_email(
to="nhom@example.com",
subject=f"Báo cáo đơn hàng ngày {today}",
text=f"Xin chào,\n\nHôm nay có {total} đơn hàng.\n\nTrân trọng.",
html=f"<p>Xin chào,</p><p>Hôm nay có <strong>{total}</strong> đơn hàng.</p>",
attachments=["orders.csv"],
)
print("Đã gửi.")Không nên để chương trình tự lặp vô hạn bằng time.sleep. Hãy dùng bộ lập lịch của hệ điều hành:
crontab -e, ví dụ 0 8 * * 1-5 /đường/dẫn/venv/bin/python /đường/dẫn/report.py để chạy 8 giờ sáng các ngày trong tuần.python.exe kèm đường dẫn script.Khi chạy từ trình lập lịch, môi trường khác với terminal của bạn: hãy dùng đường dẫn tuyệt đối và bảo đảm biến môi trường có sẵn (ví dụ khai báo trong file cấu hình của dịch vụ).
smtplib.SMTPException và ghi log để biết vì sao gửi thất bại.Với vài chục dòng Python, bạn có hệ thống gửi báo cáo tự động: cấu hình qua biến môi trường, thư HTML kèm tệp, chạy theo lịch. Cùng một nền tảng này, bạn có thể gửi cảnh báo lỗi, nhắc việc hoặc tóm tắt dữ liệu mỗi ngày.
Để học Python tự động hóa công việc một cách bài bản, hãy xem các khóa học tại codebem.com.
Nguyễn Đình Cường
0 comment