python 收发信的功能。

邮箱客户端实现 该Python代码实现了一个2925.com邮箱客户端类,主要功能包括: 发送邮件: 支持纯文本和HTML格式邮件 使用SMTP_SSL协议通过465端口发送 包含发件人、收件人和主题设置 接收邮件: 通过IMAP4_SSL协议从993端口获取 提供两种获取方式:UID命令(更可靠)和序号获取(备用) 解析邮件主题、发件人、日期和正文内容 支持限制获取邮件数量 其他特性: 邮件正文预览功能(截取前200字符) 完善的错误处理和日志输出 支持中文字符解码 该客户端类封装了完整的

python 复制代码
import smtplib
import imaplib
import email
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import decode_header
import os


class EmailClient2925:
    def __init__(self, email_address, password):
        """
        初始化2925.com邮箱客户端

        参数:
        email_address: 邮箱地址
        password: 邮箱密码
        """
        self.email_address = email_address
        self.password = password

        # 2925.com服务器配置
        self.smtp_server = "smtp.2925.com"
        self.smtp_port = 465  # SSL端口   465
        self.imap_server = "imap.2925.com"
        self.imap_port = 993

    def send_email(self, to_email, subject, body, is_html=False):
        """
        发送邮件

        参数:
        to_email: 收件人邮箱
        subject: 邮件主题
        body: 邮件正文
        is_html: 是否为HTML格式
        """
        try:
            # 创建邮件
            msg = MIMEMultipart()
            msg['From'] = self.email_address
            msg['To'] = to_email
            msg['Subject'] = subject

            # 添加邮件正文
            if is_html:
                msg.attach(MIMEText(body, 'html'))
            else:
                msg.attach(MIMEText(body, 'plain'))

            # 连接SMTP服务器并发送
            print(f"正在连接到SMTP服务器: {self.smtp_server}:{self.smtp_port}")

            # 使用SSL连接
            server = smtplib.SMTP_SSL(self.smtp_server, self.smtp_port)
            server.login(self.email_address, self.password)
            server.send_message(msg)
            server.quit()

            print(f"邮件发送成功!收件人: {to_email}")
            return True

        except Exception as e:
            print(f"发送邮件失败: {str(e)}")
            return False

    def receive_emails(self, limit=10):
        """
        接收邮件 - 改进版本,使用UID命令避免SEARCH命令问题

        参数:
        limit: 最多获取的邮件数量
        """
        emails = []

        try:
            print(f"正在连接到IMAP服务器: {self.imap_server}:{self.imap_port}")

            # 连接到IMAP服务器
            mail = imaplib.IMAP4_SSL(self.imap_server, self.imap_port)
            mail.login(self.email_address, self.password)

            # 选择收件箱
            status, select_info = mail.select('INBOX')
            if status != 'OK':
                print(f"选择收件箱失败: {select_info}")
                return []

            # 获取邮件总数
            total_msgs = int(select_info[0].decode())
            print(f"收件箱中共有 {total_msgs} 封邮件")

            if total_msgs == 0:
                print("收件箱为空")
                mail.logout()
                return []

            # 方法1: 使用UID命令获取邮件(更可靠)
            print("尝试使用UID命令获取邮件...")

            # 先获取所有邮件的UID
            status, uid_data = mail.uid('SEARCH', None, 'ALL')
            if status != 'OK' or not uid_data[0]:
                print("UID SEARCH失败,尝试方法2...")
                # 方法2: 直接按序号获取邮件
                return self._receive_by_sequence(mail, total_msgs, limit)

            # 获取UID列表
            uids = uid_data[0].split()
            print(f"找到 {len(uids)} 封邮件的UID")

            # 反转列表,获取最新的邮件
            uids = uids[::-1]

            # 限制获取数量
            uids = uids[:limit]

            for i, uid in enumerate(uids):
                try:
                    # 使用UID获取邮件
                    status, msg_data = mail.uid('FETCH', uid, '(RFC822)')

                    if status == 'OK' and msg_data[0] is not None:
                        # 解析邮件
                        if isinstance(msg_data[0], tuple):
                            raw_email = msg_data[0][1]
                        else:
                            raw_email = msg_data[0]

                        msg = email.message_from_bytes(raw_email)

                        # 解码主题
                        subject = "无主题"
                        if msg["Subject"]:
                            subject_info = decode_header(msg["Subject"])[0]
                            subject_text = subject_info[0]
                            encoding = subject_info[1]
                            if isinstance(subject_text, bytes):
                                subject = subject_text.decode(encoding if encoding else 'utf-8', errors='ignore')
                            else:
                                subject = str(subject_text)

                        # 获取发件人
                        from_ = msg.get("From", "未知发件人")

                        # 获取日期
                        date_ = msg.get("Date", "未知日期")

                        # 获取邮件正文
                        body = self._extract_email_body(msg)

                        emails.append({
                            'id': i + 1,
                            'uid': uid.decode(),
                            'subject': subject,
                            'from': from_,
                            'date': date_,
                            'body': body,
                            'body_preview': body[:200] + "..." if len(body) > 200 else body
                        })

                        print(f"邮件 {i + 1}:")
                        print(f"  UID: {uid.decode()}")
                        print(f"  主题: {subject}")
                        print(f"  发件人: {from_}")
                        print(f"  日期: {date_}")
                        print(f"  预览: {body[:100]}...")
                        print("-" * 50)
                    else:
                        print(f"获取邮件UID {uid} 失败")

                except Exception as e:
                    print(f"处理邮件UID {uid} 时出错: {str(e)}")
                    continue

            # 关闭连接
            mail.close()
            mail.logout()

        except imaplib.IMAP4.error as e:
            print(f"IMAP协议错误: {str(e)}")
            # 如果UID命令也失败,尝试最基本的FETCH方法
            return self._try_basic_fetch()
        except Exception as e:
            print(f"接收邮件失败: {str(e)}")

        return emails

    def _receive_by_sequence(self, mail, total_msgs, limit):
        """方法2: 按序号直接获取邮件"""
        emails = []

        # 计算起始和结束位置
        start = max(1, total_msgs - limit + 1)

        for seq_num in range(total_msgs, start - 1, -1):
            try:
                status, msg_data = mail.fetch(str(seq_num).encode(), '(RFC822)')

                if status == 'OK' and msg_data[0] is not None:
                    if isinstance(msg_data[0], tuple):
                        raw_email = msg_data[0][1]
                    else:
                        raw_email = msg_data[0]

                    msg = email.message_from_bytes(raw_email)

                    # 解码主题
                    subject = "无主题"
                    if msg["Subject"]:
                        subject_info = decode_header(msg["Subject"])[0]
                        subject_text = subject_info[0]
                        encoding = subject_info[1]
                        if isinstance(subject_text, bytes):
                            subject = subject_text.decode(encoding if encoding else 'utf-8', errors='ignore')
                        else:
                            subject = str(subject_text)

                    # 获取邮件正文
                    body = self._extract_email_body(msg)

                    emails.append({
                        'id': total_msgs - seq_num + 1,
                        'seq': seq_num,
                        'subject': subject,
                        'from': msg.get("From", "未知发件人"),
                        'date': msg.get("Date", "未知日期"),
                        'body_preview': body[:200] + "..." if len(body) > 200 else body
                    })

                    print(f"邮件 {total_msgs - seq_num + 1} (序号:{seq_num}): {subject}")

            except Exception as e:
                print(f"处理邮件序号 {seq_num} 时出错: {str(e)}")
                continue

        mail.logout()
        return emails

    def _extract_email_body(self, msg):
        """提取邮件正文内容"""
        body = ""

        if msg.is_multipart():
            for part in msg.walk():
                content_type = part.get_content_type()
                content_disposition = str(part.get("Content-Disposition"))

                # 跳过附件
                if "attachment" in content_disposition:
                    continue

                if content_type in ["text/plain", "text/html"]:
                    try:
                        body_bytes = part.get_payload(decode=True)
                        if body_bytes:
                            charset = part.get_content_charset() or 'utf-8'
                            try:
                                body = body_bytes.decode(charset, errors='ignore')
                            except:
                                body = body_bytes.decode('utf-8', errors='ignore')
                        else:
                            body = part.get_payload()
                    except:
                        body = part.get_payload()

                    # 优先使用纯文本正文
                    if content_type == "text/plain" and body.strip():
                        break
        else:
            try:
                body_bytes = msg.get_payload(decode=True)
                if body_bytes:
                    charset = msg.get_content_charset() or 'utf-8'
                    try:
                        body = body_bytes.decode(charset, errors='ignore')
                    except:
                        body = body_bytes.decode('utf-8', errors='ignore')
                else:
                    body = msg.get_payload()
            except:
                body = msg.get_payload()

        return body

    def _try_basic_fetch(self):
        """方法3: 尝试最基本的连接和获取"""
        try:
            print("尝试最基本的邮件获取方法...")
            mail = imaplib.IMAP4_SSL(self.imap_server, self.imap_port)
            mail.login(self.email_address, self.password)

            # 直接尝试获取第一封邮件
            mail.select('INBOX')
            status, msg_data = mail.fetch('1', '(RFC822)')

            if status == 'OK':
                print("成功获取到第一封邮件!")
                # 这里可以添加解析代码
            else:
                print("连最基本的FETCH也失败了")

            mail.logout()
        except Exception as e:
            print(f"基本方法也失败: {str(e)}")

        return []

    def check_connection(self):
        """测试服务器连接"""
        print("正在测试SMTP连接...")
        try:
            server = smtplib.SMTP_SSL(self.smtp_server, self.smtp_port)
            server.login(self.email_address, self.password)
            server.quit()
            print("SMTP连接成功!")
        except Exception as e:
            print(f"SMTP连接失败: {str(e)}")

        print("\n正在测试IMAP连接...")
        try:
            mail = imaplib.IMAP4_SSL(self.imap_server, self.imap_port)
            mail.login(self.email_address, self.password)

            # 测试是否能选择收件箱
            status, info = mail.select('INBOX')
            if status == 'OK':
                print(f"IMAP连接成功!收件箱邮件数: {info[0].decode()}")
            else:
                print(f"IMAP登录成功,但选择收件箱失败: {info}")

            mail.logout()
        except Exception as e:
            print(f"IMAP连接失败: {str(e)}")


def testSend1():
    list_ = [
        "第一个",
        "第二个",
        "第三个",
        "第四个",
    ]
    print("\n发送测试邮件...")
    for i in range(200):
        client.send_email(
            to_email="laocooon@qq.com",  # 替换为实际收件人
            subject=list_[i % len(list_)] + ",测试邮件",
            body="这是一封来自2925.com的测试邮件。"
        )


# 使用示例
if __name__ == "__main__":
    # 您的邮箱信息
    EMAIL_ADDRESS = "xxxxxx"
    EMAIL_PASSWORD = "xxxxx"

    # 创建邮箱客户端
    client = EmailClient2925(EMAIL_ADDRESS, EMAIL_PASSWORD)

    # 测试连接
    client.check_connection()

    # 发送邮件示例
    # testSend1()
    print("\n发送测试邮件...")
    client.send_email(
        to_email="xxxx@xxx.xx",  # 替换为实际收件人
        subject="测试邮件",
        body="这是一封来自xxx.com的测试邮件。"
    )

    # 接收邮件示例
    print("\n接收最新邮件...")
    emails = client.receive_emails(limit=10)

    if emails:
        print(emails)
        print(f"共收到 {len(emails)} 封邮件")
    else:
        print("没有收到邮件")
相关推荐
xixixi777771 小时前
STIX/TAXII:网络威胁情报的“普通话”与“顺丰快递”
开发语言·安全·php·威胁·攻击检测·stix·taxii
Tony Bai1 小时前
Cloudflare 2025 年度报告发布——Go 语言再次“屠榜”API 领域,AI 流量激增!
开发语言·人工智能·后端·golang
ID_180079054731 小时前
有没有其他语言实现淘宝商品详情API接口采集的方案?
开发语言
清水白石0082 小时前
《Python 责任链模式实战指南:从设计思想到工程落地》
开发语言·python·责任链模式
沛沛老爹2 小时前
Web开发者快速上手AI Agent:基于LangChain的提示词应用优化实战
人工智能·python·langchain·提示词·rag·web转型
宁大小白2 小时前
pythonstudy Day39
python·机器学习
love is sour2 小时前
深入浅出 jmap:Java 内存分析的“显微镜“
java·开发语言·测试工具·性能优化
拾贰_C2 小时前
【VSCode | python | anaconda | cmd | PowerShell】在没有进入conda环境时使用conda命令默认安装位置
vscode·python·conda
json{shen:"jing"}2 小时前
2-C语言的运算符和表达式
c语言·开发语言