13518219792

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

创新互联Python教程:mailbox—-操作多种格式的邮箱

mailbox —- 操作多种格式的邮箱

源代码: Lib/mailbox.py

十多年的分宜网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。网络营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整分宜建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。成都创新互联从事“分宜网站设计”,“分宜网站推广”以来,每个客户项目都认真落实执行。


本模块定义了两个类,Mailbox 和 Message,用于访问和操作磁盘中的邮箱及其所包含的电子邮件。 Mailbox 提供了类似字典的从键到消息的映射。 Message 为 email.message 模块的 Message 类增加了特定格式专属的状态和行为。 支持的邮箱格式有 Maildir, mbox, MH, Babyl 以及 MMDF。

参见

模块 email

表示和操作邮件消息。

Mailbox 对象

class mailbox.Mailbox

一个邮箱,它可以被检视和修改。

Mailbox 类定义了一个接口并且它不应被实例化。 而是应该让格式专属的子类继承 Mailbox 并且你的代码应当实例化一个特定的子类。

Mailbox 接口类似于字典,其中每个小键都有对应的消息。 键是由 Mailbox 实例发出的,它们将由实例来使用并且只对该 Mailbox 实例有意义。 键会持续标识一条消息,即使对应的消息已被修改,例如被另一条消息所替代。

可以使用 set 型方法 add() 将消息添加到 Mailbox 并可以使用 del 语句或 set 型方法 remove() 和 discard() 将其移除。

Mailbox 接口语义在某些值得注意的方面与字典语义有所不同。 每次请求消息时,都会基于邮箱的当前状态生成一个新的表示形式(通常为 Message 实例)。 类似地,当向 Mailbox 实例添加消息时,所提供的消息表示形式的内容将被复制。 无论在哪种情况下 Mailbox 实例都不会保留对消息表示形式的引用。

默认的 Mailbox 迭代器会迭代消息表示形式,而不像默认的字典迭代器那样迭代键。 此外,在迭代期间修改邮箱是安全且有明确定义的。 在创建迭代器之后被添加到邮箱的消息将对该迭代不可见。 在迭代器产出消息之前被从邮箱移除的消息将被静默地跳过,但是使用来自迭代器的键也有可能导致 KeyError 异常,如果对应的消息后来被移除的话。

警告

在修改可能同时被其他某个进程修改的邮箱时要非常小心。 用于此种任务的最安全邮箱格式是 Maildir;请尽量避免使用 mbox 之类的单文件格式进行并发写入。 如果你正在修改一个邮箱,你 必须 在读取文件中的任何消息或者执行添加或删除消息等修改操作 之前 通过调用 lock() 以及 unlock() 方法来锁定它。 如果未锁定邮箱则将导致丢失消息或损坏整个邮箱的风险。

Mailbox 实例具有下列方法:

Maildir

class mailbox.Maildir(dirname, factory=None, create=True)

Mailbox 的一个子类,用于 Maildir 格式的邮箱。 形参 factory 是一个可调用对象,它接受一个文件类消息表示形式(其行为相当于以二进制模式打开)并返回一个自定义的表示形式。 如果 factoryNone,则会使用 MaildirMessage 作为默认的消息表示形式。 如果 createTrue,则当邮箱不存在时会创建它。

如果 createTruedirname 路径存在,它将被视为已有的 maildir 而无需尝试验证其目录布局。

使用 dirname 这个名称而不使用 path 是出于历史原因。

Maildir 是一种基于目录的邮箱格式,它是针对 qmail 邮件传输代理而发明的,现在也得到了其他程序的广泛支持。 Maildir 邮箱中的消息存储在一个公共目录结构中的单独文件内。 这样的设计允许 Maildir 邮箱被多个彼此无关的程序访问和修改而不会导致数据损坏,因此文件锁定操作是不必要的。

Maildir 邮箱包含三个子目录,分别是: tmp, newcur。 消息会不时地在 tmp 子目录中创建然后移至 new 子目录来结束投递。 后续电子邮件客户端可能将消息移至 cur 子目录并将有关消息状态的信息存储在附带到其文件名的特殊 “info” 小节中。

Courier 电子邮件传输代理所引入的文件夹风格也是受支持的。 主邮箱中任何子目录只要其名称的第一个字符是 '.' 就会被视为文件夹。 文件夹名称会被 Maildir 表示为不带前缀 '.' 的形式。 每个文件夹自身都是一个 Maildir 邮箱但不应包含其他文件夹。 逻辑嵌套关系是使用 '.' 来划定层级,例如 “Archived.2005.07”。

备注

Maildir 规范要求使用在特定消息文件名中使用冒号 (':')。 但是,某些操作系统不允许将此字符用于文件名,如果你希望在这些操作系统上使用类似 Maildir 的格式,你应当指定改用另一个字符。 叹号 ('!') 是一个受欢迎的选择。 例如:

 
 
 
 
  1. import mailbox
  2. mailbox.Maildir.colon = '!'

colon 属性也可以在每个实例上分别设置。

Maildir 实例具有 Mailbox 的所有方法及下列附加方法:

Maildir 所实现的某些 Mailbox 方法值得进行特别的说明:

参见

maildir man page from Courier

该格式的规格说明。 描述了用于支持文件夹的通用扩展。

使用 maildir 格式

Maildir 发明者对它的说明。 包括已更新的名称创建方案和 “info” 语义的相关细节。

mbox

class mailbox.mbox(path, factory=None, create=True)

Mailbox 的子类,用于 mbox 格式的邮箱。 形参 factory 是一个可调用对象,它接受一个文件类消息表示形式(其行为相当于以二进制模式打开)并返回一个自定义的表示形式。 如果 factoryNone,则会使用 mboxMessage 作为默认的消息表示形式。 如果 createTrue,则当邮箱不存在时会创建它。

mbox 格式是在 Unix 系统上存储电子邮件的经典格式。 mbox 邮箱中的所有消息都存储在一个单独文件中,每条消息的开头由前五个字符为 “From “ 的行来指明。

还有一些 mbox 格式变种对原始格式中发现的缺点做了改进,mbox 只实现原始格式,有时被称为 mboxo。 这意味着当存储消息时 Content-Length 标头如果存在则会被忽略并且消息体中出现于行开头的任何 “From “ 会被转换为 “>From “,但是当读取消息时 “>From “ 则不会被转换为 “From “。

mbox 所实现的某些 Mailbox 方法值得进行特别的说明:

参见

tin 上的 mbox 指南页面

该格式的规格说明,包括有关锁的详情。

在 Unix 上配置 Netscape Mail: 为何 Content-Length 格式是不好的

使用原始 mbox 格式而非其变种的一些理由。

“mbox” 是由多个彼此不兼容的邮箱格式构成的家族

有关 mbox 变种的历史。

MH

class mailbox.MH(path, factory=None, create=True)

Mailbox 的子类,用于 MH 格式的邮箱。 形参 factory 是一个可调用对象,它接受一个文件类消息表示形式(其行为相当于以二进制模式打开)并返回一个自定义的表示形式。 如果 factoryNone,则会使用 MHMessage 作为默认的消息表示形式。 如果 createTrue,则当邮箱不存在时会创建它。

MH 是一种基于目录的邮箱格式,它是针对 MH Message Handling System 电子邮件用户代理而发明的。 在 MH 邮箱的每条消息都放在单独文件中。 MH 邮箱中除了邮件消息还可以包含其他 MH 邮箱 (称为 文件夹)。 文件夹可以无限嵌套。 MH 邮箱还支持 序列,这是一种命名列表,用来对消息进行逻辑分组而不必将其移入子文件夹。 序列是在每个文件夹中名为 .mh_sequences 的文件内定义的。

MH 类可以操作 MH 邮箱,但它并不试图模拟 mh 的所有行为。 特别地,它并不会修改 context.mh_profile 文件也不会受其影响,这两个文件是 mh 用来存储状态和配置数据的。

MH 实例具有 Mailbox 的所有方法及下列附加方法:

MH 所实现的某些 Mailbox 方法值得进行特别的说明:

参见

nmh - Message Handling System

nmh 的主页,这是原始 mh 的更新版本。

MH & nmh: Email for Users & Programmers

使用 GPL 许可证的介绍 mhnmh 的图书,包含有关该邮箱格式的各种信息。

Babyl

class mailbox.Babyl(path, factory=None, create=True)

Mailbox 的子类,用于 Babyl 格式的邮箱。 形参 factory 是一个可调用对象,它接受一个文件类表示形式(其行为相当于以二进制模式打开)并返回一个自定义的表示形式。 如果 factoryNone,则会使用 BabylMessage 作为默认的消息表示形式。 如果 createTrue,则当邮箱不存在时会创建它。

Babyl 是 Rmail 电子邮箱用户代理所使用单文件邮箱格式,包括在 Emacs 中。 每条消息的开头由一个包含 Control-Underscore ('\037') 和 Control-L ('\014') 这两个字符的行来指明。 消息的结束由下一条消息的开头来指明,或者当为最后一条消息时则由一个包含 Control-Underscore ('\037') 字符的行来指明。

Babyl 邮箱中的消息带有两组标头:原始标头和所谓的可见标头。 可见标头通常为原始标头经过重格式化和删减以更易读的子集。 Babyl 邮箱中的每条消息都附带了一个 标签 列表,即记录消息相关额外信息的短字符串,邮箱中所有的用户定义标签列表会存储于 Babyl 的选项部分。

Babyl 实例具有 Mailbox 的所有方法及下列附加方法:

Babyl 所实现的某些 Mailbox 方法使得进行特别的说明:

参见

Format of Version 5 Babyl Files

Babyl 格式的规格说明。

Reading Mail with Rmail

Rmail 的帮助手册,包含了有关 Babyl 语义的一些信息。

MMDF

class mailbox.MMDF(path, factory=None, create=True)

Mailbox 的子类,用于 MMDF 格式的邮箱。 形参 factory 是一个可调用对象,它接受一个文件类消息表示形式(其行为相当于以二进制模式打开)并返回一个自定义的表示形式。 如果 factoryNone,则会使用 MMDFMessage 作为默认的消息表示形式。 如果 createTrue,则当邮箱不存在时会创建它。

MMDF 是一种专用于电子邮件传输代理 Multichannel Memorandum Distribution Facility 的单文件邮箱格式。 每条消息使用与 mbox 消息相同的形式,但其前后各有包含四个 Control-A ('\001') 字符的行。 与 mbox 格式一样,每条消息的开头由一个前五个字符为 “From “ 的行来指明,但当存储消息时额外出现的 “From “ 不会被转换为 “>From “ 因为附加的消息分隔符可防止将这些内容误认为是后续消息的开头。

MMDF 所实现的某些 Mailbox 方法值得进行特别的说明:

参见

tin 上的 mmdf 指南页面

MMDF 格式的规格说明,来自新闻阅读器 tin 的文档。

MMDF

一篇描述 Multichannel Memorandum Distribution Facility 的维基百科文章。

Message 对象

class mailbox.Message(message=None)

email.message 模块的 Message 的子类。 mailbox.Message 的子类添加了特定邮箱格式专属的状态和行为。

如果省略了 message,则新实例会以默认的空状态被创建。 如果 message 是一个 email.message.Message 实例,其内容会被拷贝;此外,如果 message 是一个 Message 实例,则任何格式专属信息会尽可能地被拷贝。 如果 message 是一个字符串、字节串或文件,则它应当包含兼容 RFC 2822 的消息,该消息会被读取和解析。 文档应当以二进制模式打开,但文本模式的文件也会被接受以向下兼容。

各个子类所提供的格式专属状态和行为各有不同,但总的来说只有那些不仅限于特定邮箱的特性才会被支持(虽然这些特性可能专属于特定邮箱格式)。 例如,例如,单文件邮箱格式的文件偏移量和基于目录的邮箱格式的文件名都不会被保留,因为它们都仅适用于对应的原始邮箱。 但消息是否已被用户读取或标记为重要等状态则会被保留,因为它们适用于消息本身。

不要求用 Message 实例来表示使用 Mailbox 实例所提取到的消息。 在某些情况下,生成 Message 表示形式所需的时间和内存空间可能是不可接受的。 对于此类情况,Mailbox 实例还提供了字符串和文件类表示形式,并可在初始化 Mailbox 实例时指定自定义的消息工厂函数。

MaildirMessage

class mailbox.MaildirMessage(message=None)

具有 Maildir 专属行为的消息。 形参 message 的含义与 Message 构造器一致。

通常,邮件用户代理应用程序会在用户第一次打开并关闭邮箱之后将 new 子目录中的所有消息移至 cur 子目录,将这些消息记录为旧消息,无论它们是否真的已被阅读。 cur 下的每条消息都有一个 “info” 部分被添加到其文件名中以存储有关其状态的信息。 (某些邮件阅读器还会把 “info” 部分也添加到 new 下的消息中。) “info” 部分可以采用两种形式之一:它可能包含 “2,” 后面跟一个经标准化的旗标列表(例如 “2,FR”)或者它可能包含 “1,” 后面跟所谓的实验性信息。 Maildir 消息的标准旗标如下:

旗标

含意

说明

D

草稿

正在撰写中

F

已标记

已被标记为重要

P

已检视

转发,重新发送或退回

R

已回复

回复给

S

已查看

已阅读

T

已删除

标记为可被删除

MaildirMessage 实例提供以下方法:

当一个 MaildirMessage 实例基于 mboxMessage 或 MMDFMessage 实例被创建时,将会忽略 StatusX-Status 标头并进行下列转换:

结果状态

mboxMessage 或 MMDFMessage 状态

“cur” 子目录

O 旗标

F 旗标

F 旗标

R 旗标

A 旗标

S 旗标

R 旗标

T 旗标

D 旗标

当一个 MaildirMessage 实例基于 MHMessage 实例被创建时,将进行下列转换:

结果状态

MHMessage 状态

“cur” 子目录

“unseen” 序列

“cur” 子目录和 S 旗标

非 “unseen” 序列

F 旗标

“flagged” 序列

R 旗标

“replied” 序列

当一个 MaildirMessage 实例基于 BabylMessage 实例被创建时,将进行下列转换:

结果状态

BabylMessage 状态

“cur” 子目录

“unseen” 标签

“cur” 子目录和 S 旗标

非 “unseen” 标签

P 旗标

“forwarded” 或 “resent” 标签

R 旗标

“answered” 标签

T 旗标

“deleted” 标签

mboxMessage

class mailbox.mboxMessage(message=None)

具有 mbox 专属行为的消息。 形参 message 的含义与 Message 构造器一致。

mbox 邮箱中的消息会一起存储在单个文件中。 发件人的信封地址和发送时间通常存储在指明每条消息的起始的以 “From “ 打头的行中,不过在 mbox 的各种实现之间此数据的确切格式具有相当大的差异。 指明消息状态的各种旗标,例如是否已读或标记为重要等等通常存储在 StatusX-Status 标头中。

传统的 mbox 消息旗标如下:

旗标

含意

说明

R

已阅读

已阅读

O

旧消息

之前已经过 MUA 检测

D

已删除

标记为可被删除

F

已标记

已被标记为重要

A

已回复

回复给

“R” 和 “O” 旗标存储在 Status 标头中,而 “D”, “F” 和 “A” 旗标存储在 X-Status 标头中。 旗标和标头通常会按上述顺序显示。

mboxMessage 实例提供了下列方法:

当一个 mboxMessage 实例基于 MaildirMessage 实例被创建时,”From “ 行会基于 MaildirMessage 实例的发送时间被生成,并进行下列转换:

结果状态

MaildirMessage 状态

R 旗标

S 旗标

O 旗标

“cur” 子目录

D 旗标

T 旗标

F 旗标

F 旗标

A 旗标

R 旗标

当一个 mboxMessage 实例基于 MHMessage 实例被创建时,将进行下列转换:

结果状态

MHMessage 状态

R 旗标 和 O 旗标

非 “unseen” 序列

O 旗标

“unseen” 序列

F 旗标

“flagged” 序列

A 旗标

“replied” 序列

当一个 mboxMessage 实例基于 BabylMessage 实例被创建时,将进行下列转换:

结果状态

BabylMessage 状态

R 旗标 和 O 旗标

非 “unseen” 标签

O 旗标

“unseen” 标签

D 旗标

“deleted” 标签

A 旗标

“answered” 标签

当一个 Message 实例基于 MMDFMessage 实例被创建时,”From “ 行会被拷贝并直接对应所有旗标。

结果状态

MMDFMessage 状态

R 旗标

R 旗标

O 旗标

O 旗标

D 旗标

D 旗标

F 旗标

F 旗标

A 旗标

A 旗标

MHMessage

class mailbox.MHMessage(message=None)

具有 MH 专属行为的消息。 形参 message 的含义与 Message 构造器一致。

MH 消息不支持传统意义上的标记或旗标,但它们支持序列,即对任意消息的逻辑分组。 某些邮件阅读程序 (但不包括标准 mhnmh) 以与其他格式使用旗标类似的方式来使用序列,如下所示:

序列

说明

unseen

未阅读,但之前已经过 MUA 检测

已回复

回复给

已标记

已被标记为重要

MHMessage 实例提供了下列方法:

当一个 MHMessage 实例基于 MaildirMessage 实例被创建时,将进行下列转换:

结果状态

MaildirMessage 状态

“unseen” 序列

非 S 旗标

“replied” 序列

R 旗标

“flagged” 序列

F 旗标

当一个 MHMessage 实例基于 mboxMessage 或 MMDFMessage 实例被创建时,将会忽略 StatusX-Status 标头并进行下列转换:

结果状态

mboxMessage 或 MMDFMessage 状态

“unseen” 序列

非 R 旗标

“replied” 序列

A 旗标

“flagged” 序列

F 旗标

当一个 MHMessage 实例基于 BabylMessage 实例被创建时,将进入下列转换:

结果状态

BabylMessage 状态

“unseen” 序列

“unseen” 标签

“replied” 序列

“answered” 标签

BabylMessage

class mailbox.BabylMessage(message=None)

具有 Babyl 专属行为的消息。 形参 message 的含义与 Message 构造器一致。

某些消息标签被称为 属性,根据惯例被定义为具有特殊的含义。 这些属性如下所示:

标签

说明

unseen

未阅读,但之前已经过 MUA 检测

deleted

标记为可被删除

filed

复制到另一个文件或邮箱

answered

回复给

forwarded

已转发

edited

已被用户修改

resent

已重发

默认情况下,Rmail 只显示可见标头。 不过 BabylMessage 类会使用原始标头因为它们更完整。 如果需要可以显式地访问可见标头。

BabylMessage 实例提供了下列方法:

当一个 BabylMessage 实例基于 MaildirMessage 实例被创建时,将进行下列转换:

结果状态

MaildirMessage 状态

“unseen” 标签

非 S 旗标

“deleted” 标签

T 旗标

“answered” 标签

R 旗标

“forwarded” 标签

P 旗标

当一个 BabylMessage 实例基于 mboxMessage 或 MMDFMessage 实例被创建时,将会忽略 StatusX-Status 标头并进入下列转换:

结果状态

mboxMessage 或 MMDFMessage 状态

“unseen” 标签

非 R 旗标

“deleted” 标签

D 旗标

“answered” 标签

A 旗标

当一个 BabylMessage 实例基于 MHMessage 实例被创建时,将进入下列转换:

结果状态

MHMessage 状态

“unseen” 标签

“unseen” 序列

“answered” 标签

“replied” 序列

MMDFMessage

class mailbox.MMDFMessage(message=None)

具有 MMDF 专属行为的消息。 形参 message 的含义与 Message 构造器一致。

与 mbox 邮箱中的消息类似,MMDF 消息会与将发件人的地址和发送日期作为以 “From “ 打头的初始行一起存储。 同样地,指明消息状态的旗标通常存储在 StatusX-Status 标头中。

传统的 MMDF 消息旗标与 mbox 消息的类似,如下所示:

旗标

含意

说明

R

已阅读

已阅读

O

旧消息

之前已经过 MUA 检测

D

已删除

标记为可被删除

F

已标记

已被标记为重要

A

已回复

回复给

“R” 和 “O” 旗标存储在 Status 标头中,而 “D”, “F” 和 “A” 旗标存储在 X-Status 标头中。 旗标和标头通常会按上述顺序显示。

MMDFMessage 实例提供了下列方法,与 mboxMessage 所提供的类似:

当一个 MMDFMessage 实例基于 MaildirMessage 实例被创建时,”From “ 行会基于 MaildirMessage 实例的发送日期被生成,并进入下列转换:

结果状态

MaildirMessage 状态

R 旗标

S 旗标

O 旗标

“cur” 子目录

D 旗标

T 旗标

F 旗标

F 旗标

A 旗标

R 旗标

当一个 MMDFMessage 实例基于 MHMessage 实例被创建时,将进行下列转换:

结果状态

MHMessage 状态

R 旗标 和 O 旗标

非 “unseen” 序列

O 旗标

“unseen” 序列

F 旗标

“flagged” 序列

A 旗标

“replied” 序列

当一个 MMDFMessage 实例基于 BabylMessage 实例被创建时,将进行下列转换:

结果状态

BabylMessage 状态

R 旗标 和 O 旗标

非 “unseen” 标签

O 旗标

“unseen” 标签

D 旗标

“deleted” 标签

A 旗标

“answered” 标签

当一个 MMDFMessage 实例基于 mboxMessage 实例被创建时,”From “ 行会被拷贝并直接对应所有旗标:

结果状态

mboxMessage 状态

R 旗标

R 旗标

O 旗标

O 旗标

D 旗标

D 旗标

F 旗标

F 旗标

A 旗标

A 旗标

异常

mailbox 模块中定义了下列异常类:

exception mailbox.Error

所有其他模块专属异常的基类。

exception mailbox.NoSuchMailboxError

在期望获得一个邮箱但未找到时被引发,例如当使用不存在的路径来实例化一个 Mailbox 子类时 (且将 create 形参设为 False),或是当打开一个不存在的路径时。

exception mailbox.NotEmptyError

在期望一个邮箱为空但不为空时被引发,例如当删除一个包含消息的文件夹时。

exception mailbox.ExternalClashError

Raised when some mailbox-related condition beyond the control of the program causes it to be unable to proceed, such as when failing to acquire a lock that another program already holds a lock, or when a uniquely generated file name already exists.

exception mailbox.FormatError

在某个文件中的数据无法被解析时被引发,例如当一个 MH 实例尝试读取已损坏的 .mh_sequences 文件时。

例子

一个打印指定邮箱中所有消息的主题的简单示例:

 
 
 
 
  1. import mailbox
  2. for message in mailbox.mbox('~/mbox'):
  3. subject = message['subject'] # Could possibly be None.
  4. if subject and 'python' in subject.lower():
  5. print(subject)

要将所有邮件从 Babyl 邮箱拷贝到 MH 邮箱,请转换所有可转换的格式专属信息:

 
 
 
 
  1. import mailbox
  2. destination = mailbox.MH('~/Mail')
  3. destination.lock()
  4. for message in mailbox.Babyl('~/RMAIL'):
  5. destination.add(mailbox.MHMessage(message))
  6. destination.flush()
  7. destination.unlock()

这个示例将来自多个邮件列表的邮件分类放入不同的邮箱,小心避免由于其他程序的并发修改导致的邮件损坏,由于程序中断导致的邮件丢失,或是由于邮箱中消息格式错误导致的意外终止:

 
 
 
 
  1. import mailbox
  2. import email.errors
  3. list_names = ('python-list', 'python-dev', 'python-bugs')
  4. boxes = {name: mailbox.mbox('~/email/%s' % name) for name in list_names}
  5. inbox = mailbox.Maildir('~/Maildir', factory=None)
  6. for key in inbox.iterkeys():
  7. try:
  8. message = inbox[key]
  9. except email.errors.MessageParseError:
  10. continue # The message is malformed. Just leave it.
  11. for name in list_names:
  12. list_id = message['list-id']
  13. if list_id and name in list_id:
  14. # Get mailbox to use
  15. box = boxes[name]
  16. # Write copy to disk before removing original.
  17. # If there's a crash, you might duplicate a message, but
  18. # that's better than losing a message completely.
  19. box.lock()
  20. box.add(message)
  21. box.flush()
  22. box.unlock()
  23. # Remove original message
  24. inbox.lock()
  25. inbox.discard(key)
  26. inbox.flush()
  27. inbox.unlock()
  28. break # Found destination, so stop looking.
  29. for box in boxes.itervalues():
  30. box.close()

新闻名称:创新互联Python教程:mailbox—-操作多种格式的邮箱
文章源于:http://cdbrznjsb.com/article/cohpooi.html

其他资讯

让你的专属顾问为你服务