1.正文带图片 

# 导入相关模块
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

# 定义一个函数,用于发邮件和发图片,用qq邮箱发送,图片在正文显示
def send_email_with_image(sender, password, receiver, subject, content, image_file):
    """
    sender: 发件人邮箱
    password: 发件人邮箱密码或授权码
    receiver: 收件人邮箱
    subject: 邮件主题
    content: 邮件内容
    image_file: 图片文件名
    """
    # 创建一个带附件的邮件实例
    msg = MIMEMultipart()
    msg["From"] = sender # 设置发件人
    msg["To"] = receiver # 设置收件人
    msg["Subject"] = subject # 设置主题

    # 创建邮件正文,使用HTML格式,并插入邮件内容和图片
    body = f"""
    <p>{content}</p>
    <p>Here is the image:</p>
    <p><img src="cid:image1"></p>
    """
    msg.attach(MIMEText(body, "html")) # 将正文添加到邮件实例中

    # 指定图片文件的路径,打开并读取为二进制数据
    fp = open(image_file, "rb")
    img = MIMEImage(fp.read())
    fp.close()

    # 定义图片的ID,在HTML文本中引用
    img.add_header("Content-ID", "<image1>")
    msg.attach(img) # 将图片添加到邮件实例中

    # 创建一个SMTP对象,连接到QQ邮箱的服务器
    smtp = smtplib.SMTP_SSL("smtp.qq.com", 465)
    smtp.login(sender, password) # 登录发件人邮箱
    smtp.sendmail(sender, receiver, msg.as_string()) # 发送邮件
    smtp.quit() # 退出SMTP对象

    print("Email sent successfully.") # 打印发送成功的提示信息

# 调用函数,传入相应的参数
send_email_with_image("your_qq_email@qq.com", "your_qq_email_password", "someone_email@domain.com", "This is a test email with image", "Hi, this is a test email with image.", "test.jpg")

2.删除邮件

 

import imaplib
import email # 虽然在这个删除场景中email库不是必须的,但引入是标准做法

def delete_emails_combined(EMAIL_ACCOUNT, PASSWORD, inbox_subject_keyword=None):
    """
    连接邮箱,删除收件箱中主题包含指定关键词的邮件,
    并删除发件箱中的所有邮件。

    Args:
        EMAIL_ACCOUNT (str): 邮箱账号。
        PASSWORD (str): 邮箱的IMAP授权码。
        inbox_subject_keyword (str, optional): 收件箱邮件主题中需要匹配的关键词。
                                                如果为None或空字符串,则不删除收件箱邮件。
    """
    # QQ邮箱的IMAP服务器信息
    IMAP_SERVER = 'imap.qq.com'
    IMAP_PORT = 993

    mail = None # 初始化 mail 对象为 None

    try:
        # 连接到IMAP服务器
        print(f"正在连接到 {IMAP_SERVER}:{IMAP_PORT}...")
        mail = imaplib.IMAP4_SSL(IMAP_SERVER, IMAP_PORT)
        print("连接成功.")

        # 登录到邮箱
        print(f"尝试登录邮箱账户: {EMAIL_ACCOUNT}...")
        # mail.login() 返回状态和响应数据
        login_status, login_response = mail.login(EMAIL_ACCOUNT, PASSWORD)
        print(f"登录状态: {login_status}, 响应: {login_response}")
        if login_status != 'OK':
            print("登录失败. 请检查邮箱账号和授权码是否正确.")
            # 如果需要,可以打印更详细的登录失败响应
            # print(f"登录响应详情: {login_response}")
            return # 登录失败,停止执行

        print("登录成功.")

        # --- 处理收件箱邮件 ---
        if inbox_subject_keyword:
            print(f"\n--- 正在处理收件箱,查找主题包含 '{inbox_subject_keyword}' 的邮件 ---")
            try:
                # 选择收件箱
                print("正在选择 'inbox' 文件夹...")
                status, mail_count_inbox = mail.select('inbox')
                print(f"选择 Inbox 状态: {status}")
                if status == 'OK':
                    # 搜索所有标题包含指定关键词的邮件
                    # 搜索条件需要编码为 bytes
                    search_criteria = f'(SUBJECT "{inbox_subject_keyword}")'.encode('utf-8')
                    print(f"正在搜索条件: {search_criteria}...")
                    status, data = mail.search(None, search_criteria)
                    print(f"搜索状态: {status}, 数据长度: {len(data[0]) if data and data[0] else 0}")

                    if status == 'OK' and data[0]:
                        # 获取邮件ID列表
                        mail_ids_bytes = data[0]
                        mail_ids = mail_ids_bytes.split()
                        print(f"找到 {len(mail_ids)} 封邮件符合条件.")

                        # 删除邮件
                        deleted_count = 0
                        print("正在标记收件箱邮件以删除...")
                        for mail_id in mail_ids:
                            # 标记 \Deleted flag
                            store_status, _ = mail.store(mail_id, '+FLAGS', '\\Deleted')
                            if store_status == 'OK':
                                deleted_count += 1
                            # else: print(f"标记收件箱邮件 ID {mail_id} 失败. Status: {store_status}") # 可选,如果想看每个失败的标记

                        # 永久删除标记为删除的邮件
                        if deleted_count > 0:
                            print(f"已标记 {deleted_count} 封收件箱邮件. 正在执行永久删除 (Expunge)...")
                            expunge_status, expunge_response = mail.expunge()
                            print(f"Expunge 状态: {expunge_status}")
                            if expunge_status == 'OK':
                                print(f"成功从收件箱中永久删除了 {deleted_count} 封邮件.")
                            else:
                                print("收件箱 Expunge 操作失败.")
                        else:
                            print("没有收件箱邮件被标记删除.")


                    elif status == 'OK' and not data[0]:
                        print("收件箱搜索成功,但没有找到符合条件的邮件.")
                    else:
                        print(f"收件箱搜索失败. 状态: {status}")
                else:
                     print("未能选择 'inbox' 文件夹.")

            except Exception as e:
                print(f"处理收件箱时发生错误: {e}")
            # 可以选择在这里调用 mail.unselect(),或者依赖下次 select 自动取消选择

        else:
            print("\n--- 未指定收件箱关键词,跳过收件箱处理 ---")


        # --- 处理发件箱邮件 ---
        print("\n--- 正在处理发件箱,删除所有邮件 ---")
        try:
            # 定义可能的发件箱文件夹名称列表
            # 注意:文件夹名称需要用双引号或单引号包围,这里使用双引号因为IMAP协议要求
            sent_folders_to_try = ['"Sent Messages"', '"已发送"']
            selected_folder_name = None

            # 尝试选择发件箱文件夹
            print("正在尝试选择发件箱文件夹...")
            for folder_name in sent_folders_to_try:
                print(f"尝试选择文件夹: {folder_name}...")
                # mail.select() 返回状态和文件夹内的邮件数量信息
                status, mail_count_data = mail.select(folder_name)
                # print(f"选择文件夹 {folder_name} 的状态: {status}, 邮件数量信息: {mail_count_data}") # 可选,如果想看详细信息
                if status == 'OK':
                    selected_folder_name = folder_name
                    print(f"成功选择发件箱文件夹: {selected_folder_name}")
                    break # 找到并选中了文件夹,不再尝试其他名称

            if selected_folder_name:
                # 搜索所有邮件 (因为要删除全部)
                print(f"正在搜索 '{selected_folder_name}' 中的所有邮件...")
                status, data = mail.search(None, "ALL")
                print(f"搜索状态: {status}, 数据长度: {len(data[0]) if data and data[0] else 0}")

                if status == 'OK' and data[0]: # 检查状态是否OK且数据非空
                    mail_ids_bytes = data[0] # data[0] 是 bytes 类型,包含所有邮件ID,用空格分隔
                    mail_ids = mail_ids_bytes.split() # 转换为列表
                    print(f"找到 {len(mail_ids)} 封发件箱邮件需要删除.")

                    deleted_count = 0
                    print("正在标记发件箱邮件以删除...")
                    # 通过标记 \Deleted flag 来删除邮件
                    for mail_id in mail_ids:
                         store_status, _ = mail.store(mail_id, '+FLAGS', '\\Deleted')
                         # print(f"标记发件箱邮件 ID {mail_id} 状态: {store_status}") # 可选,如果邮件很多,这个会非常冗余
                         if store_status == 'OK':
                             deleted_count += 1
                         # else: print(f"标记发件箱邮件 ID {mail_id} 失败. Status: {store_status}") # 可选

                    # 永久删除标记为删除的邮件
                    if deleted_count > 0:
                         print(f"已标记 {deleted_count} 封发件箱邮件. 正在执行永久删除 (Expunge)...")
                         expunge_status, expunge_response = mail.expunge()
                         print(f"Expunge 状态: {expunge_status}")
                         if expunge_status == 'OK':
                             print(f"成功从 '{selected_folder_name}' 中永久删除了 {deleted_count} 封邮件.")
                         else:
                              print("发件箱 Expunge 操作失败.")
                    else:
                        print("没有发件箱邮件被标记删除.")

                elif status == 'OK' and not data[0]:
                    print("发件箱搜索成功,但在选定的文件夹中没有找到任何邮件.")
                else:
                    print(f"发件箱搜索操作失败. 状态: {status}")

            else:
                print("未能选择任何已知的发件箱文件夹. 请检查文件夹名称.")
                # 可选:列出所有可用文件夹,帮助诊断
                # print("尝试列出所有可用文件夹...")
                # status_list, folder_list_data = mail.list()
                # if status_list == 'OK':
                #     print("可用的文件夹列表:")
                #     for folder_info in folder_list_data:
                #         print(f"  {folder_info}") # 文件夹信息格式可能复杂,需要解析

        except Exception as e:
            print(f"处理发件箱时发生错误: {e}")


    except imaplib.IMAP4.error as e:
        print(f"发生 IMAP 错误: {e}")
    except Exception as e:
        print(f"发生未知错误: {e}")
    finally:
        # 关闭连接并退出登录
        if mail:
            try:
                mail.close()
                print("\n连接已关闭.")
            except Exception as e:
                print(f"关闭连接时出错: {e}")
            try:
                mail.logout()
                print("已退出登录.")
            except Exception as e:
                print(f"退出登录时出错: {e}")

        print("\n所有指定的删除过程结束.")

# --- 示例用法 ---
# 请替换为您的实际邮箱账号和授权码
# 注意:PASSWORD 必须是授权码!不是登录密码!
your_email = "你的QQ邮箱账号@qq.com"
your_password = "你的QQ邮箱授权码" # <<<<<< 请务必替换为授权码!

# 要删除的收件箱邮件主题关键词 (如果不需要删除收件箱,可以将这个设置为 None 或 "")
inbox_keyword_to_delete = "adb连接失败"

# 调用合并后的函数
delete_emails_combined(your_email, your_password, inbox_subject_keyword=inbox_keyword_to_delete)

# 如果只需要删除发件箱全部邮件,收件箱关键词设为None
# delete_emails_combined(your_email, your_password, inbox_subject_keyword=None)

# 如果只需要删除收件箱特定邮件,不删除发件箱,可以在函数内部注释掉发件箱处理部分

代码说明:

  1. 函数签名变化: 函数 delete_emails_combined 现在接受三个参数:邮箱账号、授权码,以及一个可选的 inbox_subject_keyword 参数,用于指定收件箱要删除的邮件主题关键词。
  2. 登录只执行一次: 连接和登录逻辑被放在了函数开头,确保只需要登录一次。
  3. 分别处理: 代码被分成了两个主要部分:处理收件箱和处理发件箱。
  4. 收件箱处理:
    • 只有当 inbox_subject_keyword 参数被提供(不是 None 或空字符串)时,才会执行收件箱删除逻辑。
    • 选择 'inbox' 文件夹。
    • 使用提供的关键词进行搜索。
    • 标记并删除找到的邮件。
  5. 发件箱处理:
    • 这部分逻辑与您原先的 delete_mail_sent 函数类似,尝试选择 "Sent Messages" 或 "已发送" 文件夹。
    • 搜索该文件夹内的所有邮件 ("ALL")。
    • 标记并删除找到的所有邮件。
  6. 错误处理和打印: 代码保留并增强了错误处理 (try...except) 和详细的打印输出,帮助您诊断问题出在哪里(登录失败、选择文件夹失败、搜索失败、找不到邮件等)。
  7. finally 块: 使用 finally 块确保无论是否发生错误,都会尝试关闭邮箱连接 (mail.close()) 和退出登录 (mail.logout())。
  8. 授权码: 再次强调,PASSWORD 参数必须是QQ邮箱的IMAP 授权码,不是您的QQ密码或邮箱登录密码。

使用这个合并后的函数,传入您的邮箱账号、授权码以及您想删除的收件箱关键词(如果不删除收件箱,就传入 None),就可以执行这两个任务了。如果遇到问题,请查看打印输出的错误信息。