Автор оригинала: Doug Hellmann.
Цель:
Работайте с сообщениями электронной почты в различных локальных файловых форматах.
Модуль mailbox
определяет общий API для доступа к сообщениям электронной почты, хранящимся в форматах локального диска, включая:
- Maildir
- mbox
- MH
- Вавил
- MMDF
Существуют базовые классы для Mailbox
и Message
, и каждый формат почтового ящика включает соответствующую пару подклассов для реализации деталей этого формата.
mbox
Формат mbox проще всего отображать в документации, поскольку он представляет собой полностью простой текст. Каждый почтовый ящик хранится в виде единого файла, в котором все сообщения объединяются. Каждый раз, когда встречается строка, начинающаяся с «From»
(«From», за которой следует один пробел), она рассматривается как начало нового сообщения. Каждый раз, когда эти символы появляются в начале строки в теле сообщения, они экранируются путем добавления к строке префикса ">"
.
Создание почтового ящика mbox
Создайте экземпляр класса mbox
, передав имя файла конструктору. Если файл не существует, он создается, когда add ()
используется для
mailbox_mbox_create.py
import mailbox import email.utils from_addr email.utils.formataddr(('Author', 'author@example.com')) to_addr email.utils.formataddr(('Recipient', 'recipient@example.com')) 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.\n') 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: AuthorTo: Recipient 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 To: Recipient Subject: Sample message 2 This is the second body.
Чтение почтового ящика mbox
Чтобы прочитать существующий почтовый ящик, откройте его и обращайтесь с объектом mbox
как со словарем. Ключи – это произвольные значения, определенные экземпляром почтового ящика, и они не обязательно имеют смысл, кроме как внутренние идентификаторы для объектов сообщения.
mailbox_mbox_read.py
import mailbox mbox mailbox.mbox('example.mbox') for message in mbox: print(message['subject'])
Открытый почтовый ящик поддерживает протокол итератора, но в отличие от настоящих объектов словаря итератор по умолчанию для почтового ящика работает со значениями значения вместо ключей .
$ 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: AuthorTo: Recipient Subject: Sample message 1 This is the body. >From (will not be escaped). There are 3 lines.
Maildir
Формат Maildir был создан для устранения проблемы одновременного изменения файла mbox. Вместо использования одного файла почтовый ящик организован как каталог, в котором каждое сообщение содержится в отдельном файле. Это также позволяет вкладывать почтовые ящики, поэтому API для почтового ящика Maildir расширен методами для работы с подпапками.
Создание почтового ящика Maildir
Единственная реальная разница между созданием Maildir
и mbox
заключается в том, что аргументом конструктора является имя каталога, а не имя файла. Как и раньше, если почтовый ящик не существует, он создается при добавлении сообщений.
mailbox_maildir_create.py
import mailbox import email.utils import os from_addr email.utils.formataddr(('Author', 'author@example.com')) to_addr email.utils.formataddr(('Recipient', 'recipient@example.com')) 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.\n') 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('\n***', 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: AuthorTo: Recipient Subject: Sample message 2 This is the second body. ******************** *** Example/new/1521404460.M303200P41689Q1.hubert.local From: Author To: Recipient Subject: Sample message 1 This is the body. From (will not be escaped). There are 3 lines. ******************** Example/cur Directories: [] Example/tmp Directories: []
После того как они будут прочитаны, клиент может переместить их в подкаталог 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('\nAfter:') 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: []
Чтение почтового ящика Maildir
Чтение из существующего почтового ящика 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('\n***', 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: AuthorTo: Recipient 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('\n{:#^30}\n'.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('\n{:#^30}\n'.format('')) subfolder.add_folder('second_level') print('second_level created:', subfolder.list_folders()) show_maildir('Example') print('\n{:#^30}\n'.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
имеют методы для извлечения и изменения значений флагов. В этом примере показаны флаги сообщений в Пример
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') # Tell the mailbox to update the message. mbox[message_id] message finally: mbox.flush() mbox.close() print('\nAfter:') 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') # Tell the mailbox to update the message. mbox[message_id] message finally: mbox.flush() mbox.close() print('\nAfter:') mbox mailbox.Maildir('Example') for message in mbox: print('{:6} "{}"'.format(message.get_flags(), message['subject']))
Флаг F
, добавленный в предыдущем примере, теряется, когда set_flags ()
заменяет флаги на S
в этом примере.
$ python3 mailbox_maildir_set_flags.py Before: F "Sample message 1" After: S "Sample message 1"
Другие форматы
mailbox
поддерживает несколько других форматов, но ни один из них не пользуется такой популярностью, как mbox или Maildir. MH – еще один формат многофайлового почтового ящика, используемый некоторыми почтовыми обработчиками. Babyl и MMDF – это однофайловые форматы с разными разделителями сообщений, чем
Смотрите также
- стандартная библиотека документации для почтового ящика
- Заметки о переносе Python 2 на 3 для почтового ящика
- man-страница mbox из qmail – документация для формата mbox.
- Справочная страница Maildir из