想象这样一个场景:
你的自动化脚本运行了一个小时,终于处理完了1000份Excel报表。
但你不知道它什么时候跑完的——你一直在刷手机等它。
更尴尬的是:
这就是 Day4 要解决的问题:让你的程序"开口说话"。
通知是自动化的"最后一公里"——没有通知的自动化,就像发射了火箭却不看落点。
为什么邮件是最佳选择?
邮件是职场"最大公约数"——每个人都会用,每个公司都有。
Python 内置 smtplib 和 email 库,无需安装额外依赖就能发邮件。
发送邮件需要以下信息(以 QQ 邮箱为例):
SMTP服务器:smtp.qq.com SMTP端口:465(SSL)或 587(TLS) 邮箱账号:你的QQ号@qq.com 授权码:在QQ邮箱设置中开启SMTP服务后获取 获取授权码的步骤:
其他邮箱的 SMTP 设置:
import smtplib from email.mime.text import MIMEText from email.header import Header # 配置 SMTP_SERVER = "smtp.qq.com" SMTP_PORT = 465 EMAIL_USER = "123456789@qq.com" # 替换为你的邮箱 EMAIL_PASS = "abcdefghijklmnop" # 替换为你的授权码 # 创建邮件 msg = MIMEText("这是一封测试邮件,来自 Python 自动化脚本。", "plain", "utf-8") msg["From"] = f"自动化脚本<{EMAIL_USER}>" msg["To"] = "收件人邮箱@example.com" msg["Subject"] = Header("自动化测试邮件", "utf-8") # 发送 with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: server.login(EMAIL_USER, EMAIL_PASS) server.sendmail(EMAIL_USER, ["收件人邮箱@example.com"], msg.as_string()) print("邮件发送成功!") 运行这段代码,收件人会收到一封纯文本邮件。
纯文本太朴素,我们可以发送带格式的 HTML 邮件:
from email.mime.text import MIMEText from email.header import Header import smtplib SMTP_SERVER = "smtp.qq.com" SMTP_PORT = 465 EMAIL_USER = "your_qq@qq.com" EMAIL_PASS = "your_auth_code" # HTML 内容 html_content = """ <html> <head><style> body { font-family: 'Microsoft YaHei', sans-serif; line-height: 1.6; } h2 { color: #1565C0; } .highlight { background: #FFF3CD; padding: 2px 6px; border-radius: 4px; } .footer { color: #666; font-size: 12px; margin-top: 20px; } </style></head> <body> <h2>📊 日报数据已生成</h2> <p>您好,<span class="highlight">今日的数据处理任务已完成</span>。</p> <p><strong>处理时间:</strong>2026-04-10 14:30</p> <p><strong>数据条数:</strong>1,247 条</p> <p><strong>文件位置:</strong>/reports/daily_2026-04-10.xlsx</p> <hr> <p class="footer">此邮件由自动化脚本发送</p> </body> </html> """ msg = MIMEText(html_content, "html", "utf-8") msg["From"] = f"数据机器人<{EMAIL_USER}>" msg["To"] = "manager@company.com" msg["Subject"] = Header("【日报】数据处理完成通知", "utf-8") with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: server.login(EMAIL_USER, EMAIL_PASS) server.sendmail(EMAIL_USER, ["manager@company.com"], msg.as_string()) print("HTML 邮件发送成功!") HTML 邮件的优势:
报表做完了,直接作为附件发出去:
from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders from email.header import Header import smtplib import os SMTP_SERVER = "smtp.qq.com" SMTP_PORT = 465 EMAIL_USER = "your_qq@qq.com" EMAIL_PASS = "your_auth_code" def send_email_with_attachment(to_email, subject, body, attachment_path): """ 发送带附件的邮件 """ # 创建多部分邮件 msg = MIMEMultipart() msg["From"] = f"报表系统<{EMAIL_USER}>" msg["To"] = to_email msg["Subject"] = Header(subject, "utf-8") # 添加邮件正文 msg.attach(MIMEText(body, "plain", "utf-8")) # 添加附件 if attachment_path and os.path.exists(attachment_path): with open(attachment_path, "rb") as f: attachment = MIMEBase("application", "octet-stream") attachment.set_payload(f.read()) encoders.encode_base64(attachment) filename = os.path.basename(attachment_path) attachment.add_header( "Content-Disposition", f'attachment; filename="{filename}"' ) msg.attach(attachment) print(f"已添加附件:{filename}") # 发送 with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: server.login(EMAIL_USER, EMAIL_PASS) server.sendmail(EMAIL_USER, [to_email], msg.as_string()) print(f"邮件已发送至:{to_email}") # 使用示例 send_email_with_attachment( to_email="team@company.com", subject="【周报】销售数据报表", body="各位好,\n\n本周销售数据报表已生成,请查收附件。\n\n自动化报表系统", attachment_path="reports/sales_weekly_2026_04.xlsx" ) 给多个部门发同样的报告?用循环搞定:
def batch_send_emails(recipient_list, subject, body, attachment_path=None): """ 批量发送邮件 recipient_list: [(姓名, 邮箱), ...] """ success_count = 0 fail_count = 0 for name, email in recipient_list: try: # 个性化正文(替换姓名) personalized_body = body.replace("{{姓名}}", name) if attachment_path: send_email_with_attachment(email, subject, personalized_body, attachment_path) else: # 发送纯文本邮件 msg = MIMEText(personalized_body, "plain", "utf-8") msg["From"] = f"通知系统<{EMAIL_USER}>" msg["To"] = email msg["Subject"] = Header(subject, "utf-8") with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: server.login(EMAIL_USER, EMAIL_PASS) server.sendmail(EMAIL_USER, [email], msg.as_string()) print(f"✓ 发送成功:{name} ({email})") success_count += 1 except Exception as e: print(f"✗ 发送失败:{name} ({email}) - {str(e)}") fail_count += 1 print(f"\n发送完成:成功 {success_count} 封,失败 {fail_count} 封") return success_count, fail_count # 收件人列表 recipients = [ ("张经理", "zhang@company.com"), ("李主管", "li@company.com"), ("王总监", "wang@company.com"), ] # 批量发送 batch_send_emails( recipient_list=recipients, subject="【重要】月度运营会议通知", body="{{姓名}}您好,\n\n月度运营会议将于明天下午 2:00 举行,请准时参加。\n\n行政部", ) 把邮件发送整合到你的自动化脚本中:
import pandas as pd from datetime import datetime def process_data_and_notify(): """ 处理数据并发送通知邮件 """ print("开始处理数据...") # 1. 读取数据 df = pd.read_excel("raw_data.xlsx") total_rows = len(df) # 2. 清洗处理 df = df.dropna() df["日期"] = pd.to_datetime(df["日期"]) processed_rows = len(df) # 3. 保存结果 output_file = f"cleaned_data_{datetime.now().strftime('%Y%m%d')}.xlsx" df.to_excel(output_file, index=False) # 4. 发送通知邮件 summary = f""" 数据处理任务完成报告 处理时间:{datetime.now().strftime('%Y-%m-%d %H:%M')} 原始数据:{total_rows} 条 处理后:{processed_rows} 条 异常数据:{total_rows - processed_rows} 条 输出文件:{output_file} 请查收附件中的处理结果。 """ send_email_with_attachment( to_email="manager@company.com", subject=f"【数据处理】{datetime.now().strftime('%m月%d日')} 数据清洗完成", body=summary, attachment_path=output_file ) print("处理完成并已发送通知邮件!") # 运行 process_data_and_notify() 监控脚本检测到问题,立刻发邮件告警:
import time def monitor_and_alert(): """ 监控系统状态,异常时发送告警邮件 """ max_retries = 3 for attempt in range(max_retries): try: # 模拟监控检查 check_system_status() print(f"检查 #{attempt + 1}:系统正常") time.sleep(60) # 每分钟检查一次 except Exception as e: error_msg = f"系统异常告警!\n\n时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n错误:{str(e)}\n重试次数:{attempt + 1}/{max_retries}" print(f"⚠️ 检测到异常:{str(e)}") # 发送告警邮件 msg = MIMEText(error_msg, "plain", "utf-8") msg["From"] = f"监控系统<{EMAIL_USER}>" msg["To"] = "ops@company.com" msg["Subject"] = Header("【紧急】系统异常告警", "utf-8") with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: server.login(EMAIL_USER, EMAIL_PASS) server.sendmail(EMAIL_USER, ["ops@company.com"], msg.as_string()) print("告警邮件已发送!") if attempt < max_retries - 1: time.sleep(5) # 等待5秒后重试 else: print("已达到最大重试次数,停止监控") break def check_system_status(): """模拟系统检查""" import random if random.random() < 0.1: # 10% 概率报错 raise Exception("数据库连接超时") # 运行监控 monitor_and_alert() 结合 Windows 任务计划程序或 Linux cron,定时发送邮件:
def daily_report_scheduler(): """ 每日报告生成和发送 建议配合任务调度器定时运行 """ today = datetime.now() # 检查是否是工作日(跳过周末) if today.weekday() >= 5: # 5=周六, 6=周日 print("今天是周末,跳过日报发送") return print(f"生成 {today.strftime('%Y-%m-%d')} 日报...") # 生成报告(这里用你的实际逻辑) report_path = generate_daily_report(today) # 发送邮件 send_email_with_attachment( to_email="team@company.com", subject=f"【日报】{today.strftime('%m月%d日')} 运营数据", body=f"各位好,\n\n{today.strftime('%Y年%m月%d日')}日报已生成,请查收。\n\n此邮件由自动化脚本发送", attachment_path=report_path ) print("日报发送完成!") def generate_daily_report(date): """生成日报(模拟)""" # 这里替换为你的实际数据生成逻辑 report_file = f"daily_report_{date.strftime('%Y%m%d')}.xlsx" # ... 生成报告的逻辑 ... return report_file # 运行 if __name__ == "__main__": daily_report_scheduler() Windows 定时任务设置:
python,参数:daily_report.py复杂邮件用 Jinja2 模板:
from jinja2 import Template email_template = """ <h2>Hello {{ name }},</h2> <p>Your daily report for <strong>{{ date }}</strong> is ready.</p> <table border="1" cellpadding="5"> <tr><th>Metric</th><th>Value</th></tr> <tr><td>Total Sales</td><td>${{ total_sales }}</td></tr> <tr><td>New Orders</td><td>{{ new_orders }}</td></tr> <tr><td>Conversion</td><td>{{ conversion }}%</td></tr> </table> <p>Please find the detailed report attached.</p> """ data = { "name": "Manager", "date": "2026-04-10", "total_sales": 15230, "new_orders": 47, "conversion": 3.2 } template = Template(email_template) html_body = template.render(**data) # 然后用 html_body 发送邮件 记录发送历史,方便追踪:
import json from datetime import datetime def log_email_sent(to_email, subject, status, error=None): """ 记录邮件发送日志 """ log_entry = { "timestamp": datetime.now().isoformat(), "to": to_email, "subject": subject, "status": status, "error": error } log_file = "email_log.json" try: with open(log_file, "r", encoding="utf-8") as f: logs = json.load(f) except FileNotFoundError: logs = [] logs.append(log_entry) with open(log_file, "w", encoding="utf-8") as f: json.dump(logs, f, ensure_ascii=False, indent=2) # 使用示例 log_email_sent("user@example.com", "测试邮件", "success") 今天我们学了:
1. Python 发邮件基础
2. 批量邮件发送
3. 实战场景
4. 高级技巧
完成以下任务,巩固今天的内容:
Day5:会议纪要智能整理 —— 自动录音转文字、提取待办、生成纪要。
我们会用到 AI 语音识别 + 自然语言处理,敬请期待!
💡 系列回顾
- Day1:Excel 批量清洗
- Day2:Word 批量排版
- Day3:PPT 自动生成
- Day4:邮件通知自动化 ✅
关注「量子位开发手记」,每天解锁一个办公自动化技能