14.4. mailbox — 管理 email 规定文件 | 邮件模块 |《python 3 标准库实例教程》| python 技术论坛-金年会app官方网

未匹配的标注

目的:处理各种本地文件格式的电子邮件。

mailbox模块定义了用于访问以本地磁盘格式存储的电子邮件的通用api,包括:

  • maildir
  • mbox
  • mh
  • babyl
  • mmdf

mailboxmessage的基类,每种邮箱格式都包括一对相应的子类,以实现该格式的详细信息。

mbox

mbox格式是纯文本格式,因此最容易在文档中显示。每个邮箱都存储为单个文件,所有邮件都串联在一起。每次遇到以“from”(“发件人”,后跟一个空格)开头的行,它将被视为新消息的开头。每当这些字符出现在消息正文中行的开头时,都可以通过在行前面添加“>” 来对其进行转义。

创建一个mbox邮箱

通过将文件名传递给构造函数来实例化mbox类。如果文件不存在,则在使用add()附加消息时创建该文件。

mailbox_mbox_create.py

import mailbox
import email.utils
from_addr = email.utils.formataddr(('author',
                                    '[email protected]'))
to_addr = email.utils.formataddr(('recipient',
                                  '[email protected]'))
payload = '''this is the body.
from (will not be escaped).
there are 3 lines.
'''
mbox = mailbox.mbox('example.mbox')
mbox.lock()
try:
    msg = mailbox.mboxmessage()
    msg.set_unixfrom('author sat feb  7 01:05:34 2009')
    msg['from'] = from_addr
    msg['to'] = to_addr
    msg['subject'] = 'sample message 1'
    msg.set_payload(payload)
    mbox.add(msg)
    mbox.flush()
    msg = mailbox.mboxmessage()
    msg.set_unixfrom('author')
    msg['from'] = from_addr
    msg['to'] = to_addr
    msg['subject'] = 'sample message 2'
    msg.set_payload('this is the second body..')
    mbox.add(msg)
    mbox.flush()
finally:
    mbox.unlock()
print(open('example.mbox', 'r').read())

该脚本的结果是一个包含两个电子邮件的新邮箱文件。

$ python3 mailbox_mbox_create.py
from mailer-daemon sun mar 18 20:20:59 2018
from: author <[email protected]>
to: recipient <[email protected]>
subject: sample message 1
this is the body.
>from (will not be escaped).
there are 3 lines.
from mailer-daemon sun mar 18 20:20:59 2018
from: author <[email protected]>
to: recipient <[email protected]>
subject: sample message 2
this is the second body.

reading an mbox mailbox

要读取现有邮箱,请打开它并将mbox对象视为字典。密钥是邮箱实例定义的任意值,除了作为邮件对象的内部标识符之外,没有其他意义。

mailbox_mbox_read.py

import mailbox
mbox = mailbox.mbox('example.mbox')
for message in mbox:
    print(message['subject'])

打开的邮箱支持迭代器协议,但是与真正的字典对象不同,邮箱的默认迭代器在 values 而不是 keys 上运行。

$ python3 mailbox_mbox_read.py
sample message 1
sample message 2

从mbox邮箱中删除邮件

要从 mbox 文件中删除现有消息,请使用其键和remove()或使用del

mailbox_mbox_remove.py

import mailbox
mbox = mailbox.mbox('example.mbox')
mbox.lock()
try:
    to_remove = []
    for key, msg in mbox.iteritems():
        if '2' in msg['subject']:
            print('removing:', key)
            to_remove.append(key)
    for key in to_remove:
        mbox.remove(key)
finally:
    mbox.flush()
    mbox.close()
print(open('example.mbox', 'r').read())

lock()unlock()方法用于防止问题同时访问文件,并且flush()强制将更改写入磁盘。

$ python3 mailbox_mbox_remove.py
removing: 1
from mailer-daemon sun mar 18 20:20:59 2018
from: author <[email protected]>
to: recipient <[email protected]>
subject: sample message 1
this is the body.
>from (will not be escaped).
there are 3 lines.

maildir

创建 maildir 格式是为了消除同时修改 mbox 文件的问题。邮箱不使用单个文件,而是组织为目录,其中每个邮件都包含在其自己的文件中。这还允许嵌套邮箱,因此 maildir 邮箱的 api 扩展了与子文件夹一起使用的方法。

创建maildir邮箱

创建maildirmbox的唯一真正区别是构造函数的参数是目录名而不是文件名。和以前一样,如果邮箱不存在,则会在添加邮件时创建它。

mailbox_maildir_create.py

import mailbox
import email.utils
import os
from_addr = email.utils.formataddr(('author',
                                    '[email protected]'))
to_addr = email.utils.formataddr(('recipient',
                                  '[email protected]'))
payload = '''this is the body.
from (will not be escaped).
there are 3 lines.
'''
mbox = mailbox.maildir('example')
mbox.lock()
try:
    msg = mailbox.mboxmessage()
    msg.set_unixfrom('author sat feb  7 01:05:34 2009')
    msg['from'] = from_addr
    msg['to'] = to_addr
    msg['subject'] = 'sample message 1'
    msg.set_payload(payload)
    mbox.add(msg)
    mbox.flush()
    msg = mailbox.mboxmessage()
    msg.set_unixfrom('author sat feb  7 01:05:34 2009')
    msg['from'] = from_addr
    msg['to'] = to_addr
    msg['subject'] = 'sample message 2'
    msg.set_payload('this is the second body..')
    mbox.add(msg)
    mbox.flush()
finally:
    mbox.unlock()
for dirname, subdirs, files in os.walk('example'):
    print(dirname)
    print('  directories:', subdirs)
    for name in files:
        fullname = os.path.join(dirname, name)
        print('.***', fullname)
        print(open(fullname).read())
        print('*' * 20)

将邮件添加到邮箱后,它们将转到new子目录。

警告

尽管从多个进程中写入同一maildir是安全的,但是add()并不是线程安全的。使用信号量或其他锁定设备,以防止同一进程的多个线程同时修改邮箱。

$ python3 mailbox_maildir_create.py
example
  directories: ['new', 'cur', 'tmp']
example/new
  directories: []
*** example/new/1521404460.m306174p41689q2.hubert.local
from: author <[email protected]>
to: recipient <[email protected]>
subject: sample message 2
this is the second body.
********************
*** example/new/1521404460.m303200p41689q1.hubert.local
from: author <[email protected]>
to: recipient <[email protected]>
subject: sample message 1
this is the body.
from (will not be escaped).
there are 3 lines.
********************
example/cur
  directories: []
example/tmp
  directories: []

读取它们之后,客户端可以使用maildirmessageset_subdir()方法将它们移动到cur子目录中。

mailbox_maildir_set_subdir.py

import mailbox
import os
print('before:')
mbox = mailbox.maildir('example')
mbox.lock()
try:
    for message_id, message in mbox.iteritems():
        print('{:6} "{}"'.format(message.get_subdir(),
                                 message['subject']))
        message.set_subdir('cur')
        # tell the mailbox to update the message.
        mbox[message_id] = message
finally:
    mbox.flush()
    mbox.close()
print('.after:')
mbox = mailbox.maildir('example')
for message in mbox:
    print('{:6} "{}"'.format(message.get_subdir(),
                             message['subject']))
print()
for dirname, subdirs, files in os.walk('example'):
    print(dirname)
    print('  directories:', subdirs)
    for name in files:
        fullname = os.path.join(dirname, name)
        print(fullname)

尽管maildir包含“ tmp”目录,但set_subdir()的唯一有效参数是“ cur”和“ new” 。

$ python3 mailbox_maildir_set_subdir.py
before:
new    "sample message 2"
new    "sample message 1"
after:
cur    "sample message 2"
cur    "sample message 1"
example
  directories: ['new', 'cur', 'tmp']
example/new
  directories: []
example/cur
  directories: []
example/cur/1521404460.m306174p41689q2.hubert.local
example/cur/1521404460.m303200p41689q1.hubert.local
example/tmp
  directories: []

reading a maildir mailbox

从现有 maildir 邮箱中进行读取就像 mbox 邮箱一样。

mailbox_maildir_read.py

import mailbox
mbox = mailbox.maildir('example')
for message in mbox:
    print(message['subject'])

不能保证以任何特定顺序读取消息。

$ python3 mailbox_maildir_read.py
sample message 2
sample message 1

从maildir邮箱中删除邮件

要从maildir邮箱中删除现有邮件,请将其密钥传递到remove()或使用del

mailbox_maildir_remove.py

import mailbox
import os
mbox = mailbox.maildir('example')
mbox.lock()
try:
    to_remove = []
    for key, msg in mbox.iteritems():
        if '2' in msg['subject']:
            print('removing:', key)
            to_remove.append(key)
    for key in to_remove:
        mbox.remove(key)
finally:
    mbox.flush()
    mbox.close()
for dirname, subdirs, files in os.walk('example'):
    print(dirname)
    print('  directories:', subdirs)
    for name in files:
        fullname = os.path.join(dirname, name)
        print('.***', fullname)
        print(open(fullname).read())
        print('*' * 20)

无法计算邮件的密钥,因此请同时使用items()iteritems()从邮箱同时检索密钥和消息对象。

$ python3 mailbox_maildir_remove.py
removing: 1521404460.m306174p41689q2.hubert.local
example
  directories: ['new', 'cur', 'tmp']
example/new
  directories: []
example/cur
  directories: []
*** example/cur/1521404460.m303200p41689q1.hubert.local
from: author <[email protected]>
to: recipient <[email protected]>
subject: sample message 1
this is the body.
from (will not be escaped).
there are 3 lines.
********************
example/tmp
  directories: []

maildir文件夹

maildir 邮箱的子目录或 文件夹 可以直接通过maildir类的方法进行管理。呼叫者可以列出,检索,创建和删除给定邮箱的子文件夹。

mailbox_maildir_folders.py

import mailbox
import os
def show_maildir(name):
    os.system('find {} -print'.format(name))
mbox = mailbox.maildir('example')
print('before:', mbox.list_folders())
show_maildir('example')
print('.{:#^30}.'.format(''))
mbox.add_folder('subfolder')
print('subfolder created:', mbox.list_folders())
show_maildir('example')
subfolder = mbox.get_folder('subfolder')
print('subfolder contents:', subfolder.list_folders())
print('.{:#^30}.'.format(''))
subfolder.add_folder('second_level')
print('second_level created:', subfolder.list_folders())
show_maildir('example')
print('.{:#^30}.'.format(''))
subfolder.remove_folder('second_level')
print('second_level removed:', subfolder.list_folders())
show_maildir('example')

文件夹的目录名称是通过在文件夹名称前加上句点(.)来构造的。

$ python3 mailbox_maildir_folders.py
example
example/new
example/cur
example/cur/1521404460.m303200p41689q1.hubert.local
example/tmp
example
example/.subfolder
example/.subfolder/maildirfolder
example/.subfolder/new
example/.subfolder/cur
example/.subfolder/tmp
example/new
example/cur
example/cur/1521404460.m303200p41689q1.hubert.local
example/tmp
example
example/.subfolder
example/.subfolder/.second_level
example/.subfolder/.second_level/maildirfolder
example/.subfolder/.second_level/new
example/.subfolder/.second_level/cur
example/.subfolder/.second_level/tmp
example/.subfolder/maildirfolder
example/.subfolder/new
example/.subfolder/cur
example/.subfolder/tmp
example/new
example/cur
example/cur/1521404460.m303200p41689q1.hubert.local
example/tmp
example
example/.subfolder
example/.subfolder/maildirfolder
example/.subfolder/new
example/.subfolder/cur
example/.subfolder/tmp
example/new
example/cur
example/cur/1521404460.m303200p41689q1.hubert.local
example/tmp
before: []
##############################
subfolder created: ['subfolder']
subfolder contents: []
##############################
second_level created: ['second_level']
##############################
second_level removed: []

消息标志

邮箱中的邮件具有用于跟踪各个方面的标志,例如邮件是否已被阅读,阅读者将其标记为重要或以后标记为删除。标志以特定于格式的字母代码序列存储,message类具有检索和更改标志值的方法。此示例在添加标记以表明该消息被视为重要之前,在example maildir中显示消息上的标志。

mailbox_maildir_add_flag.py

import mailbox
print('before:')
mbox = mailbox.maildir('example')
mbox.lock()
try:
    for message_id, message in mbox.iteritems():
        print('{:6} "{}"'.format(message.get_flags(),
                                 message['subject']))
        message.add_flag('f')
        # 告诉邮箱更新消息
        mbox[message_id] = message
finally:
    mbox.flush()
    mbox.close()
print('.after:')
mbox = mailbox.maildir('example')
for message in mbox:
    print('{:6} "{}"'.format(message.get_flags(),
                             message['subject']))

默认情况下,消息没有标志。添加标志会更改内存中的消息,但不会更新磁盘上的消息。若要更新磁盘上的邮件,请使用其现有标识符将邮件对象存储在邮箱中。

$ python3 mailbox_maildir_add_flag.py
before:
       "sample message 1"
after:
f      "sample message 1"

使用add_flag()添加标志会保留所有现有标志。使用set_flags()覆盖任何现有的标志集,并将其替换为传递给该方法的新值。

mailbox_maildir_set_flags.py

import mailbox
print('before:')
mbox = mailbox.maildir('example')
mbox.lock()
try:
    for message_id, message in mbox.iteritems():
        print('{:6} "{}"'.format(message.get_flags(),
                                 message['subject']))
        message.set_flags('s')
        # 告诉邮箱更新消息
        mbox[message_id] = message
finally:
    mbox.flush()
    mbox.close()
print('.after:')
mbox = mailbox.maildir('example')
for message in mbox:
    print('{:6} "{}"'.format(message.get_flags(),
                             message['subject']))

在本示例中,当set_flags()将标志替换为s时,上一示例添加的f标志丢失。

$ python3 mailbox_maildir_set_flags.py
before:
f      "sample message 1"
after:
s      "sample message 1"

其他格式

mailbox支持其他几种格式,但没有一种比mbox或maildir受欢迎。 mh是某些邮件处理程序使用的另一种多文件邮箱格式。 babyl和mmdf是单文件格式,具有与mbox不同的消息分隔符。单文件格式支持与mbox相同的api,mh包括maildir类中与文件夹相关的方法。

另请参见

-
-
-– mbox格式的文档。
-– maildir格式的文档。
-电子邮件-电子邮件模块。
-[imaplib](“ imaplib:imap4客户端库”)– – imaplib模块可以在imap服务器上使用已保存的电子邮件。

本文章首发在 金年会app官方网 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系金年会app官方网。

原文地址:https://learnku.com/docs/pymotw/mailbox-...

译文地址:https://learnku.com/docs/pymotw/mailbox-...

上一篇 下一篇
贡献者:2
讨论数量: 0



暂无话题~
网站地图