Подписка

добавить на Яндекс

Наши проекты

Delphi+Google

Google API

Google API в Delphi - проект с открытым исходным кодом.

Chrono

Chrono

Хронометр - программа для ведения списка задач.

ODFProc

ODFProc

ODFProc - работа с документами OpenOffice в Lazarus и FreePascal.

Поддержка блога

А тут я коплю на лицензию Delphi XE на iPad =).
Сумма пожертвования не фиксирована.

Публикации

Год назад

Случайный пост

Последние

Сообщения форума

Комментарии

Социальные сети

Google

Facebook

Twitter

Опрос

Вы сейчас или в ближайшем обозримом будущем планируете разрабатывать кроссплатформенное приложение с использованием Firemonkey?



Loading ... Loading ...

Блоги и сообщества

Статьи по Delphi DelphiFeeds.ru - Все Delphi-блоги Рунета Сообщество умных людей VR-Online.RU Бесплатный журнал для программистов и всех, кто интересуется IT Статьи и уроки по Delphi Новостной блог о высоких технологиях
Система Orphus
Опубликовал Vlad 27 июля 2010 в 04:31.
Категории: Delphi в Web.


Итак, пока наш раздел "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-кодом также нормально принимается и обрабатывается почтовыми клиентами.

В заключении можно сказать следующее:

  1. OutLook - зло, но вполне сносное. При должной настройке бедет работать вполне нормально. В статье я использовал Outlook 2007.
  2. Разработчики Synapse немного перестарались с поиском идеальных кодировок, а точнее немного недостарались - в методе IdealCharsetCoding, думаю, следовало бы останавливаться не на первой попавшейся подходящей кодировке, а все-таки отдавать предпочтение при прочих равных результатах дефолтной - той, которая используется в ОС...хотя я RFC не читал и могу чего-то и не знать.

В ближайшее время сделаю апдейт в репозитории - выложу немного подправленный вариант компонента, "special for ms outlook" так сказать. Найдете ошибки - пишите о них подробно в разделе Issues - буду исправлять, а пока буду усиленно читать о том, что такое раскрутка блога и как её правильно проводить и, самое главное - для чего :).

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

Понравилась статья? Тогда:
Делись! Загружай! Плюсуй!
   Отправить PDF на   
Читай ещё статьи на WebDelphi.ru

Комментарии (16)

WP_Cloudy
  • Александр пишет:

    >>> но быть того не может, чтобы разработчики были уж настолько плохи

    http://www.transl-gunsmoker.ru/2009/12/blog-post_24.html

  • Vlad пишет:

    Александр, эта ссылка значит, что разработчики Synapse не читали RFC и «от балды» указали дефолтную кодировку? Или наоборот, разработчики OutLook действуют не по стандарту? Ссылка, конечно хорошо, но как бы аргуменировать чтоль надо её положение в посте :)

  • Kirill Krasnov пишет:

    Влад, даже разработчики, которые стараются соблюдать все стандарты (Thunderbird) до сих пор некорректно обрабатывают заголовок темы в юникоде, если она разбивается на несколько строк.
    А то, что Микрософт чхала на стандарты — это уже давно известный факт. Идеальный пример — IE.

  • Егор пишет:

    Кирилл, полностью с Вами согласен!

  • Александр пишет:

    >>> Александр, эта ссылка значит, что разработчики Synapse не читали RFC и “от балды” указали дефолтную кодировку?

    Не, имелось ввиду, что говоря «ну не может же такого быть», вы рассматривали Outlook в сферическом вакууме. Я не думаю, что указание неверной кодировки в Synapse имеет какое-то отношение к RFC — там же ничего не говорится про реализацию, а только про стандарты протоколов. А упомянутое явление — видимо, баг в IdealCharsetCoding (отправили разработчикам?).

    В реальной жизни MS не слишком-то соблюдает стандарты, но происходит это не потому, как указал Кирилл, что она «чхает на них», а как раз наоборот — потому что на них «чхали другие», а продуктам MS пришлось быть баг-к-багу с ними совместимыми.

    Все ругают IE. Мало кто понимает, что это не его вина — он просто копирует Netscape.

    Об этом хорошо сказал Джоэль Спольски: http://habrahabr.ru/blogs/webdev/31478/

  • Vlad пишет:

    >>>А упомянутое явление – видимо, баг в IdealCharsetCoding (отправили разработчикам?).
    Пока нет. Хочу разобраться почему DefaultCharset не помогает решить проблему с кодировками. Такое ощущение, что свойство просто не работает так как было задумано.
    >>>Все ругают IE. Мало кто понимает, что это не его вина – он просто копирует Netscape.
    Александр, «просто копирует» ни как не освобождает разработчиков от ответственности за их работу. Разве не так? Мало ли, что было взято за основу — они создают свой продукт на основе Netscape, а не просто копируют. Так можно в итоге докговориться до «я не виноват, что моя программа не работает правильно, просто Windows/Linux не учли, что я так буду делать — виноваты разработчики ОС» :)

  • Александр пишет:

    >>> ни как не освобождает разработчиков от ответственности за их работу

    Да само собой, только в большинстве случаев выбора-то особо и нет. Альтернативы будут хуже.

    К примеру, секретный план всех ругающих IE обычно выглядит так:

    1. Написать браузер, соответствующий стандартам на 100%.
    2. ???
    3. PROFIT!!!

    Проблема в п2, который звучит так: «никто не будет использовать этот браузер, потому что в нём не работает ни один сайт». До п3 дело просто не дойдёт.

    Вы не можете изменить миллионы сайтов. Единственное, что вы можете сделать — написать браузер, в котором они будут работать. А это значит, что ваш браузер не будет соблюдать стандарты. Стандарты в web — это миф.

  • Vlad пишет:

    >>>К примеру, секретный план всех ругающих IE обычно выглядит так:
    :) никогда не вынашивал подобные планы. Но IE обычно использую только 1 раз — когда надо скачать другой браузер, например FF. Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки. Не соблюдаешь рекомендации — могут возникнуть проблемы. Так собственно и происходит. Только у кого-то продукты глючат больше, а у кого-то меньше в зависимости от того кто учше соблюдал эти самые рекомендации.

  • Александр пишет:

    >>> Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки

    Да, это то, что всем хочется думать, что это правда, но в реальности это просто не работает.

    Ядро проблемы в том, что вы думаете, что есть один стандарт, но так как никто не может реально протестировать на соответствие с ним, то стандарт этот — виртуальный: это платонический идеал и набор недоразумений, а следовательно такой стандарт не служит достижению желаемой цели.

    DOCTYPE — это миф.

    Обычный смертный, который включил DOCTYPE себе в страницу, приговаривая «это стандартный HTML» — нагло врёт. Нет никакого способа узнать это. И на самом они говорят то, что эта страница по идее должна быть стандартным HTML. А что они действительно знают, так это то, что они протестировали её в IE, Файерфокс, может быть Опере и Сафари, и она вроде бы работала (а может они вообще просто перепечатали DOCTYPE из книжки и понятия не имеют, что он значит).

    Именно поэтому:

    >>> Не соблюдаешь рекомендации – могут возникнуть проблемы. Так собственно и происходит. Только у кого-то продукты глючат больше, а у кого-то меньше в зависимости от того кто учше соблюдал эти самые рекомендации.

    Неверно. Лучше работает не у того, кто лучше соблюдает стандарты, а у того, кто лучше приспособил свои вещи к существующему порядку вещей (да, кривому, не соблюдающего стандарты, но реальному, а не воображаемому или желаемому).

  • x_tasy пишет:

    Не очень правильно менять исходники, когда для указания кодировки есть расширенная функция AddPartTextEx.

    вместо

    AttachMess.AddPartText(lst, MimePart);

    используем

    AttachMess.AddPartTextEx(lst, MimePart, UTF_8, true, ME_BASE64);

  • _scorpio_ пишет:

    пробовал всё что вы выше написали, поискал немного в интернете и наткнулся на хорошую статью
    http://developers.do.am/publ/delphi/biblioteka_synapse/biblioteka_synapse_sozdanie_fajla_pisma_msg/9-1-0-35

  • _scorpio_ пишет:

    а точнее на этот кусок


    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.

    тему письма отправляет как надо…

  • _scorpio_ пишет:

    >x_tasy пишет:
    >16 Aug 2010 в 2:52 pm 
    >
    >Не очень правильно менять исходники, когда для указания кодировки есть расширенная функция >AddPartTextEx.
    пробовал, на почту бред приходил…

  • Vlad пишет:

    Ну, x_tasy, в целом прав — если уж править исходник, то так, чтобы не было мучительно больно за бесцельно прожитые годы :) Точнее за то, что в другой ситуации правка может привести к очередной проблеме в программе. Я обычно, когда не могу получить кодировку через свойства начинаю перебирать все заголовки в поисках «Content-Type…..charset….», не трогая исходник.
    Были проблемы с кодировкой и при отправке, но вроде как для своей задачи разобрался, опять таки не трогая исходников

  • _scorpio_ пишет:

    исходники можно мучать, понимая программирование… но сама программа будет не универсальна для других пользователей в виде исходных кодов… а так как я пишу в личных целях)) то могу спокойно подгонять исходные коды модулей…

  • Vlad пишет:

    ну так да, можно и поковырять :)

Ваш ответ

Внимание: Все комментарии модерируются, и это может вызвать задержку их публикации. Отправлять комментарий заново не требуется.

Пожалуйста, заключайте исходный код в тэги [code][/code].
Если код большой, то воспользуйтесь Вставкой кода на отдельной странице и оставьте в комментарии ссылку на исходник