Опубликован: 22.12.2005 | Доступ: свободный | Студентов: 24084 / 1831 | Оценка: 4.18 / 3.71 | Длительность: 16:10:00
ISBN: 978-5-9556-0109-0
Лекция 7:

Работа с данными в различных форматах

Формирование сообщения

Часто возникает ситуация, когда нужно сформировать сообщение с вложенным файлом. В следующем примере строится сообщение с текстом и вложением. В качестве класса для порождения сообщения можно использовать не только 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. Создание функции для такого преобразования предлагается в качестве упражнения.

Сергей Крупко
Сергей Крупко

Добрый день.

Я сейчас прохожу курс  повышения квалификации  - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?

 

Павел Ялганов
Павел Ялганов

Скажите экзамен тоже будет ввиде теста? или там будет какое то практическое интересное задание?