Итак, пока наш раздел «Issues» в проекте молчит — черпаем ошибки и идеи для дальнейшей работы из комментариев блога. И первое, что попалось на глаза из последних тем, касающихся работы с сервисами Google — это отправка писем с Gmail с использованием библиотеки Synapse.
За основу для работы были взяты два комментария читателей. Первый комментарий можно расценить и как недочёт и как идею для дальнейшей работы и касался этот комментарий следующей темы:
при отправке письма с GMail на любой другой почтовый ящик всё работает прекрасно, но MS Outlook никак не желает принимать кодировку и выводит вместо заголовка кракозябры (обычное дело при проблеме с кодировками). При этом в том же Яндекс или Mail.ru всё в порядке — проблем с кодировками нет.
Второй комментарий касался «особенности» компонента — почему-то при отправке одной строки пользователю приходило пуcтое письмо.
Рассмотрим все по порядку.
Начнем с самого простого — отправка одной строки. Запускаем Demo-проект, заполняем все необходимые поля и добавляем в поле Memo всего одну строку «Привет». Так как в письмо можно вставить несколько различный частей как текстовых, так и HTML-кода, то под Memo есть соответствующие кнопки: «Добавить как текст» и «Добавить как HTML«. Жмем «Добавить как текст» и получаем подтверждение:
Теперь жмем кнопку «Отправить» и получаем ещё одно подтверждение:
Проверяем почту (я отправлял на Яндекс):
Скрин хреновенький, но, тем не менее, видно, что наша одна строка нормально переслалась. Следовательно, господа, у кого не пересылается одна строка — подробный ход ваших действий «в студию» — будем разбираться. Пока я явных ошибок в этой части не нашел.
Совершенно другое дело с Outlook. Сам я дома почтовыми клиентами не пользовался, но теперь пришлось. Итак, повторяем все те же действия, что и вначале — отправляем письмо на почту, но только грузим его через Outlook:
Здесь я для верности отправил письмо дважды. При этом верхнее на скрине письмо было отправлено как HTML, а второе — как простой текст. Содержимое письма было одинаково — слово «Привет».
Кликните на скрин, чтобы увидеть, что у двух одинаковых писем, почему-то совершенно разные «кракозябры» и также само совершенно нормальный текст письма. По верхнему письму опытный глаз веб-мастера сразу заметит UTF-8, а вот нижняя кодировка — загадка.
Но не в этом суть. Раз проблема с кодировками — будем искать где они устанавливаются. Открываем модуль mimepart.pas и ищем в нем описание класса TMimePart. В числе прочих полезных свойств класса есть следующие:
property DefaultCharset: string read FDefaultCharset write FDefaultCharset; property CharsetCode: TMimeChar read FCharsetCode Write FCharsetCode;//кодировка чисти письма property TargetCharset: TMimeChar read FTargetCharset Write FTargetCharset;//кодировка, используемая в ОС
Обратите внимание на описание первого свойства:
Определяет кодировку по умолчанию для декодирования MIME частей текста без учёта спецификации. Значение по умолчанию ‘ISO-8859-1’, согласно документам RCF. Но Microsoft Outlook использует Windows-кодировки по умолчанию. Это свойство позволяет правильно декодировать текстовst части в Microsoft Outlook. (Это плохое программное обеспечение!)
Только судя по этому объяснению наличия свойства в классе можно уже сказать, что проблема далеко не столько в Synapse сколько в Outlook. Теперь двигаемся дальше и разберемся почему в двух одинаковых письмах Outlook указал нам на две разные кодировки (все-таки как бы ни ругали этот почтовый клиент, но быть того не может, чтобы разработчики были уж настолько плохи).
Для этого посмотрим как добавляются новые части в сообщение. Вначале функция добавления простого текста:
function TMimeMess.AddPartText(const Value: TStrings; const PartParent: TMimePart): TMimepart; begin Result := AddPart(PartParent);//добавили новую часть with Result do begin Value.SaveToStream(DecodedLines);//записали текст Primary := 'text'; Secondary := 'plain'; Description := 'Message text'; Disposition := 'inline'; CharsetCode := IdealCharsetCoding(Value.Text, TargetCharset, IdealCharsets);//(!!!!) подбор оптимальной кодировки EncodingCode := ME_QUOTED_PRINTABLE; EncodePart; //закодировали весь текст и составили заголовки EncodePartHeader;//закодировали заголовки end; end;
Смотрим, что нам скажет описание функции IdealCharsetCoding:
Ищет лучшую кодировку из множества TMimeChars для минимального количества потерь неконвертируемых символов
Причём кодировок в множестве порядка 100 штук и начинается поиск с ISO_8859_1. И, как оказалось, на этой же кодировке и заканчивается:
Пробуем исправить ситуацию и добавить текст без всяких вспомогательных функций, то есть использовать основной метод AddPart и добавить текст, используя CharsetCode кодировку из свойства TargetCharset (которая, по-моему, самая что ни есть идеальная):
function TGMailSMTP.AddText(const aText: string): boolean; var s:TStringList; Part:TMimePart; begin Part:= FMsg.AddPart(FMIMEPart); with Part do begin S:=TStringList.Create; S.Text:=aText; S.SaveToStream(DecodedLines); Primary := 'text'; Secondary := 'plain'; Description := 'Message text'; Disposition := 'inline'; CharsetCode :=TargetCharset;//ставим кодировку как в ОС EncodingCode := ME_QUOTED_PRINTABLE; EncodePart; EncodePartHeader; end; end;
Как видите — поменяли всего одну строку. Отсылаем письмо с пламенным «привет» на тот же ящик и загружаем тем же OutLook:
Всё в порядке — кодировки в норме. Письмо читабельно на 100% хоть через он-лайн интерфейс почтовика, хоть через почтового клиента.
Аналогичным образом решается и проблема с добавлением HTML, только там во вспомогательном методе AddPartHTML сразу намертво забивается кодировка UTF-8 без всякого поиска идеалов — задаете свою кодировку и письмо с HTML-кодом также нормально принимается и обрабатывается почтовыми клиентами.
В заключении можно сказать следующее:
- OutLook — зло, но вполне сносное. При должной настройке будет работать вполне нормально. В статье я использовал Outlook 2007.
- Разработчики Synapse немного перестарались с поиском идеальных кодировок, а точнее немного недостарались — в методе IdealCharsetCoding, думаю, следовало бы останавливаться не на первой попавшейся подходящей кодировке, а все-таки отдавать предпочтение при прочих равных результатах дефолтной — той, которая используется в ОС…хотя я RFC не читал и могу чего-то и не знать.
В ближайшее время сделаю апдейт в репозитории — выложу немного подправленный вариант компонента, «special for ms outlook» так сказать. Найдете ошибки — пишите о них подробно в разделе Issues — буду исправлять
Книжная полка
Описание: Рассмотрены практические вопросы по разработке клиент-серверных приложений в среде Delphi 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
|
||
Название: О чем не пишут в книгах по Delphi
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
|
>>> но быть того не может, чтобы разработчики были уж настолько плохи
http://www.transl-gunsmoker.ru/2009/12/blog-post_24.html
Александр, эта ссылка значит, что разработчики Synapse не читали RFC и «от балды» указали дефолтную кодировку? Или наоборот, разработчики OutLook действуют не по стандарту? Ссылка, конечно хорошо, но как бы аргуменировать чтоль надо её положение в посте :)
Влад, даже разработчики, которые стараются соблюдать все стандарты (Thunderbird) до сих пор некорректно обрабатывают заголовок темы в юникоде, если она разбивается на несколько строк.
А то, что Микрософт чхала на стандарты — это уже давно известный факт. Идеальный пример — IE.
Кирилл, полностью с Вами согласен!
>>> Александр, эта ссылка значит, что разработчики Synapse не читали RFC и “от балды” указали дефолтную кодировку? Не, имелось ввиду, что говоря «ну не может же такого быть», вы рассматривали Outlook в сферическом вакууме. Я не думаю, что указание неверной кодировки в Synapse имеет какое-то отношение к RFC — там же ничего не говорится про реализацию, а только про стандарты протоколов. А упомянутое явление — видимо, баг в IdealCharsetCoding (отправили разработчикам?). В реальной жизни MS не слишком-то соблюдает стандарты, но происходит это не потому, как указал Кирилл, что она «чхает на них», а как раз наоборот — потому что на… Подробнее »
>>>А упомянутое явление – видимо, баг в IdealCharsetCoding (отправили разработчикам?). Пока нет. Хочу разобраться почему DefaultCharset не помогает решить проблему с кодировками. Такое ощущение, что свойство просто не работает так как было задумано. >>>Все ругают IE. Мало кто понимает, что это не его вина – он просто копирует Netscape. Александр, «просто копирует» ни как не освобождает разработчиков от ответственности за их работу. Разве не так? Мало ли, что было взято за основу — они создают свой продукт на основе Netscape, а не просто копируют. Так можно в итоге докговориться до «я не виноват, что моя программа не работает правильно, просто… Подробнее »
>>> ни как не освобождает разработчиков от ответственности за их работу Да само собой, только в большинстве случаев выбора-то особо и нет. Альтернативы будут хуже. К примеру, секретный план всех ругающих IE обычно выглядит так: 1. Написать браузер, соответствующий стандартам на 100%. 2. ??? 3. PROFIT!!! Проблема в п2, который звучит так: «никто не будет использовать этот браузер, потому что в нём не работает ни один сайт». До п3 дело просто не дойдёт. Вы не можете изменить миллионы сайтов. Единственное, что вы можете сделать — написать браузер, в котором они будут работать. А это значит, что ваш браузер не будет… Подробнее »
>>>К примеру, секретный план всех ругающих IE обычно выглядит так:
:) никогда не вынашивал подобные планы. Но IE обычно использую только 1 раз — когда надо скачать другой браузер, например FF. Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки. Не соблюдаешь рекомендации — могут возникнуть проблемы. Так собственно и происходит. Только у кого-то продукты глючат больше, а у кого-то меньше в зависимости от того кто учше соблюдал эти самые рекомендации.
>>> Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки Да, это то, что всем хочется думать, что это правда, но в реальности это просто не работает. Ядро проблемы в том, что вы думаете, что есть один стандарт, но так как никто не может реально протестировать на соответствие с ним, то стандарт этот — виртуальный: это платонический идеал и набор недоразумений, а следовательно такой стандарт не служит достижению желаемой цели. DOCTYPE — это миф. Обычный смертный, который включил DOCTYPE себе в страницу, приговаривая «это стандартный HTML» — нагло врёт.… Подробнее »
Не очень правильно менять исходники, когда для указания кодировки есть расширенная функция AddPartTextEx.
вместо
AttachMess.AddPartText(lst, MimePart);
используем
AttachMess.AddPartTextEx(lst, MimePart, UTF_8, true, ME_BASE64);
пробовал всё что вы выше написали, поискал немного в интернете и наткнулся на хорошую статью
http://developers.do.am/publ/delphi/biblioteka_synapse/biblioteka_synapse_sozdanie_fajla_pisma_msg/9-1-0-35
а точнее на этот кусок [code] 3 Highlander1981 (14.06.2010 17:35) Тоже долго мучился этим вопросом и нашел таки решение. Сам разработчик (Lukas Gebauer) написал, что Header.CharsetCode указывает на исходную кодировку, а не на ту в которую нужно перевести заголовки. А выходная кодировка выбирается автоматически из IdealCharsets (synachar.pas): IdealCharsets: TMimeSetChar = [ISO_8859_1, ISO_8859_2, ISO_8859_3, ISO_8859_4, ISO_8859_5, ISO_8859_6, ISO_8859_7, ISO_8859_8, ISO_8859_9, ISO_8859_10, KOI8_R, KOI8_U {$IFNDEF CIL} //error URW778 ??? :-O , GB2312, EUC_KR, ISO_2022_JP, EUC_TW {$ENDIF} ]; Мне нужно было использовать Windows-1251, так что я заменил код: IdealCharsets: TMimeSetChar = [CP1251 {$IFNDEF CIL} //error URW778 ??? :-O , GB2312, EUC_KR, ISO_2022_JP, EUC_TW… Подробнее »
>x_tasy пишет:
>16 Aug 2010 в 2:52 pm
>
>Не очень правильно менять исходники, когда для указания кодировки есть расширенная функция >AddPartTextEx.
пробовал, на почту бред приходил…
Ну, x_tasy, в целом прав — если уж править исходник, то так, чтобы не было мучительно больно за бесцельно прожитые годы :) Точнее за то, что в другой ситуации правка может привести к очередной проблеме в программе. Я обычно, когда не могу получить кодировку через свойства начинаю перебирать все заголовки в поисках «Content-Type…..charset….», не трогая исходник.
Были проблемы с кодировкой и при отправке, но вроде как для своей задачи разобрался, опять таки не трогая исходников
исходники можно мучать, понимая программирование… но сама программа будет не универсальна для других пользователей в виде исходных кодов… а так как я пишу в личных целях)) то могу спокойно подгонять исходные коды модулей…
ну так да, можно и поковырять :)