207 lines
7.3 KiB
Python
207 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
邮件摘要脚本 - 每天早上9点推送前一天的邮件摘要
|
||
重点关注 fj@77ircloud.com 的邮件
|
||
需要回应的邮件会标记提醒
|
||
|
||
⚠️ 安全规则:此脚本仅读取邮件,不执行任何删除操作
|
||
"""
|
||
|
||
import imaplib
|
||
import ssl
|
||
import email
|
||
from email.header import decode_header
|
||
from datetime import datetime, timedelta
|
||
|
||
def decode_str(s):
|
||
if s is None:
|
||
return ''
|
||
parts = decode_header(s)
|
||
result = []
|
||
for part, charset in parts:
|
||
if isinstance(part, bytes):
|
||
charset = charset or 'utf-8'
|
||
try:
|
||
result.append(part.decode(charset, errors='replace'))
|
||
except:
|
||
result.append(part.decode('utf-8', errors='replace'))
|
||
else:
|
||
result.append(part)
|
||
return ''.join(result)
|
||
|
||
def get_body_preview(msg, max_len=200):
|
||
"""获取邮件正文预览"""
|
||
try:
|
||
if msg.is_multipart():
|
||
for part in msg.walk():
|
||
if part.get_content_type() == 'text/plain':
|
||
payload = part.get_payload(decode=True)
|
||
if payload:
|
||
charset = part.get_content_charset() or 'utf-8'
|
||
body = payload.decode(charset, errors='replace')
|
||
return body[:max_len].replace('\n', ' ').strip()
|
||
else:
|
||
payload = msg.get_payload(decode=True)
|
||
if payload:
|
||
charset = msg.get_content_charset() or 'utf-8'
|
||
body = payload.decode(charset, errors='replace')
|
||
return body[:max_len].replace('\n', ' ').strip()
|
||
except:
|
||
pass
|
||
return ''
|
||
|
||
def needs_response(subject, body, sender):
|
||
"""判断邮件是否需要回应"""
|
||
text = (subject + ' ' + body).lower()
|
||
sender_lower = sender.lower()
|
||
|
||
# 需要回应的关键词
|
||
response_keywords = [
|
||
'请回复', '请回复我', '需回复', '需要回复',
|
||
'请回复确认', '请回复一下', '请回复告知',
|
||
'请确认', '请批准', '请审核', '请审批',
|
||
'期待回复', '希望回复', '烦请', '麻烦',
|
||
'请知悉', '请查收', '请查阅',
|
||
'请协助', '请配合', '请支持', '请安排', '请处理',
|
||
]
|
||
|
||
# 重要发件人
|
||
important_senders = ['fj@77ircloud.com']
|
||
|
||
return any(kw in text for kw in response_keywords) or any(s in sender_lower for s in important_senders)
|
||
|
||
def fetch_yesterday_emails():
|
||
"""获取昨天的邮件"""
|
||
try:
|
||
context = ssl.create_default_context()
|
||
mail = imaplib.IMAP4_SSL('imap.exmail.qq.com', 993, ssl_context=context)
|
||
mail.login('lgc@77ircloud.com', 'bVPPcg6XgB7qRPw7')
|
||
|
||
mail.select('INBOX')
|
||
status, messages = mail.search(None, 'ALL')
|
||
email_ids = messages[0].split()
|
||
|
||
yesterday = (datetime.now() - timedelta(days=1)).date()
|
||
|
||
all_emails = []
|
||
important_emails = []
|
||
need_response_emails = []
|
||
|
||
# 扫描最近50封
|
||
scan_range = email_ids[-50:] if len(email_ids) >= 50 else email_ids
|
||
|
||
for uid in reversed(scan_range):
|
||
try:
|
||
# 获取完整邮件(头部+正文)
|
||
status, msg_data = mail.fetch(uid, '(RFC822)')
|
||
if not msg_data or not msg_data[0]:
|
||
continue
|
||
|
||
raw_email = msg_data[0][1]
|
||
if isinstance(raw_email, tuple):
|
||
raw_email = raw_email[1]
|
||
|
||
msg = email.message_from_bytes(raw_email)
|
||
|
||
subject = decode_str(msg.get('Subject', '(无主题)'))
|
||
sender = decode_str(msg.get('From', ''))
|
||
date_str = msg.get('Date', '')
|
||
|
||
# 解析日期
|
||
try:
|
||
t = email.utils.parsedate_tz(date_str)
|
||
if t:
|
||
local_dt = datetime.fromtimestamp(email.utils.mktime_tz(t))
|
||
email_date = local_dt.date()
|
||
else:
|
||
continue
|
||
except:
|
||
continue
|
||
|
||
# 只取昨天的邮件
|
||
if email_date != yesterday:
|
||
continue
|
||
|
||
body = get_body_preview(msg, 300)
|
||
|
||
email_info = {
|
||
'subject': subject,
|
||
'sender': sender,
|
||
'date': date_str,
|
||
'body': body,
|
||
}
|
||
|
||
all_emails.append(email_info)
|
||
|
||
# 重点关注
|
||
if 'fj@77ircloud.com' in sender:
|
||
important_emails.append(email_info)
|
||
|
||
# 需要回应
|
||
if needs_response(subject, body, sender):
|
||
need_response_emails.append(email_info)
|
||
|
||
except Exception as e:
|
||
continue
|
||
|
||
mail.logout()
|
||
return all_emails, important_emails, need_response_emails, yesterday.strftime('%Y年%m月%d日')
|
||
|
||
except Exception as e:
|
||
return [], [], [], str(e)
|
||
|
||
def format_summary():
|
||
"""格式化邮件摘要"""
|
||
emails, important, need_response, date_str = fetch_yesterday_emails()
|
||
|
||
if isinstance(important, str):
|
||
return f"⚠️ 获取邮件失败: {important}"
|
||
|
||
if not emails:
|
||
return f"📬 {date_str} 无新邮件\n\n祝你一天好心情!😊"
|
||
|
||
lines = [f"📬 {date_str} 邮件摘要\n"]
|
||
lines.append(f"共收到 **{len(emails)}** 封邮件\n")
|
||
|
||
# 需要回应的邮件(最优先)
|
||
if need_response:
|
||
lines.append(f"🔔 **需要您回应({len(need_response)} 封)**\n")
|
||
lines.append("─" * 40)
|
||
for i, mail in enumerate(need_response, 1):
|
||
lines.append(f" {i}. 📧 {mail['subject']}")
|
||
lines.append(f" 发件人: {mail['sender']}")
|
||
if mail.get('body'):
|
||
lines.append(f" 摘要: {mail['body'][:150]}...")
|
||
lines.append("")
|
||
|
||
# 重点关注(排除已标记需要回应的)
|
||
important_only = [e for e in important if e not in need_response]
|
||
if important_only:
|
||
lines.append(f"⭐ **重点关注(fj@77ircloud.com)({len(important_only)} 封)**\n")
|
||
lines.append("─" * 40)
|
||
for i, mail in enumerate(important_only, 1):
|
||
lines.append(f" {i}. 📧 {mail['subject']}")
|
||
lines.append(f" 发件人: {mail['sender']}")
|
||
lines.append("")
|
||
|
||
# 其他邮件
|
||
other = [e for e in emails if e not in important and e not in need_response]
|
||
if other:
|
||
lines.append(f"\n📋 **其他邮件({len(other)} 封)**\n")
|
||
lines.append("─" * 40)
|
||
for i, mail in enumerate(other[:8], 1):
|
||
lines.append(f" {i}. 📧 {mail['subject']}")
|
||
lines.append(f" 发件人: {mail['sender']}")
|
||
lines.append("")
|
||
if len(other) > 8:
|
||
lines.append(f" ... 还有 {len(other) - 8} 封邮件")
|
||
|
||
lines.append("\n" + "=" * 40)
|
||
lines.append("💡 提示:以上标记「需要回应」的邮件,请及时处理!")
|
||
|
||
return "\n".join(lines)
|
||
|
||
if __name__ == '__main__':
|
||
print(format_summary())
|