14.4. mailbox — 管理 email 规定文件 | 邮件模块 |《python 3 标准库实例教程》| python 技术论坛-金年会app官方网
目的:处理各种本地文件格式的电子邮件。
mailbox
模块定义了用于访问以本地磁盘格式存储的电子邮件的通用api,包括:
- maildir
- mbox
- mh
- babyl
- mmdf
有mailbox
和message
的基类,每种邮箱格式都包括一对相应的子类,以实现该格式的详细信息。
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邮箱
创建maildir
和mbox
的唯一真正区别是构造函数的参数是目录名而不是文件名。和以前一样,如果邮箱不存在,则会在添加邮件时创建它。
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: []
读取它们之后,客户端可以使用maildirmessage
的set_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服务器上使用已保存的电子邮件。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 cc 协议,如果我们的工作有侵犯到您的权益,请及时联系金年会app官方网。