Для разных нужд обычно требуется иметь несколько вариантов классов читающих и пишущих объектов. Новые классы могут получаться наследованием от базовых классов либо обертыванием функций, предоставляемых модулем расширения (написанным на C). В приведенном примере DictReader и DictWriter являются обертками для функций reader и writer и объектов, которые они порождают.
Пакет email
Модули пакета email помогут разобрать, изменить и сгенерировать сообщение в формате RFC 2822. Наиболее часто RFC 2822 применяется в сообщениях электронной почты в Интернете.
В пакете есть несколько модулей, назначение которых (кратко) указано ниже:
Листинг
Message
Модуль определяет класс Message — основной класс для представления сообщения в пакете email.
Листинг
Parser
Модуль для разбора представленного в виде текста сообщения с получением объектной структуры сообщения.
Листинг
Header
Модуль для работы с полями, в которых используется кодировка, отличная от ASCII.
Листинг
Generator
Порождает текст сообщения RFC 2822 на основании объектной модели.
Листинг
Utils
Различные утилиты, которые решают разнообразные небольшие задачи, связанные с сообщениями.
В пакете есть и другие модули, которые здесь рассматриваться не будут.
Разбор сообщения. Класс Message
Класс Message — центральный во всем пакете email. Он определяет методы для работы с сообщением, которое состоит из заголовка (header) и тела (payload). Поле заголовка имеет название и значение, разделенное двоеточием (двоеточие не входит ни в название, ни в значение). Названия полей нечувствительны к регистру букв при поиске значения, хотя хранятся с учетом регистра. В классе также определены методы для доступа к некоторым часто используемым сведениям (кодировке сообщения, типу содержимого и т.п.).
Следует заметить, что сообщение может иметь одну или несколько частей, в том числе вложенных друг в друга. Например, сообщение об ошибке доставки письма может содержать исходное письмо в качестве вложения.
Пример наиболее употребительных методов экземпляров класса Message с пояснениями:
Листинг
>>> import email
>>> input_file = open(«pr1.eml»)
>>> msg = email.message_from_file(input_file)
Здесь используется функция email.message_from_file для чтения сообщения из файла pr1.eml. Сообщение можно получить и из строки с помощью функции email.message_from_string. А теперь следует произвести некоторые операции над этим сообщением (не стоит обращать внимания на странные имена — сообщение было взято из папки СПАМ). Доступ к полям по имени осуществляется так:
Листинг
>>> print msg['from']
«felton olive»
>>> msg.get_all('received')
['from mail.onego.ru\n\tby localhost with POP3 (fetchmail–6.2.5
polling mail.onego.ru account spam)\n\tfor spam@localhost
(single–drop); Wed, 01 Sep 2004 15:46:33 +0400 (MSD)',
'from thecanadianteacher.com ([222.65.104.100])\n\tby mail.onego.ru
(8.12.11/8.12.11) with SMTP id i817UtUN026093;\n\tWed, 1 Sep 2004
11:30:58 +0400']
Стоит заметить, что в электронном письме может быть несколько полей с именем received (в этом примере их два).
Некоторые важные данные можно получить в готовом виде, например, тип содержимого, кодировку:
Листинг
>>> msg.get_content_type
'text/plain'
>>> print msg.get_main_type, msg.get_subtype
text plain
>>> print msg.get_charset
None
>>> print msg.get_params
[('text/plain', ''), ('charset', 'us–ascii')]
>>> msg.is_multipart
False
или список полей:
Листинг
>>> print msg.keys
['Received', 'Received', 'Message–ID', 'Date', 'From', 'User–Agent',
'MIME–Version', 'To', 'Subject', 'Content–Type',
'Content–Transfer–Encoding', 'Spam', 'X–Spam']
Так как сообщение состоит из одной части, можно получить его тело в виде строки:
Листинг
>>> print msg.get_payload
sorgeloosheid hullw ifesh nozama decompresssequenceframes
Believe it or not, I have tried several sites to b»_«uy presription
medication. I should say that currently you are still be the best amony
…
Теперь будет рассмотрен другой пример, в котором сообщение состоит из нескольких частей. Это сообщение порождено вирусом. Оно состоит из двух частей: HTML–текста и вложенного файла с расширением cpl. Для доступа к частям сообщения используется метод walk, который обходит все его части. Попутно следует собрать типы содержимого (в списке parts), поля Content–Type (в ct_fields) и имена файлов (в filenames):
Листинг
import email
parts = []
ct_fields = []
filenames = []
f = open(«virus.eml»)
msg = email.message_from_file(f)
for submsg in msg.walk:
parts.append(submsg.get_content_type)
ct_fields.append(submsg.get('Content–Type', ''))
filenames.append(submsg.get_filename)
if submsg.get_filename:
print «Длина файла:", len(submsg.get_payload)
f.close
print parts
print ct_fields
print filenames
В результате получилось:
Листинг
Длина файла: 31173
['multipart/mixed', 'text/html', 'application/octet–stream']
['multipart/mixed;\n boundary=" — — — — hidejpxkblmvuwfplzue»',
'text/html; charset=«us–ascii»',
'application/octet–stream; name=«price.cpl»']
[None, None, 'price.cpl']