Язык программирования Python.
Пакет 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" <zinakinch@thecanadianteacher.com>
>>> 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'].
Из списка parts можно увидеть, что само сообщение имеет тип multipart/mixed, тогда как две его части — text/html и application/octet–stream соответственно. Только с последней частью связано имя файла ( price.cpl). Файл читается методом get_payload() и вычисляется его длина.
Кстати, в случае, когда сообщение является контейнером для других частей, get_payload() выдает список объектов–сообщений (то есть экземпляров класса Message).
Формирование сообщения.
Часто возникает ситуация, когда нужно сформировать сообщение с вложенным файлом. В следующем примере строится сообщение с текстом и вложением. В качестве класса для порождения сообщения можно использовать не только Message из модуля email.Message, но и MIMEMultipart из email.MIMEMultipart (для сообщений из нескольких частей), MIMEImage (для сообщения с графическим изображением), MIMEAudio (для аудиофайлов), MIMEText (для текстовых частей):
# Загружаются необходимые модули и функции из модулей.
From email.Header import make_header as mkh.
From email.MIMEMultipart import MIMEMultipart.
From email.MIMEText import MIMEText.
From email.MIMEBase import MIMEBase.
From email.Encoders import encode_base64.
# Создается главное сообщение и задаются некоторые поля.
Msg = MIMEMultipart().
Msg["Subject"] = mkh([("Привет", "koi8–r")]).
Msg["From"] = mkh([("Друг", "koi8–r"), ("<friend@mail.ru>", "us–ascii")]).
Msg["To"] = mkh([("Друг2", "koi8–r"), ("<friend2@yandex.ru>", "us–ascii")]).
# То, чего будет не видно, если почтовая программа поддерживает MIME.
Msg.preamble = "Multipart message".
Msg.epilogue = "".
# Текстовая часть сообщения.
Text = u"""К письму приложен файл с архивом.""".encode("koi8–r").
To_attach = MIMEText(text, _charset="koi8–r").
Msg.attach(to_attach).
# Прикладывается файл.
Fp = open("archive_file.zip", "rb").
To_attach = MIMEBase("application", "octet–stream").
To_attach.set_payload(fp.read()).
Encode_base64(to_attach).
To_attach.add_header("Content–Disposition", "attachment",
filename="archive_file.zip").
Fp.close().
Msg.attach(to_attach).
Print msg.as_string().
В этом примере видно сразу несколько модулей пакета email. Функция make_header() из email.Header позволяет закодировать содержимое для заголовка:
>>> from email.Header import make_header.
>>> print make_header([("Друг", "koi8–r"), ("<friend@mail.ru>", "us–ascii")]).
=?koi8–r?b?5NLVxw==?= <friend@mail.ru>
>>> print make_header([(u"Друг", ""), ("<friend@mail.ru>", "us–ascii")]).
=?utf–8?b?w6TDksOVw4c=?= <friend@mail.ru>
Функция email.Encoders.encode_base64() воздействует на переданное ей сообщение и кодирует тело с помощью base64. Другие варианты: encode_quopri() — кодировать quoted printable, encode_7or8bit() — оставить семь или восемь бит. Эти функции добавляют необходимые поля.
Аргументы конструкторов классов из MIME–модулей пакета email:
Class MIMEBase(_maintype, _subtype, **_params).
Базовый класс для всех использующих MIME сообщений (подклассов Message). Тип содержимого задается через _maintype и _subtype.
Class MIMENonMultipart().
Подкласс для MIMEBase, в котором запрещен метод attach(), отчего он гарантированно состоит из одной части.
Class MIMEMultipart([_subtype[, boundary[, _subparts[, _params]]]]).
Подкласс для MIMEBase, который является базовым для MIME–сообщений из нескольких частей. Главный тип multipart, подтип указывается с помощью _subtype.
Class MIMEAudio(_audiodata[, _subtype[, _encoder[, **_params]]]).
Подкласс MIMENonMultipart. Используется для создания MIME–сообщений, содержащих аудио данные. Главный тип — audio, подтип указывается с помощью _subtype. Данные задаются параметром _audiodata.
Class MIMEImage(_imagedata[, _subtype[, _encoder[, **_params]]]).
Подкласс MIMENonMultipart. Используется для создания MIME–сообщений с графическим изображением. Главный тип — image, подтип указывается с помощью _subtype. Данные задаются параметром _imagedata.
Class MIMEMessage(_msg[, _subtype]).
Подкласс MIMENonMultipart для класса MIMENonMultipart используется для создания MIME–объектов с главным типом message. Параметр _msg применяется в качестве тела и должен являться экземпляром класса Message или его потомков. Подтип задается с помощью _subtype, по умолчанию 'rfc822'.
Class MIMEText(_text[, _subtype[, _charset]]).
Подкласс MIMENonMultipart. Используется для создания MIME–сообщений текстового типа. Главный тип — text, подтип указывается с помощью _subtype. Данные задаются параметром _text. Посредством _charset можно указать кодировку (по умолчанию 'us–ascii').
Разбор поля заголовка.
В примере выше поле Subject формировалось с помощью email.Header.make_header(). Разбор поля поможет провести другая функция: email.Header.decode_header(). Эта функция возвращает список кортежей, в каждом из них указан кусочек текста поля и кодировка, в которой этот текст был задан. Следующий пример поможет понять суть дела:
Subj = """=?koi8–r?Q?=FC=D4=CF_=D0=D2=C9=CD=C5=D2_=CF=DE=C5=CE=D8_=C4=CC=C9?=
=?koi8–r?Q?=CE=CE=CF=C7=CF_=28164_bytes=29_=D0=CF=CC=D1_=D3_=D4?=
=?koi8–r?Q?=C5=CD=CF=CA_=D3=CF=CF=C2=DD=C5=CE=C9=D1=2E_=EF=CE=CF_?=
=?koi8–r?Q?=D2=C1=DA=C2=C9=CC=CF=D3=D8_=CE=C1_=CB=D5=D3=CB=C9_=D7?=
=?koi8–r?Q?_=D3=CF=CF=C2=DD=C5=CE=C9=C9=2C_=CE=CF_=CC=C5=C7=CB=CF?=
=?koi8–r?Q?_=D3=CF=C2=C9=D2=C1=C5=D4=D3=D1_=D7_=D4=C5=CB=D3=D4_?=
=?koi8–r?Q?=D3_=D0=CF=CD=CF=DD=D8=C0_email=2EHeader=2Edecode=5Fheader?=
=?koi8–r?Q?=28=29?=""".
Import email.Header.
For text, enc in email.Header.decode_header(subj):
print enc, text.
В результате будет выведено:
Koi8–r Это пример очень длинного (164 bytes) поля с темой сообщения.
Оно разбилось на куски в сообщении, но легко собирается в текст.
С помощью email.Header.decode_header().
Следует заметить, что кодировку можно не указывать:
>>> email.Header.decode_header("simple text").
[('simple text', None)].
>>> email.Header.decode_header("пример").
[('\xd0\xd2\xc9\xcd\xc5\xd2', None)].
>>> email.Header.decode_header("=?KOI8–R?Q?=D0=D2=CF_?=Linux").
[('\xd0\xd2\xcf ', 'koi8–r'), ('Linux', None)].
Если в первом случае можно подразумевать us–ascii, то во втором случае о кодировке придется догадываться: вот почему в электронных письмах нельзя просто так использовать восьмибитные кодировки. В третьем примере русские буквы закодированы, а латинские — нет, поэтому в результате email.Header.decode_header() список из двух пар.
В общем случае представить поле сообщения можно только в Unicode. Создание функции для такого преобразования предлагается в качестве упражнения.
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.