Итак, пока наш раздел "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 Day". Автора этого блога я уже упоминал (добрым словом) несколько раз в своих постах, теперь упомяну и блог. А блог надо сказать мне очень даже нравится. В последнее время, Егор пишет цикл статей по зашите Delphi-программ от взлома - отличная тема, а самое главное - понятное человеческое описание всех приемов, методов, софта и т.д. На данный момент опубликовано четыре статьи из серии. Также в блоге есть интересная информация по ассемблеру. В общем блог, на мой взгляд, отличный. Так держать, Егор ;).
--------------------------------------
Кстати, больше всего посетителей от Егора пришло с главной страницы - кликали по баннеру. Так что желающие поучаствовать в акции "Бесплатный мини-обзор Вашего блога" возьмите на заметку - баннеры блога находятся здесь.
| Делись! | Загружай! | Плюсуй! |
| | |










27 Июл 2010 в 12:58 пп
>>> но быть того не может, чтобы разработчики были уж настолько плохи
http://www.transl-gunsmoker.ru/2009/12/blog-post_24.html
27 Июл 2010 в 1:18 пп
Александр, эта ссылка значит, что разработчики Synapse не читали RFC и «от балды» указали дефолтную кодировку? Или наоборот, разработчики OutLook действуют не по стандарту? Ссылка, конечно хорошо, но как бы аргуменировать чтоль надо её положение в посте :)
27 Июл 2010 в 4:48 пп
Влад, даже разработчики, которые стараются соблюдать все стандарты (Thunderbird) до сих пор некорректно обрабатывают заголовок темы в юникоде, если она разбивается на несколько строк.
А то, что Микрософт чхала на стандарты — это уже давно известный факт. Идеальный пример — IE.
28 Июл 2010 в 4:40 дп
Кирилл, полностью с Вами согласен!
28 Июл 2010 в 3:06 пп
>>> Александр, эта ссылка значит, что разработчики Synapse не читали RFC и “от балды” указали дефолтную кодировку?
Не, имелось ввиду, что говоря «ну не может же такого быть», вы рассматривали Outlook в сферическом вакууме. Я не думаю, что указание неверной кодировки в Synapse имеет какое-то отношение к RFC — там же ничего не говорится про реализацию, а только про стандарты протоколов. А упомянутое явление — видимо, баг в IdealCharsetCoding (отправили разработчикам?).
В реальной жизни MS не слишком-то соблюдает стандарты, но происходит это не потому, как указал Кирилл, что она «чхает на них», а как раз наоборот — потому что на них «чхали другие», а продуктам MS пришлось быть баг-к-багу с ними совместимыми.
Все ругают IE. Мало кто понимает, что это не его вина — он просто копирует Netscape.
Об этом хорошо сказал Джоэль Спольски: http://habrahabr.ru/blogs/webdev/31478/
28 Июл 2010 в 6:00 пп
>>>А упомянутое явление – видимо, баг в IdealCharsetCoding (отправили разработчикам?).
Пока нет. Хочу разобраться почему DefaultCharset не помогает решить проблему с кодировками. Такое ощущение, что свойство просто не работает так как было задумано.
>>>Все ругают IE. Мало кто понимает, что это не его вина – он просто копирует Netscape.
Александр, «просто копирует» ни как не освобождает разработчиков от ответственности за их работу. Разве не так? Мало ли, что было взято за основу — они создают свой продукт на основе Netscape, а не просто копируют. Так можно в итоге докговориться до «я не виноват, что моя программа не работает правильно, просто Windows/Linux не учли, что я так буду делать — виноваты разработчики ОС» :)
28 Июл 2010 в 6:07 пп
>>> ни как не освобождает разработчиков от ответственности за их работу
Да само собой, только в большинстве случаев выбора-то особо и нет. Альтернативы будут хуже.
К примеру, секретный план всех ругающих IE обычно выглядит так:
1. Написать браузер, соответствующий стандартам на 100%.
2. ???
3. PROFIT!!!
Проблема в п2, который звучит так: «никто не будет использовать этот браузер, потому что в нём не работает ни один сайт». До п3 дело просто не дойдёт.
Вы не можете изменить миллионы сайтов. Единственное, что вы можете сделать — написать браузер, в котором они будут работать. А это значит, что ваш браузер не будет соблюдать стандарты. Стандарты в web — это миф.
28 Июл 2010 в 7:05 пп
>>>К примеру, секретный план всех ругающих IE обычно выглядит так:
:) никогда не вынашивал подобные планы. Но IE обычно использую только 1 раз — когда надо скачать другой браузер, например FF. Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки. Не соблюдаешь рекомендации — могут возникнуть проблемы. Так собственно и происходит. Только у кого-то продукты глючат больше, а у кого-то меньше в зависимости от того кто учше соблюдал эти самые рекомендации.
28 Июл 2010 в 7:59 пп
>>> Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки
Да, это то, что всем хочется думать, что это правда, но в реальности это просто не работает.
Ядро проблемы в том, что вы думаете, что есть один стандарт, но так как никто не может реально протестировать на соответствие с ним, то стандарт этот — виртуальный: это платонический идеал и набор недоразумений, а следовательно такой стандарт не служит достижению желаемой цели.
DOCTYPE — это миф.
Обычный смертный, который включил DOCTYPE себе в страницу, приговаривая «это стандартный HTML» — нагло врёт. Нет никакого способа узнать это. И на самом они говорят то, что эта страница по идее должна быть стандартным HTML. А что они действительно знают, так это то, что они протестировали её в IE, Файерфокс, может быть Опере и Сафари, и она вроде бы работала (а может они вообще просто перепечатали DOCTYPE из книжки и понятия не имеют, что он значит).
Именно поэтому:
>>> Не соблюдаешь рекомендации – могут возникнуть проблемы. Так собственно и происходит. Только у кого-то продукты глючат больше, а у кого-то меньше в зависимости от того кто учше соблюдал эти самые рекомендации.
Неверно. Лучше работает не у того, кто лучше соблюдает стандарты, а у того, кто лучше приспособил свои вещи к существующему порядку вещей (да, кривому, не соблюдающего стандарты, но реальному, а не воображаемому или желаемому).
16 Авг 2010 в 2:52 пп
Не очень правильно менять исходники, когда для указания кодировки есть расширенная функция AddPartTextEx.
вместо
AttachMess.AddPartText(lst, MimePart);
используем
AttachMess.AddPartTextEx(lst, MimePart, UTF_8, true, ME_BASE64);
31 Окт 2010 в 5:56 дп
пробовал всё что вы выше написали, поискал немного в интернете и наткнулся на хорошую статью
http://developers.do.am/publ/delphi/biblioteka_synapse/biblioteka_synapse_sozdanie_fajla_pisma_msg/9-1-0-35
31 Окт 2010 в 5:58 дп
а точнее на этот кусок
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
{$ENDIF}
];
Аналогично думаю сработает и для UTF_8.
тему письма отправляет как надо…
31 Окт 2010 в 10:00 пп
>x_tasy пишет:
>16 Aug 2010 в 2:52 pm
>
>Не очень правильно менять исходники, когда для указания кодировки есть расширенная функция >AddPartTextEx.
пробовал, на почту бред приходил…
01 Ноя 2010 в 12:18 дп
Ну, x_tasy, в целом прав — если уж править исходник, то так, чтобы не было мучительно больно за бесцельно прожитые годы :) Точнее за то, что в другой ситуации правка может привести к очередной проблеме в программе. Я обычно, когда не могу получить кодировку через свойства начинаю перебирать все заголовки в поисках «Content-Type…..charset….», не трогая исходник.
Были проблемы с кодировкой и при отправке, но вроде как для своей задачи разобрался, опять таки не трогая исходников
01 Ноя 2010 в 12:48 дп
исходники можно мучать, понимая программирование… но сама программа будет не универсальна для других пользователей в виде исходных кодов… а так как я пишу в личных целях)) то могу спокойно подгонять исходные коды модулей…
01 Ноя 2010 в 1:23 дп
ну так да, можно и поковырять :)