уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.

Итак, пока наш раздел «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 7 и Delphi 2005 с использованием СУБД MS SQL Server 2000, InterBase и Firebird. Приведена информация о теории построения реляционных баз данных и языке SQL. Освещены вопросы эксплуатации и администрирования СУБД.
купить книгу delphi на ЛитРес
Описание: Рассмотрены малоосвещенные вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные режимы их работы, особенности для протоколов TCP и UDP и др.
купить книгу delphi на ЛитРес
0 0 голоса
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
16 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии
Александр
27/07/2010 12:58

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

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

Kirill Krasnov
27/07/2010 16:48

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

Егор
28/07/2010 04:40

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

Александр
28/07/2010 15:06

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

Александр
28/07/2010 18:07

>>> ни как не освобождает разработчиков от ответственности за их работу Да само собой, только в большинстве случаев выбора-то особо и нет. Альтернативы будут хуже. К примеру, секретный план всех ругающих IE обычно выглядит так: 1. Написать браузер, соответствующий стандартам на 100%. 2. ??? 3. PROFIT!!! Проблема в п2, который звучит так: «никто не будет использовать этот браузер, потому что в нём не работает ни один сайт». До п3 дело просто не дойдёт. Вы не можете изменить миллионы сайтов. Единственное, что вы можете сделать — написать браузер, в котором они будут работать. А это значит, что ваш браузер не будет… Подробнее »

Александр
28/07/2010 19:59

>>> Стандарты Web я бы больше отнёс к рекомендациям того, что необходимо сделать, что бы что-то работало с минимальной вероятностью ошибки Да, это то, что всем хочется думать, что это правда, но в реальности это просто не работает. Ядро проблемы в том, что вы думаете, что есть один стандарт, но так как никто не может реально протестировать на соответствие с ним, то стандарт этот — виртуальный: это платонический идеал и набор недоразумений, а следовательно такой стандарт не служит достижению желаемой цели. DOCTYPE — это миф. Обычный смертный, который включил DOCTYPE себе в страницу, приговаривая «это стандартный HTML» — нагло врёт.… Подробнее »

x_tasy
x_tasy
16/08/2010 14:52

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

вместо

AttachMess.AddPartText(lst, MimePart);

используем

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

_scorpio_
_scorpio_
31/10/2010 05:56

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

_scorpio_
_scorpio_
31/10/2010 05:58

а точнее на этот кусок [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… Подробнее »

_scorpio_
_scorpio_
31/10/2010 22:00

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

_scorpio_
_scorpio_
01/11/2010 00:48

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