2015-07-04 14 views
1

Предположим, что я хочу составить заголовок электронной почты с кодированным тегом UTF-8, закодированным в кавычки, который является «test — UNIX-утилита для проверки типа файла и сравнения значений». Я могу подтвердить байты символов, используя: UTF-8 цитируемый для печати, многострочный объект для Thunderbird?

 
$ echo "UNIX-утилита ..." | perl utfinfo.pl 
Got 16 uchars 
Char: 'U' u: 85 [0x0055] b: 85 [0x55] n: LATIN CAPITAL LETTER U [Basic Latin] 
Char: 'N' u: 78 [0x004E] b: 78 [0x4E] n: LATIN CAPITAL LETTER N [Basic Latin] 
Char: 'I' u: 73 [0x0049] b: 73 [0x49] n: LATIN CAPITAL LETTER I [Basic Latin] 
Char: 'X' u: 88 [0x0058] b: 88 [0x58] n: LATIN CAPITAL LETTER X [Basic Latin] 
Char: '-' u: 45 [0x002D] b: 45 [0x2D] n: HYPHEN-MINUS [Basic Latin] 
Char: 'у' u: 1091 [0x0443] b: 209,131 [0xD1,0x83] n: CYRILLIC SMALL LETTER U [Cyrillic] 
Char: 'т' u: 1090 [0x0442] b: 209,130 [0xD1,0x82] n: CYRILLIC SMALL LETTER TE [Cyrillic] 
Char: 'и' u: 1080 [0x0438] b: 208,184 [0xD0,0xB8] n: CYRILLIC SMALL LETTER I [Cyrillic] 
... 

Итак, я пытаюсь получить UTF-8, цитируемое для печати представление этого. Например, с помощью языка Python quopri:

$ python -c 'import quopri; a="test — UNIX-утилита для проверки типа файла и сравнения значений"; print(quopri.encodestring(a));' 
test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB= 
=D1=8F =D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF= 
=D0=B0 =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0=D0=B2=D0=BD= 
=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9 

... или РНР quoted_printable_encode, который дает тот же результат:

$ php -r '$a="test — UNIX-утилита для проверки типа файла и сравнения значений"; echo quoted_printable_encode($a)."\n";' 
test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB= 
=D1=8F =D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF= 
=D0=B0 =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0=D0=B2=D0=BD= 
=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9 

Таким образом, чтобы проверить, я делаю текстовый файл с именем test.eml и попробовать просто обернуть этот выход в =?UTF-8?Q? ... ?= тегов для Subject: линии, убедившись, что линия окончания CRLF \r\n:

Message-Id: <[email protected]> 
Subject: =?UTF-8?Q?test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB= 
=D1=8F =D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF= 
=D0=B0 =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0=D0=B2=D0=BD= 
=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= 
Content-Type: text/plain; charset=UTF-8 
Content-Transfer-Encoding: 8bit 

Hello world 

... но если я открываю это в Thunderbird, я получаю коррумпированное выход:

test1

Я где-то читал, что многострочный в длинных полей заголовка покрывается RFC0822 «LONG HEADER ПОЛЕЙ», и в основном, завершение строки должно сопровождаться пробелом. Поэтому я отступа строки продолжения одним пробелом:

Message-Id: <[email protected]> 
Subject: =?UTF-8?Q?test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB= 
=D1=8F =D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF= 
=D0=B0 =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0=D0=B2=D0=BD= 
=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= 
Content-Type: text/plain; charset=UTF-8 
Content-Transfer-Encoding: 8bit 

Hello world 

... и я получаю slighly другую тему в Thunderbird, но все-таки поврежден:

test2.png

Теперь, если удалить из =\r\n первые три строки продолжения, так что объект находится все в одной строке:

Message-Id: <[email protected]> 
Subject: =?UTF-8?Q?test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB=D1=8F =D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF=D0=B0 =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0=D0=B2=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= 
Content-Type: text/plain; charset=UTF-8 
Content-Transfer-Encoding: 8bit 

Hello world 

... то на самом деле Thunderbird показывает тематический список т линия хорошо:

test3.png

... но мой заголовок находится в конфликте с рекомендацией от RFC 2822 - 2.1.1. Line Length Limits, который говорит: «Каждая строка символов не должен быть не более 998 символов, и не должно быть не более 78 символов, исключая CRLF. "; в частности, лимитный лимит в 78 символов.

Итак, как я могу получить правильное многострочное цитируемое представление строки заголовка заголовка UTF-8 Subject, поэтому я могу использовать его в файле с разделителем нас 78 символами - и Thunderbird правильно его прочитал?

ответ

1

Когда я спрашиваю питон, чтобы создать электронную почту с этой темой, вот что он делает:

$ python 
Python 2.7.9 (default, Mar 1 2015, 18:22:53) 
[GCC 4.9.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from email.message import Message 
>>> from email.header import Header 
>>> msg = Message() 
>>> import quopri 
>>> h = Header(quopri.decodestring('test =E2=80=94 UNIX-' 
    '=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB=D1=8F' 
    '=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8' 
    '=D0=BF=D0=B0 =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8' 
    '=D1=81=D1=80=D0=B0=D0=B2=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F ' 
    '=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?='), 'UTF-8') 
>>> msg['Subject'] = h 
>>> print msg.as_string() 
Subject: =?utf-8?b?dGVzdCDigJQgVU5JWC3Rg9GC0LjQu9C40YLQsCDQtNC70Y8g0L/RgNC+0LI=?= 
=?utf-8?b?0LXRgNC60Lgg0YLQuNC/0LAg0YTQsNC50LvQsCDQuCDRgdGA0LDQstC90LU=?= 
=?utf-8?b?0L3QuNGPINC30L3QsNGH0LXQvdC40Lk/?= 


>>> 

Так он использует кодирование base64 вместо кавычко печати, но мое сильное подозрение, на этом основании, что ответ заключается в том, что каждая строка должна начинаться и заканчиваться побегом.

Действительно:

>>> import email 
>>> s = '''Subject: =?UTF-8?Q?test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8=D0?= 
... =?UTF-8?Q?=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB=D1=8F =D0=BF=D1=80=D0?= 
... =?UTF-8?Q?=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF=D0=B0?= 
... =?UTF-8?Q? =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0=D0?= 
... =?UTF-8?Q?=B2=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0=D1?= 
... =?UTF-8?Q?=87=D0=B5=D0=BD=D0=B8=D0=B9?= 
... 
... Hello. 
... ''' 
>>> e = email.message_from_string(s.replace('\n', '\r\n')) 
>>> email.header.decode_header(e['Subject']) 
[('test \xe2\x80\x94 UNIX-\xd1\x83\xd1\x82\xd0\xb8\xd0\xbb\xd0\xb8\xd1\x82\xd0\xb0 \xd0\xb4\xd0\xbb\xd1\x8f \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb5\xd1\x80\xd0\xba\xd0\xb8 \xd1\x82\xd0\xb8\xd0\xbf\xd0\xb0 \xd1\x84\xd0\xb0\xd0\xb9\xd0\xbb\xd0\xb0 \xd0\xb8 \xd1\x81\xd1\x80\xd0\xb0\xd0\xb2\xd0\xbd\xd0\xb5\xd0\xbd\xd0\xb8\xd1\x8f \xd0\xb7\xd0\xbd\xd0\xb0\xd1\x87\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9', 'utf-8')] 
>>> decoded = email.header.decode_header(e['Subject']) 
>>> print decoded[0][0].decode(decoded[0][1]) 
test — UNIX-утилита для проверки типа файла и сравнения значений 

EDIT: Тем не менее, даже с вышеизложенным добавлены в EML-файл, Thunderbird снова не удалось:

test4,png

... но на этот раз указывает на правильность некоторых символов. И действительно, поломка происходит там, где линии сломаны «в середине персонажа»; скажем, если для последовательности 0xD1, 0x83 для символа у, =D1?= заканчивается на одну строку, а Q?=83 запускает другую, затем Thunderbird не может ее разобрать. Таким образом, после ручной перестройки, этот фрагмент может быть получен:

Message-Id: <[email protected]> 
Subject: =?UTF-8?Q?test =E2=80=94 UNIX-=D1=83=D1=82=D0=B8?= 
=?UTF-8?Q?=D0=BB=D0=B8=D1=82=D0=B0 =D0=B4=D0=BB=D1=8F =D0=BF=D1=80?= 
=?UTF-8?Q?=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8 =D1=82=D0=B8=D0=BF=D0=B0?= 
=?UTF-8?Q? =D1=84=D0=B0=D0=B9=D0=BB=D0=B0 =D0=B8 =D1=81=D1=80=D0=B0?= 
=?UTF-8?Q?=D0=B2=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F =D0=B7=D0=BD=D0=B0?= 
=?UTF-8?Q?=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= 
Content-Type: text/plain; charset=UTF-8 
Content-Transfer-Encoding: 8bit 

Hello world 

... который открывается прекрасным как .eml сообщения в Thunderbird (то же самое, как this image из ОП).

EDIT2: Кроме того, PHP, кажется, сделать это правильно, с этим вызовом mb_encode_mimeheader (непосредственно pasteable в .eml файле):

$ php -r '$a="test — UNIX-утилита для проверки типа файла и сравнения значений"; mb_internal_encoding("UTF-8"); echo mb_encode_mimeheader($a, "UTF-8", "Q")."\n";' 
test =?UTF-8?Q?=E2=80=94=20UNIX-=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82?= 
=?UTF-8?Q?=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= 
=?UTF-8?Q?=D1=80=D0=BA=D0=B8=20=D1=82=D0=B8=D0=BF=D0=B0=20=D1=84=D0=B0?= 
=?UTF-8?Q?=D0=B9=D0=BB=D0=B0=20=D0=B8=20=D1=81=D1=80=D0=B0=D0=B2=D0=BD?= 
=?UTF-8?Q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD?= 
=?UTF-8?Q?=D0=B8=D0=B9?= 
+0

Большое спасибо за это, @ DanielMartin - я отредактировал ваш ответ с решением, которое, наконец, сработало для меня. Ура! – sdaau

1

Проблема с test.eml в том, что ваш RFC2047 кодирование нарушается. Кодирование Q составляет на основе, но оно не совсем одно и то же. В частности, каждое пространство должно быть закодировано как =20 или _, и вы не можете избежать разрывов строк с окончательным =.

По существу, каждая последовательность =?...?= должна быть единым, недвусмысленным токеном на RFC 822. Вы можете либо разбить свой вход на несколько таких токенов, либо оставить пробелы незакодированными или закодировать пробелы. Обратите внимание, что пробелы между двумя такими токенами несущественны, поэтому кодирование пробелов в последовательности имеет больше смысла.

Message-Id: <[email protected]> 
Subject: =?UTF-8?Q?test_=E2=80=94_UNIX-=D1=83=D1=82=D0=B8=D0=BB?= 
=?UTF-8?Q?=D0=B8=D1=82=D0=B0_=D0=B4=D0=BB_=D1=8F_=D0=BF=D1=80?= 
=?UTF-8?Q?=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B8_=D1=82=D0=B8=D0=BF?= 
=?UTF-8?Q?=D0=B0_=D1=84=D0=B0=D0=B9=D0=BB=D0=B0_=D0=B8_=D1=81?= 
=?UTF-8?Q?=D1=80=D0=B0=D0=B2=D0=BD_=D0=B5=D0=BD=D0=B8=D1=8F_?= 
=?UTF-8?Q?=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9?= 
Content-Type: text/plain; charset=UTF-8 
Content-Transfer-Encoding: 8bit 

Hello world 

Конечно, с этой экспозиции, кавычко печати не очень разборчиво на всех, и, вероятно, занимает гораздо больше места, чем base64, так что вы можете предпочесть идти с B кодирования в конце концов все-таки.

Если вы сами не пишете MIME-библиотеку, простое решение не должно волновать и позволить библиотеке собрать это вместе для вас. PHP более проблематичен (стандартная библиотека не обладает этой функциональностью, а сторонние библиотеки несколько неравномерны - найдите тот, которому вы доверяете, и придерживайтесь его), но в Python просто передайте строку Unicode, а библиотека email будет закодируйте его, если необходимо.

+0

Я не квалифицирован, чтобы сделать рекомендацию для библиотеки PHP, и изо всех сил старался не предлагать вообще отказаться от PHP. – tripleee

 Смежные вопросы

  • Нет связанных вопросов^_^