#!/usr/bin/env python3 """ 邮件发送器 用于发送每日资讯摘要 """ import os import json import smtplib import logging from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from datetime import datetime from typing import List, Dict, Optional logger = logging.getLogger(__name__) class EmailSender: """邮件发送器""" def __init__(self, config_path=None): """初始化邮件发送器""" if config_path is None: config_path = "/home/ubuntu/nanocode/it_automation_enhanced/config/config.json" self.config_path = config_path self.load_config() # 检查配置 email_config = self.config.get('email', {}) if not email_config.get('smtp_host') or email_config.get('smtp_host', '').startswith('{{'): logger.warning("邮件配置不完整,邮件功能将禁用") def load_config(self): """加载配置""" try: with open(self.config_path, 'r', encoding='utf-8') as f: self.config = json.load(f) logger.info(f"邮件配置加载成功") except Exception as e: logger.error(f"配置加载失败: {e}") self.config = {} def send_email(self, subject: str, content: str, to_emails: List[str] = None, attachments: List[str] = None) -> bool: """发送邮件""" email_config = self.config.get('email', {}) # 检查是否启用 if not email_config.get('enable_daily_digest', True): logger.info("邮件功能已禁用") return False # 获取配置 smtp_host = email_config.get('smtp_host') smtp_port = email_config.get('smtp_port', 587) username = email_config.get('username') password = email_config.get('password') from_email = email_config.get('from_email') if not all([smtp_host, username, password, from_email]): logger.error("邮件配置不完整") return False if to_emails is None: to_emails = [email_config.get('to_email')] if not to_emails[0]: logger.error("收件人邮箱未配置") return False try: # 创建邮件 msg = MIMEMultipart() msg['From'] = from_email msg['To'] = ', '.join(to_emails) msg['Subject'] = subject msg['Date'] = datetime.now().strftime('%a, %d %b %Y %H:%M:%S %z') # 添加正文 msg.attach(MIMEText(content, 'html' if '' in content.lower() else 'plain', 'utf-8')) # 添加附件 if attachments: for attachment_path in attachments: if os.path.exists(attachment_path): with open(attachment_path, 'rb') as f: part = MIMEApplication(f.read(), Name=os.path.basename(attachment_path)) part['Content-Disposition'] = f'attachment; filename="{os.path.basename(attachment_path)}"' msg.attach(part) logger.info(f"添加附件: {attachment_path}") # 连接SMTP服务器并发送 logger.info(f"连接SMTP服务器: {smtp_host}:{smtp_port}") if smtp_port == 465: # SSL连接 server = smtplib.SMTP_SSL(smtp_host, smtp_port) else: # TLS连接 server = smtplib.SMTP(smtp_host, smtp_port) server.starttls() server.login(username, password) server.send_message(msg) server.quit() logger.info(f"邮件发送成功: {subject} -> {', '.join(to_emails)}") return True except Exception as e: logger.error(f"邮件发送失败: {e}") return False def create_daily_digest(self, articles: List[Dict], date: str = None) -> Dict: """创建每日摘要""" if date is None: date = datetime.now().strftime('%Y-%m-%d') # 统计信息 total_articles = len(articles) sources = {} categories = {} for article in articles: source = article.get('source', '未知') category = article.get('category', '未分类') sources[source] = sources.get(source, 0) + 1 categories[category] = categories.get(category, 0) + 1 # 创建HTML内容 html_content = f""" IT资讯每日摘要 - {date}

📰 IT资讯每日摘要

{date} | 共收录 {total_articles} 篇文章

📊 今日统计

文章总数

{total_articles}

来源分布

""" # 添加来源统计 for source, count in sources.items(): html_content += f'
{source}: {count}篇
' html_content += """

分类分布

""" # 添加分类统计 for category, count in categories.items(): html_content += f'
{category}: {count}篇
' html_content += f"""

📋 今日精选

""" # 添加文章列表(最多10篇) for i, article in enumerate(articles[:10]): title = article.get('title', '无标题') source = article.get('source', '未知') category = article.get('category', '未分类') url = article.get('url', '#') summary = article.get('summary', article.get('description', '暂无摘要')) html_content += f"""
{i+1}. {title}
{summary[:200]}...
""" html_content += """
""" # 创建纯文本版本 text_content = f"IT资讯每日摘要 - {date}\n" text_content += "=" * 50 + "\n\n" text_content += f"共收录 {total_articles} 篇文章\n\n" text_content += "来源统计:\n" for source, count in sources.items(): text_content += f" {source}: {count}篇\n" text_content += "\n分类统计:\n" for category, count in categories.items(): text_content += f" {category}: {count}篇\n" text_content += "\n精选文章:\n" for i, article in enumerate(articles[:5]): title = article.get('title', '无标题') source = article.get('source', '未知') text_content += f"{i+1}. {title} [{source}]\n" text_content += f"\n\n--\nIT资讯自动化系统 v1.0.0\n{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" return { 'date': date, 'total_articles': total_articles, 'sources': sources, 'categories': categories, 'html_content': html_content, 'text_content': text_content, 'subject': f"IT资讯每日摘要 - {date} ({total_articles}篇文章)" } def send_daily_digest(self, articles: List[Dict], date: str = None) -> bool: """发送每日摘要""" logger.info(f"准备发送每日摘要,文章数量: {len(articles)}") if not articles: logger.warning("没有文章可发送") return False # 创建摘要 digest = self.create_daily_digest(articles, date) # 发送邮件 success = self.send_email( subject=digest['subject'], content=digest['html_content'], to_emails=None # 使用配置中的收件人 ) if success: logger.info(f"每日摘要发送成功: {digest['subject']}") else: logger.error("每日摘要发送失败") return success def send_test_email(self): """发送测试邮件""" test_articles = [ { 'title': 'AI芯片技术的最新突破', 'source': 'TechNews', 'category': 'AI', 'url': 'https://example.com/ai-chip', 'summary': '研究人员在AI芯片能效比方面取得重大进展' }, { 'title': 'Python 3.12性能优化', 'source': 'PythonWeekly', 'category': '编程', 'url': 'https://example.com/python-optimize', 'summary': 'Python 3.12在性能方面有显著提升' }, { 'title': '云计算安全指南', 'source': 'CloudTech', 'category': '云计算', 'url': 'https://example.com/cloud-security', 'summary': '最新的云计算安全最佳实践' } ] print("发送测试邮件...") success = self.send_daily_digest(test_articles) if success: print("✅ 测试邮件发送成功") else: print("❌ 测试邮件发送失败(可能是配置问题)") return success def test_email_sender(): """测试邮件发送器""" import sys logging.basicConfig(level=logging.INFO) sender = EmailSender() # 检查配置 email_config = sender.config.get('email', {}) print("邮件配置检查:") for key, value in email_config.items(): if 'password' in key: print(f" {key}: [已隐藏]") else: print(f" {key}: {value}") print("\n发送测试邮件...") sender.send_test_email() if __name__ == "__main__": test_email_sender()