Опубликован: 22.12.2005 | Уровень: для всех | Доступ: платный
Лекция 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. Создание функции для такого преобразования предлагается в качестве упражнения.

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

Добрый день.

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

 

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

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

Максим Чиндясов
Максим Чиндясов
Россия, Нижний Новгород
Ольга Коваль
Ольга Коваль
Беларусь, Минск