Ответ 1
если строка содержит только ASCII, равна ли она строке в виде байтов?
Нет. Он не равен в Python 3:
>>> '1' == b'1'
False
bytes
объект не равен объекту str
(строка Unicode) аналогичным образом, когда целое число не равно строке:
>>> '1' == 1
False
В некоторых языках программирования приведенные выше сравнения верны, например, в Python 2:
>>> b'1' == u'1'
True
и 1 == '1'
в Perl:
$ perl -e "print qq(True\n) if 1 == q(1)"
True
Ваш вопрос - хороший пример того, почему более предпочтительное поведение Python 3 предпочтительнее. Это заставляет программистов противостоять ошибочным представлениям их текста/байта, не дожидаясь, когда их код сломается для некоторого ввода.
- Строки в Python 3 являются Unicode.
да. Строки являются неизменяемыми последовательностями кодовых точек Unicode в Python 3.
- Письма всегда ASCII.
Большинство писем переносятся как 7-битные сообщения (диапазон ASCII: hex 00-7F
). Хотя "практически все современные почтовые серверы имеют 8-битную чистоту" ., то есть 8-битное содержимое не будет повреждено. И расширение 8BITMIME санкционирует передачу некоторого 8-битного контента.
Другими словами: электронные письма не всегда ASCII.
- Pure ASCII действителен Unicode.
ASCII - кодировка символов. Вы можете декодировать некоторые последовательности байтов в Unicode с использованием кодировки символов US-ASCII. Строки Unicode не имеют связанной кодировки символов, то есть вы можете кодировать их в байтах, используя любую кодировку символов, которая может представлять соответствующие кодовые точки Unicode.
Поэтому электронное письмо, которое входит в систему, является чистым ASCII (который является действительным Unicode), поэтому строка SMTPD DATA в точности эквивалентна исходным байтам, полученным SMPTD. Правильно ли это?
Если вход находится в диапазоне ascii, тогда data.decode('ascii', 'strict').encode('ascii') == data
.
Хотя Lib/smtpd.py выполняет некоторые преобразования во входные данные (согласно RFC 5321
), поэтому контент, который вы получаете как data
, может быть другим даже если вход является чистым ASCII.
"Как сохранить файл Python 3 SMTPD DATA как ТОЧНО получаемые байты?"
Моя цель состоит не в том, чтобы найти неправильные электронные письма, а для того, чтобы сохранить входящие электронные письма на диск именно в форме бинарных/байтов, которые они прибыли.
Ошибка, с которой вы связались (smtpd.py не должен декодировать utf-8) делает smptd.py не 8-битным чистым.
Вы можете переопределить метод SMTPChannel.collect_incoming_data
из smtpd.py
, чтобы сохранить входящие байты как есть.
Это правда. Это приятное свойство кодировки UTF-8. Если вы можете декодировать последовательность байтов в Юникоде, используя кодировку символов US-ASCII, вы также можете декодировать байты с использованием кодировки символов UTF-8 (и получающиеся в результате кодовые точки Юникода в обоих случаях одинаковы).
smptd.py
должен был использовать либо latin1
(он декодирует любую последовательность байтов), либо ascii
(с "строгим" обработчиком ошибок для отказа в любом байте без ascii) вместо utf-8
(он позволяет некоторым не -ascii bytes - bad).
Имейте в виду:
- некоторые электронные письма могут иметь байты вне диапазона ascii
- de-transparent в соответствии с RFC 5321 не сохраняет входные байты как есть, даже если они все находятся в диапазоне ascii