Первым письмом здесь было то, которое мы послали с фиктивным адресом отправителя. Вторым было более легитимное сообщение. Как и в адресах отправителя, в строках заголовков SMTP также допускает некоторый произвол. Сценарий smtpmail автоматически добавляет строки заголовков «From» и «To» в текст сообщения с теми адресами, которые были переданы интерфейсу SMTP, но только в порядке жеста вежливости. Иногда, однако, нельзя узнать даже, кому было послано письмо — чтобы скрыть круг получателей или поддержать законные списки адресов, отправители могут манипулировать этими заголовками в тексте сообщения.
Например, если изменить сценарий smtpmail так, чтобы он не создавал автоматически строку заголовка «To:» с теми же адресами, которые передаются вызову интерфейса SMTP:
text = (‘From: %s\nDate: %s\nSubject: %s\n’ % (From, Date, Subj))
можно будет вручную ввести заголовок «To:», отличающийся от настоящего адреса получателя — методу отправки модуля smtplib будет передаваться действительный список адресатов, а строка заголовка «To:» в тексте сообщения — это то, что будут отображать большинство почтовых клиентов (в сценарии smtpmail-noTo.py в дереве примеров приводится реализация поддержки такого анонимного поведения, и не забудьте ввести пустую строку после ввода строки заголовка «To:»):
C:\…\PP4E\Internet\Email> smtpmail-noTo.py
From? Eric.the.Half.a.Bee@aol.com
Subj? a b c d e f g
Type message text, end with line=(ctrl + D or Z)
To: nobody.in.particular@marketing.com
Spam; Spam and eggs; Spam, spam, and spam.
"Z
Connecting… No errors.
Bye.
В некоторых отношениях адреса «From» и «To» в вызове метода отправки и в заголовках сообщения аналогичны адресу на конверте и письму в конверте. Первое используется для пересылки, а второе представляет то, что видит читатель. Здесь оба адреса «From» являются фиктивными. Кроме того, я указал действительный адрес «To», но в строке заголовка «To:» я вручную ввел фиктивное имя — первый адрес определяет действительное место доставки сообщения, а второй отображается клиентами электронной почты. Если ваш клиент отображает строку «To:», такое письмо при просмотре будет выглядеть немного странным.
Например, если посмотреть, как отображается письмо, которое мы только что отправили, в моем почтовом ящике на сайте learning-python.com, то будет очень сложно сказать, кем и кому было отправлено это письмо, в том веб-интерфейсе, который предоставляет мой интернет-провайдер, как показано на рис. 13.5.
Рис. 13.5 Анонимное письмо в клиенте с веб-интерфейсом (смотрите также пример PyMailGUI далее)
Кроме того, и необработанный текст сообщения не поможет нам в этом, разве только внимательнее посмотреть на заголовки «Received:», добавляемые серверами, через которые пересылалось письмо:
C:\…\PP4E\Internet\Email> popmail.py
Password for pop.secureserver.net?
Connecting…
b’+OK <4802.1273156821@p3plpop03-03.prod.phx3.secureserver.net>’
There are 5 mail messages in 6364 bytes
(b’+OK ‘, [b’1 1860′, b’2 1408′, b’3 1049′, b’4 1009′, b’5 1038′], 40)
————————————————————————
[Press Enter key]
…первые три письма опущены…
Received: (qmail 30325 invoked from network); 6 May 2010 14:33:45 -0000
Received: from unknown (HELO p3pismtp01-004.prod.phx3.secureserver.net) ([10.6.1 (envelope-sender <Eric.the.Half.a.Bee@aol.com>) by p3plsmtp06-03.prod.phx3.secureserver.net (qmail-1.03) with SMTP for <PP4E@learning-python.com>; 6 May 2010 14:33:45 -0000
…часть строк опущена…
Received: from [66.194.109.3] by smtp.mailmt.com (ArGoSoft Mail
Server .NET v.1.
for <PP4E@learning-python.com>; Thu, 06 May 2010 10:33:16 -0400
From: Eric.the.Half.a.Bee@aol.com
Date: Thu, 06 May 2010 14:32:32 -0000
Subject: a b c d e f g
To: nobody.in.particular@marketing.com
Message-ID: <66koqg66e0q1c8hl06052010103316@SMTP>
X-FromIP: 66.194.109.3
X-Nonspam: None
Spam; Spam and eggs; Spam, spam, and spam.
Bye.
Еще раз повторю — не делайте так без веских причин. Я показываю это только с целью помочь вам понять, какую роль играют заголовки письма в процессе обработки электронной почты. Чтобы написать автоматический спам-фильтр, удаляющий нежелательную входящую почту, например, вам потребуется изучить контрольные признаки и научиться отыскивать их в тексте сообщения. Приемы, применяемые при рассылке спама, становятся все более изощренными, и по сложности давно превзошли простую подделку адресов отправителя и получателя (более подробную информацию по этой теме вы найдете в Интернете в целом и в почтовом фильтре SpamBayes, написанном на языке Python), но это одна из наиболее распространенных хитростей.
Кроме того, фокусы с адресами «To» могут оказаться полезными в контексте законных списков рассылки — при просмотре сообщения в заголовке «To:» выводится название списка, а не список потенциально большого количества получателей, указанных в вызове метода отправки сообщения. Как будет показано в следующем разделе, почтовый клиент легко может отправить сообщение всем получателям в списке, но вставить общее название списка в заголовок «To:».
Но в других ситуациях отправка электронной почты с фальшивыми строками «From:» и «To:» эквивалентна анонимным телефонным звонкам. Большинство почтовых программ не позволяет изменить строку «From» и не делает отличия между адресом получателя и строкой заголовка «To», хотя SMTP широко открыт в этом отношении.
В предыдущей версии сценария smtpmail, представленной в примере 13.19, в заголовок «Date» записывалось текущее время и дата в простом формате, который не совсем соответствует стандарту форматирования даты в SMTP:
>>> import time
>>> time.asctime()
‘Wed May 05 17:52:05 2010′
Большинство серверов не обращают внимания на этот заголовок и позволяют вставлять в него любой текст с датой или даже могут сами добавлять его при необходимости. Клиенты тоже часто проявляют подобную беззаботность, но не всегда. Одна из программ с веб-интерфейсом, предоставляемая моим интернет-провайдером, корректно отображает даты в любом случае, но другая оставляет такие неправильно отформатированные значения пустыми при отображении. При желании как можно точнее соответствовать стандартам вы можете форматировать заголовок с датой с помощью следующего программного кода (результат которого может быть проанализирован любыми стандартными инструментами, такими как функция time.strptime):
import time
gmt = time.gmtime(time.time())
fmt = ‘%a, %d %b %Y %H:%M:%S GMT’
str = time.strftime(fmt, gmt) hdr = ‘Date: ‘ + str print(hdr)
После выполнения этого фрагмента значение переменной hdr будет иметь следующий вид:
Date: Wed, 05 May 2010 21:49:32 GMT
>>> import email.utils
>>> email.utils.formatdate()
‘Wed, 05 May 2010 21:54:28 -0000′
>>> email.utils.formatdate(localtime=True)
‘Wed, 05 May 2010 17:54:52 -0400′
>>> email.utils.formatdate(usegmt=True)
‘Wed, 05 May 2010 21:55:22 GMT‘
Смотрите описание примеров pymail и mailtools в этой главе, где вы увидите дополнительные способы использования. Последний повторно используется в крупных почтовых клиентах PyMailGUI и PyMailCGI, представленных далее в этой книге.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011