使用IMAP服务获取163邮箱的未读邮件

使用IMAP服务获取163邮箱的未读邮件

整体的逻辑思路如下:

  1. 开启163邮箱的IMAP服务,拿到授权码用于登录IMAP服务
  2. 登录IMAP服务,获取邮箱的未读邮件列表
  3. 遍历未读邮件列表,获取邮件内容
# 导入必要的库
import os
import imaplib
import ssl
import email
from email.header import decode_header
from email.utils import parseaddr

1. 开启163邮箱的IMAP服务,拿到授权码用于登录IMAP服务

163邮箱设置IMAP服务,需要到邮箱设置页面,选择“邮箱设置”->“POP3/IMAP”->“开启IMAP服务”,然后点击“保存”,即可开启IMAP服务。

2. 登录IMAP服务,获取邮箱的未读邮件列表

# 创建一个默认的SSL上下文对象,用于服务器认证
# 参数设置为None,表示使用默认值,后续将通过代码明确指定SSL/TLS版本范围
ssl_context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH, cafile=None, capath=None, cadata=None)
# 指定SSL/TLS的最小版本为TLS 1.2,以确保连接使用的协议不低于此版本
ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2

# 指定SSL/TLS的最大版本为TLS 1.3,以确保连接不会使用超出此版本的协议
# TLS 1.3是最新的TLS版本,提供了更强的安全性和加密方法
ssl_context.maximum_version = ssl.TLSVersion.TLSv1_3
def login163(user=None, pwd=None, host="imap.163.com" ):
    # 尝试建立SSL加密的IMAP连接并登录
    # 异常处理增强
    try:
        imap_client = imaplib.IMAP4_SSL(host, ssl_context=ssl_context)  # 确保使用TLS 1.2
        imap_client.login(user, pwd)
    except imaplib.IMAP4.error as e:
        print(f"登录失败: {e}")
        return

    # 发送ID命令给服务器,提供客户端信息
    imaplib.Commands["ID"] = ('AUTH',)
    args = ("name", user, "contact", user, "version", "1.0.0", "vendor", "myclient")
    imap_client._simple_command("ID", str(args).replace(",", "").replace("'", "\""))

    return imap_client

3. 遍历未读邮件列表,获取邮件内容

def fetch_and_mark_emails_as_read(imap_client,mailbox="INBOX"):
    """
    从指定的邮箱中获取未读邮件,并将这些邮件标记为已读。
    
    :param imap_client: IMAP客户端对象,用于与邮件服务器交互
    :param mailbox: string, 指定的邮箱,默认为"INBOX"(收件箱)
    """
    # 选择邮箱,默认为收件箱
    imap_client.select(mailbox)
    # 搜索未读邮件
    typ, dat = imap_client.search(None, "UNSEEN")

    # 解码邮件编号字符串
    str_numbers = dat[0].decode('utf-8')
    # 将编号字符串分割成列表
    numbers_str_list = str_numbers.split()
    # 遍历未读邮件
    for msg in numbers_str_list:
        try:
            # 获取邮件内容
            _, data = imap_client.fetch(msg, '(RFC822)')
            raw_email = data[0][1]
            email_message = email.message_from_bytes(raw_email)

            # 解码邮件主题
            subject = decode_email_header(email_message['Subject'])

            # 解码发件人信息
            from_info = decode_header(email_message['From'])
            name_parts = []
            for part, charset in from_info:
                if isinstance(part, bytes):
                    if charset:
                        decoded_part = part.decode(charset)
                    else:
                        decoded_part = part.decode('utf-8', errors='replace')
                else:
                    decoded_part = part
                name_parts.append(decoded_part)

            full_name = ''.join(name_parts).strip() 
            from_person,_=parseaddr(full_name)

            # 提取邮件正文
            all_text_body = extract_text_body(email_message)
            #------------------------------
            #你对得到的邮件的处理代码
     		#------------------------------
            # 标记邮件为已读
            imap_client.store(msg, '+FLAGS', '\\Seen')
        except imaplib.IMAP4.error as e:
            print(f"处理邮件或标记已读失败: {e}")

邮件主题解码函数:

def decode_email_header(header):
    """
    解码电子邮件头信息。

    电子邮件头信息可能包含多种编码,这个函数旨在解析头信息并返回解码后的字符串。
    如果头信息是ASCII码,则直接返回;如果是非ASCII码,会根据编码类型进行解码。

    参数:
    header (str): 需要解码的电子邮件头信息。

    返回:
    str: 解码后的字符串。如果解码过程中包含多种编码,会返回一个元组,包含解码后的字符串和对应的编码类型。
    """
    # 解码头信息,返回一个包含解码结果和编码类型的元组
    # 列表
    decoded_header = decode_header(header)[0]
    # print(decoded_header)
    # 判断解码结果是否为元组,如果是,说明存在多种编码,需要进一步解码
    if isinstance(decoded_header, tuple):
        # 对元组中的字符串进行解码,并返回解码后的结果
        part, charset = decoded_header
        if isinstance(part, bytes):  # 检查是否为字节串
            if charset:  # 如果有字符集,按指定字符集解码
                decoded_part = part.decode(charset)
            else:  # 没有指定字符集时尝试UTF-8解码,或选择其他策略
                decoded_part = part.decode('utf-8', errors='replace')
        else:  # 如果已经是字符串,直接使用
            decoded_part = part
        return decoded_part
    else:
        # 如果解码结果不是元组,直接返回解码后的字符串
        return None

正文获取部分

def extract_text_body(email_message):
    """
    从电子邮件消息中提取纯文本正文。
    
    参数:
    email_message: 一个电子邮件消息对象,可以是使用Python email库构建的或从文件中读取的。
    
    返回:
    一个字符串,包含电子邮件的纯文本正文。如果没有找到纯文本正文或邮件为空,则返回空字符串。
    """
    # 初始化一个字符串,用于存储提取的文本正文
    all_text_body = ""
    
    # 遍历电子邮件的每一个部分
    for part in email_message.walk():
        # 获取当前部分的Content-Type
        ctype = part.get_content_type()
        # 获取当前部分的Content-Disposition
        cdispo = str(part.get('Content-Disposition'))
        
        # 检查当前部分是否为纯文本且不是附件
        if ctype == 'text/plain' and 'attachment' not in cdispo:
            # 获取当前部分的payload(实际内容),并解码
            body = part.get_payload(decode=True)
            # 获取当前部分的内容字符集
            charset = part.get_content_charset()
            # 将解码后的文本添加到存储所有文本正文的字符串中
            all_text_body += body.decode(charset, errors='replace')
            # 找到纯文本正文后立即终止循环,以提高效率
            break  # 如果找到文本部分,即停止搜索,提高效率
    
    # 返回收集到的所有文本正文
    return all_text_body

测试代码

def imap_mail_get(client):
    retry_limit = 3
    for i in range(retry_limit):
        try:
            if client is None:
                client = login163(username, password)#password为IMAP授权码
            # 对两个邮箱进行操作
            for mailbox in ["INBOX", "Sent"]:
                fetch_and_mark_emails_as_read(client, mailbox=mailbox)
            return client 
        except Exception as e:
            pass

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值