菜单

使用cursor开发QQ邮箱邮件自动清理脚本

发布于 2025年07月04日

1、下载安装cursor

https://cursor.com/

2、提示词如下

提示词1:

qq邮箱自动清理来自指定发送人的邮件 ,开发一个python脚本帮我实现这个功能。

提示词2:

继续完善一下脚本,实现运行脚本时,不删除最近3天收到的邮件,最好可以在配置文件中自定义删除几天以前的

3、编辑配置文件

cursor生成了一个配置文件和2个脚本文件,配置文件如下

[EMAIL]
# 您的QQ邮箱地址
email = your_email@qq.com

# 几天前及更早的邮件会被删除,默认3天
days_before_delete = 3 
# QQ邮箱授权码(不是登录密码)
# 获取方法:登录QQ邮箱 -> 设置 -> 账户 -> POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 -> 开启IMAP/SMTP服务
password = your_app_password

# 要删除邮件的发送人邮箱地址,多个用逗号分隔
target_senders = spam@example.com,advertisement@company.com,newsletter@service.com

# 是否永久删除邮件(False=移动到垃圾箱,True=永久删除)
delete_permanently = False

# 是否模拟运行(True=只显示要删除的邮件,不实际删除;False=实际删除)
dry_run = True 

4、类 脚本如下

#!/usr/bin python3
# -*- coding: utf-8 -*-
"""
QQ邮箱自动清理工具
自动删除来自指定发送人的邮件
"""

import imaplib
import email
import os
import configparser
from email.header import decode_header
from datetime import datetime
import logging

class QQEmailCleaner:
    def __init__(self, config_file='email_config.ini'):
        """
        初始化QQ邮箱清理器
        
        Args:
            config_file (str): 配置文件路径
        """
        self.config_file = config_file
        self.config = self.load_config()
        self.imap_server = 'imap.qq.com'
        self.imap_port = 993
        self.mail = None
        
        # 设置日志
        self.setup_logging()
        
    def setup_logging(self):
        """设置日志配置"""
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler('email_cleaner.log', encoding='utf-8'),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger(__name__)
        
    def load_config(self):
        """加载配置文件"""
        config = configparser.ConfigParser()
        
        if os.path.exists(self.config_file):
            config.read(self.config_file, encoding='utf-8')
        else:
            # 创建默认配置
            config['EMAIL'] = {
                'email': 'your_email@qq.com',
                'password': 'your_app_password',
                'target_senders': 'sender1@example.com,sender2@example.com',
                'delete_permanently': 'False',
                'dry_run': 'True',
                'days_before_delete': '3'
            }
            
            with open(self.config_file, 'w', encoding='utf-8') as f:
                config.write(f)
                
            print(f"已创建配置文件: {self.config_file}")
            print("请编辑配置文件,填入您的邮箱信息")
            
        return config
        
    def connect_to_mailbox(self):
        """连接到QQ邮箱"""
        try:
            self.mail = imaplib.IMAP4_SSL(self.imap_server, self.imap_port)
            email_address = self.config['EMAIL']['email']
            password = self.config['EMAIL']['password']
            
            self.mail.login(email_address, password)
            self.logger.info(f"成功连接到邮箱: {email_address}")
            return True
            
        except Exception as e:
            self.logger.error(f"连接邮箱失败: {str(e)}")
            return False
            
    def disconnect(self):
        """断开邮箱连接"""
        if self.mail:
            try:
                self.mail.logout()
                self.logger.info("已断开邮箱连接")
            except Exception as e:
                self.logger.error(f"断开连接时出错: {str(e)}")
                
    def get_sender_emails(self, sender):
        """获取指定发送人的邮件ID列表"""
        try:
            if not self.mail:
                self.logger.error("邮箱连接未建立")
                return []
                
            # 选择收件箱
            self.mail.select('INBOX')
            
            # 搜索来自指定发送人的邮件
            search_criteria = f'FROM "{sender}"'
            status, message_ids = self.mail.search(None, search_criteria)
            
            if status == 'OK' and message_ids and message_ids[0]:
                email_ids = message_ids[0].split()
                self.logger.info(f"找到来自 {sender} 的邮件 {len(email_ids)} 封")
                return email_ids
            else:
                self.logger.info(f"未找到来自 {sender} 的邮件")
                return []
                
        except Exception as e:
            self.logger.error(f"搜索邮件时出错: {str(e)}")
            return []
            
    def get_email_info(self, email_id):
        """获取邮件信息"""
        try:
            if not self.mail:
                return None
                
            status, msg_data = self.mail.fetch(email_id, '(RFC822)')
            if status == 'OK' and msg_data and len(msg_data) > 0:
                email_body = msg_data[0][1]
                if isinstance(email_body, bytes):
                    email_message = email.message_from_bytes(email_body)
                    
                    # 解析邮件头信息
                    subject = decode_header(email_message['subject'])[0][0]
                    if isinstance(subject, bytes):
                        subject = subject.decode('utf-8', errors='ignore')
                        
                    from_addr = decode_header(email_message['from'])[0][0]
                    if isinstance(from_addr, bytes):
                        from_addr = from_addr.decode('utf-8', errors='ignore')
                        
                    date = email_message['date']
                    
                    return {
                        'subject': subject,
                        'from': from_addr,
                        'date': date
                    }
        except Exception as e:
            self.logger.error(f"获取邮件信息时出错: {str(e)}")
            
        return None
        
    def delete_emails(self, email_ids, dry_run=True, days_before_delete=3):
        """删除邮件,只删除N天前的邮件"""
        deleted_count = 0
        
        if not self.mail:
            self.logger.error("邮箱连接未建立")
            return deleted_count
        
        now = datetime.now()
        
        for email_id in email_ids:
            try:
                # 获取邮件信息用于日志
                email_info = self.get_email_info(email_id)
                
                # 判断邮件日期
                skip = False
                if email_info and email_info['date']:
                    try:
                        # 解析邮件日期
                        from email.utils import parsedate_to_datetime
                        mail_date = parsedate_to_datetime(email_info['date'])
                        if mail_date.tzinfo is not None:
                            mail_date = mail_date.astimezone().replace(tzinfo=None)
                        days_diff = (now - mail_date).days
                        if days_diff < days_before_delete:
                            skip = True
                    except Exception as e:
                        self.logger.warning(f"解析邮件日期失败: {email_info['date']},跳过此邮件。错误: {str(e)}")
                        skip = True
                if skip:
                    self.logger.info(f"[跳过] 邮件ID: {email_id.decode()},日期: {email_info['date'] if email_info else '未知'},未达到删除天数")
                    continue
                
                if dry_run:
                    self.logger.info(f"[模拟删除] 邮件ID: {email_id.decode()}")
                    if email_info:
                        self.logger.info(f"  主题: {email_info['subject']}")
                        self.logger.info(f"  发件人: {email_info['from']}")
                        self.logger.info(f"  日期: {email_info['date']}")
                    deleted_count += 1
                else:
                    # 实际删除邮件
                    self.mail.store(email_id, '+FLAGS', '\\Deleted')
                    self.logger.info(f"[已删除] 邮件ID: {email_id.decode()}")
                    if email_info:
                        self.logger.info(f"  主题: {email_info['subject']}")
                        self.logger.info(f"  发件人: {email_info['from']}")
                    deleted_count += 1
                    
            except Exception as e:
                self.logger.error(f"删除邮件时出错: {str(e)}")
                
        # 如果实际删除,则执行expunge
        if not dry_run and deleted_count > 0:
            try:
                self.mail.expunge()
                self.logger.info("已永久删除邮件")
            except Exception as e:
                self.logger.error(f"永久删除邮件时出错: {str(e)}")
                
        return deleted_count
        
    def clean_emails(self):
        """清理邮件主函数"""
        if not self.connect_to_mailbox():
            return
            
        try:
            # 获取目标发送人列表
            target_senders = self.config['EMAIL']['target_senders'].split(',')
            target_senders = [sender.strip() for sender in target_senders if sender.strip()]
            
            if not target_senders:
                self.logger.warning("未配置目标发送人")
                return
                
            dry_run = self.config['EMAIL'].getboolean('dry_run', True)
            delete_permanently = self.config['EMAIL'].getboolean('delete_permanently', False)
            days_before_delete = int(self.config['EMAIL'].get('days_before_delete', 3))
            
            total_deleted = 0
            
            for sender in target_senders:
                self.logger.info(f"开始处理来自 {sender} 的邮件...")
                
                # 获取该发送人的所有邮件
                email_ids = self.get_sender_emails(sender)
                
                if email_ids:
                    # 删除邮件
                    deleted_count = self.delete_emails(email_ids, dry_run, days_before_delete)
                    total_deleted += deleted_count
                    
                    if dry_run:
                        self.logger.info(f"模拟删除完成,共 {deleted_count} 封邮件")
                    else:
                        self.logger.info(f"删除完成,共 {deleted_count} 封邮件")
                        
            self.logger.info(f"清理完成,总共处理 {total_deleted} 封邮件")
            
        except Exception as e:
            self.logger.error(f"清理邮件时出错: {str(e)}")
        finally:
            self.disconnect()
            
    def list_folders(self):
        """列出所有邮件文件夹"""
        if not self.connect_to_mailbox():
            return
            
        try:
            status, folders = self.mail.list()
            if status == 'OK':
                self.logger.info("邮件文件夹列表:")
                for folder in folders:
                    folder_name = folder.decode().split('"')[-2]
                    self.logger.info(f"  - {folder_name}")
        except Exception as e:
            self.logger.error(f"获取文件夹列表时出错: {str(e)}")
        finally:
            self.disconnect()
            
    def get_email_count(self, folder='INBOX'):
        """获取指定文件夹的邮件数量"""
        if not self.connect_to_mailbox():
            return 0
            
        try:
            self.mail.select(folder)
            status, messages = self.mail.search(None, 'ALL')
            if status == 'OK':
                count = len(messages[0].split())
                self.logger.info(f"{folder} 文件夹共有 {count} 封邮件")
                return count
        except Exception as e:
            self.logger.error(f"获取邮件数量时出错: {str(e)}")
        finally:
            self.disconnect()
            
        return 0


def main():
    """主函数"""
    print("QQ邮箱自动清理工具")
    print("=" * 50)
    
    cleaner = QQEmailCleaner()
    
    while True:
        print("\n请选择操作:")
        print("1. 清理指定发送人的邮件")
        print("2. 查看邮件文件夹列表")
        print("3. 查看收件箱邮件数量")
        print("4. 退出")
        
        choice = input("\n请输入选择 (1-4): ").strip()
        
        if choice == '1':
            print("\n开始清理邮件...")
            cleaner.clean_emails()
            
        elif choice == '2':
            print("\n获取文件夹列表...")
            cleaner.list_folders()
            
        elif choice == '3':
            print("\n获取收件箱邮件数量...")
            cleaner.get_email_count()
            
        elif choice == '4':
            print("退出程序")
            break
            
        else:
            print("无效选择,请重新输入")


if __name__ == "__main__":
    main()

5、调用脚本如下

#!/usr/bin python3
# -*- coding: utf-8 -*-
"""
QQ邮箱清理工具 - 快速开始示例
"""

from clear_qq_email import QQEmailCleaner

def quick_clean_example():
    """快速清理示例"""
    print("QQ邮箱清理工具 - for cursor")
    print("=" * 50)
    
    # 创建清理器实例
    cleaner = QQEmailCleaner()
    
    # 示例1: 查看收件箱邮件数量
    print("\n1. 查看收件箱邮件数量...")
    cleaner.get_email_count()
    
    # 示例2: 查看邮件文件夹列表
    print("\n2. 查看邮件文件夹列表...")
    cleaner.list_folders()
    
    # 示例3: 模拟清理邮件(不会实际删除)
    print("\n3. 清理邮件...")
   # print("注意:这是模拟运行,不会实际删除邮件")
    cleaner.clean_emails()
    
    print("\n清理完成!")
   # print("请编辑 email_config.ini 文件配置您的邮箱信息")

if __name__ == "__main__":
    quick_clean_example() 

7、最后,可以设置定时任务来将清理邮件

mkdir /opt/clear_email

crontab -e 

#每周一6点运行
0 6 * * 1 /usr/bin/python3 /opt/clear_email/quick_start.py >> /opt/clear_email/run.log 2>&1
systemctl restart crond

7、生成的readme文件如下

# QQ邮箱自动清理工具

这是一个用于自动清理QQ邮箱中指定发送人邮件的Python脚本。

## 功能特性

- 🔍 自动搜索指定发送人的邮件
- 🗑️ 支持批量删除邮件
- 📝 详细的日志记录
- 🛡️ 模拟运行模式,安全预览删除操作
- ⚙️ 配置文件管理,方便设置
- 📊 查看邮箱文件夹和邮件数量

## 安装要求

- Python 3.6+
- 标准库模块(无需额外安装包)

## 使用方法

### 1. 获取QQ邮箱授权码

1. 登录您的QQ邮箱
2. 进入 **设置** → **账户**
3. 找到 **POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务**
4. 开启 **IMAP/SMTP服务**
5. 按照提示获取授权码(不是登录密码)

### 2. 配置脚本

1. 编辑 `email_config.ini` 文件:
   ```ini
   [EMAIL]
   email = your_email@qq.com
   password = your_app_password
   target_senders = spam@example.com,advertisement@company.com
   delete_permanently = False
   dry_run = True
   days_before_delete = 3
   ```

2. 配置说明:
   - `email`: 您的QQ邮箱地址
   - `password`: QQ邮箱授权码
   - `target_senders`: 要删除邮件的发送人,多个用逗号分隔
   - `delete_permanently`: 是否永久删除(False=移动到垃圾箱)
   - `dry_run`: 是否模拟运行(True=预览,False=实际删除)
   - `days_before_delete`: 只删除几天前的邮件(默认3,3表示只删除3天前及更早的邮件,3天内新邮件不会被删除)

### 3. 运行脚本

```



评论