Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2011.08.07;
Скачать: CL | DM;

Вниз

TidPOP3 заголовки не всех писем получает. Как заставить?   Найти похожие ветки 

 
sasha73   (2009-04-14 18:28) [0]

Добрый день, Мастера.

  Второй день бьюсь. Сначало код, потом объясню:


Var
 POP3             : TIdPOP3;
 MsgRecive      : TIdMessage;
 st                 : String;

Begin
 POP3:=TIdPOP3.Create(nil);
 MsgRecive:=TIdMessage.Create(nil);
 POP3.Host:="aa.bb.cc.dd";
 POP3.Username:="user1";
 POP3.Password:="passwd1";
 POP3.Connect(5000);
 POP3.RetrieveHeader(3,MsgRecive);
 St:=MsgRecive.Subject;


  На некоторых сообщения не принимается заголовок. Не могу понять почему. Т.е. St в итоге пустая строка. Хотя на самом деле в письме тема заполнена.
  Заголовок письма несколько нестандартен:


From user@domen.ru  Mon Apr 13 17:45:41 2009
X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on domen.ru
X-Spam-Level: **
X-Spam-Status: No, score=2.9 required=5.0 tests=ALL_TRUSTED,DATE_IN_PAST_03_06,
       TVD_SPACE_RATIO autolearn=no version=3.2.5
>From office  Mon Apr 13 17:45:41 2009
Return-Path: <send@domen.ru>
X-Original-To: rcpt@domen.ru
Delivered-To: rcpt@domen.ru
Received: from domen.ru (localhost [127.0.0.1])
...


  В Delphi 6 на POP3.RetrieveHeader(3,MsgRecive) вообще было исключение "Connection Closed Gracefully". После установки Delphi 7 исключения нет, но заголовок пустой.
  Понятно, что это из-за нестандартности письма. Такие письма получаются в результате персылки. Но все же компонент TNMPOP3 обрабатывает его нормально. И все почтовые клиенты. На TNMPOP3 переходить не хочется, т.к. немало кода уже написано под TIdPOP3. :-(

  Как думаете, есть возможность заставить TIdPOP3 воспринимать все заголовки отдельно?


 
sasha73   (2009-04-14 18:30) [1]

Не отдельно, а правильно, имелось ввиду. :-)
(Извините, голова уже болит и перепрыгиваю с одного задания на другое)


 
Сергей М. ©   (2009-04-14 20:18) [2]


> это из-за нестандартности письма


Что же в нем нестандартного по-твоему ?
И где в процитированном тобой фрагменте заголовка оригинальное значение поля Subject, о проблеме с котором собссно и идет речь, судя по


> St в итоге пустая строка


?


 
sasha73   (2009-04-15 10:13) [3]

Спасибо за ответ.


> Что же в нем нестандартного по-твоему ?


  Многие почтовые клиенты, особенно не самых последних версий "неадекватно" реагируют, на знаки типа ">" и т.п.  в средине заголовка письма. Думал в нем причина, оказывается нет.


> И где в процитированном тобой фрагменте заголовка оригинальное
> значение поля Subject


  Я внизу заголовка поставил троеточие, извините, не догадался, что слов "Хотя на самом деле в письме тема заполнена" и "Но все же компонент TNMPOP3 обрабатывает его нормально. И все почтовые клиенты" будет недостаточно. Привел, только по моему мнению "нестандартную часть".

  Вот весь заголовок:

From send@domen.ru  Mon Apr 13 17:45:41 2009
X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on domen.ru
X-Spam-Level: **
X-Spam-Status: No, score=2.9 required=5.0 tests=ALL_TRUSTED,DATE_IN_PAST_03_06,
       TVD_SPACE_RATIO autolearn=no version=3.2.5
>From office  Mon Apr 13 17:45:41 2009
Return-Path: <send@domen.ru>
X-Original-To: rcpt@domen.ru
Delivered-To: rcpt@domen.ru
Received: from domen.ru (localhost [aa.bb.cc.dd])
       by domen.ru (Postfix) with ESMTP id E81A736A01E
       for <rcpt@domen.ru>; Mon, 13 Apr 2009 17:45:40 +0000 (UTC)
Received: from [aa.bb.cc.dd] (aa.bb.cc.dd.ip.prov.net [aa.bb.cc.dd])
       by domen.ru (Postfix) with ESMTPA id 26CDB36A01A
       for <rcpt@domen.ru>; Mon, 13 Apr 2009 17:45:39 +0000 (UTC)
Message-ID: <49E34FD4.10701@domen.ru>
Date: Mon, 13 Apr 2009 17:44:36 +0300
From: =?UTF-8?B?0JDQu9C10LrRgdCw0L3QtNGA?= <send@domen.ru>
User-Agent: Thunderbird 2.0.0.21 (Windows/20090302)
MIME-Version: 1.0
To: rcpt@domen.ru
Subject: =?UTF-8?B?0J/RgNC+0LLQtdGA0LrQsCDRgNCw0LHQvtGC0Ysg0L/QvtGH0YLQvtCy?=
=?UTF-8?B?0L7Qs9C+INGA0L7QsdC+0YLQsDI=?=
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8bit
X-Virus-Scanned: ClamAV using ClamSMTP


Оказалось  POP3.RetrieveHeader(3,MsgRecive) в моем случае читает только 3 строки. Т.е.:

 For i:=0 to MsgRecive.Headers.Count-1 do
   St:=MsgRecive.Headers.Strings[i];

  Получаем:
1 = "X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on domen.ru"
2 = "X-Spam-Level: **"
3 = "X-Spam-Status: No, score=2.9 required=5.0 tests=ALL_TRUSTED,DATE_IN_PAST_03_06,"
  Т.е. если строка заканчивается на запятую и $0A , а следующая начинается с $09  - компонент считает это концом заголовка. :-(
  Вот вам и стандартность заголовка.
  Придется ковыряться в коде TidPOP3. Кода много, а опыта и времени не хватает. :-)
  Может другой способ посоветуете? Может какие-то еще есть интересные свойства/методы у этого компонента?


 
Сергей М. ©   (2009-04-15 12:53) [4]

У меня установлен Indy10

На форме - Memo, в нем текст заголовка, скопированного один-в-один из [9]

Запускаю тест:

procedure TForm1.Button3Click(Sender: TObject);
var
 msg: TIdMessage;
 ms: TStream;
begin
 ms := TMemoryStream.Create;
 Memo.Lines.SaveToStream(ms);
 ms.Position := 0;
 msg := TIdMessage.Create;
 msg.Headers.LoadFromStream(ms);
 msg.ProcessHeaders;
 ShowMessage(msg.Subject);
 ms.Free;
 msg.Free;
end;


Вижу огрызок темы "Проверка работы почтов".

Привожу заголовок в соответствие с п.2.2.3 RFC-2822.

Повторяю тот же тест, вижу полную строку темы "Проверка работы почтового робота2".

Как видишь, ни до ни после правки заголовка поле темы не было пустым.

Вывод: индейский парсер заголовка работает корректно.


 
sasha73   (2009-04-15 17:14) [5]


> Привожу заголовок в соответствие с п.2.2.3 RFC-2822.


  В данном случае это не очень важно, так как из заголовка читается только 3 верхние строки.


>  msg.Headers.LoadFromStream(ms);


  Данный код и у меня отрабатывает нормально и без проблем. Подозреваю что методы  Headers.LoadFromStream и RetrieveHeader работают по разному. Так как и у меня на этом письме POP3.RetrieveRaw получает все письмо с заголовком и телом, т.е. все верно.
А значит вывод

> Вывод: индейский парсер заголовка работает корректно.

не совсем точен. ;-)

 Спасибо, что уделили время и даже попробовали код. В свою очередь, я не поленился, открыл на рабочем сервер 110-й порт, где можно попробовать:

Procedure TestIndy;
Var
 POP3                : TIdPOP3;
 MsgRecive           : TIdMessage;
Begin
 POP3:=TIdPOP3.Create(nil);
 MsgRecive:=TIdMessage.Create(nil);
 POP3.Host:="91.203.13.3";
 POP3.Username:="indy";
 POP3.Password:="indypass";
 POP3.Connect;
 POP3.RetrieveHeader(1,MsgRecive);
 MessageBox(0,PChar("\"+MsgRecive.Subject+"/"),"Empty:",mb_OK);
 MessageBox(0,PChar("Header string count = "+IntToStr(MsgRecive.Headers.Count)),"Empty:",mb_OK);
 POP3.RetrieveHeader(2,MsgRecive);
 MessageBox(0,PChar("\"+MsgRecive.Subject+"/"),"Empty:",mb_OK);
 MessageBox(0,PChar("Header string count = "+IntToStr(MsgRecive.Headers.Count)),"Empty:",mb_OK);
End;


  Это реально работающий сервер, где каждому можно будет попробовать несколько дней поэкспериментировать. Там лежит именно это письмо первое по счету, и второе - точная его копия, но удалена в конце строки "X-Spam-Status: No, score=2.9 required=5.0 tests=ALL_TRUSTED,DATE_IN_PAST_03_06," запятая. Как видно, с ним компонент работает нормально.

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


 
Сергей М. ©   (2009-04-15 17:27) [6]


> sasha73   (15.04.09 17:14) [5]


> точная его копия, но удалена в конце строки "X-Spam-Status:
>  No, score=2.9 required=5.0 tests=ALL_TRUSTED,DATE_IN_PAST_03_06,
> " запятая


В [4] я не удалял никаких запятых, и при этом поле Тема было непустое...


 
sasha73   (2009-04-15 18:02) [7]


> В [4] я не удалял никаких запятых, и при этом поле Тема
> было непустое...


  Я жек вроде объяснил, что код:

procedure TForm1.Button3Click(Sender: TObject);
var
msg: TIdMessage;
ms: TStream;
begin
ms := TMemoryStream.Create;
Memo.Lines.SaveToStream(ms);
ms.Position := 0;
msg := TIdMessage.Create;
msg.Headers.LoadFromStream(ms);
msg.ProcessHeaders;
ShowMessage(msg.Subject);
ms.Free;
msg.Free;
end;


  и у меня отрабатывает верно и без проблем. И объяснил свои догадки, почему. У вас ...Headers.LoadFromStream.. , а у меня ..RetrieveHeader...

  Вы выпонили новый код из [5]? Думаю у вас тоже будет ошибка. ;-)


 
Сергей М. ©   (2009-04-15 21:38) [8]


> sasha73   (15.04.09 18:02) [7]


Да, я воспроизвел ситуацию, проиллюстрированную в [5].
В ближ.время постараюсь локализовать "засаду".


 
sasha73   (2009-04-16 09:34) [9]

Больше нет идей? :-(


 
Сергей М. ©   (2009-04-16 12:08) [10]


> Больше нет идей?


Уже есть)

Все движется к тому, что твой POP3-сервер - кривой.

В ответ на запрос RETR 1 сервер отдает оригинальный приведенный тобой заголовок + тело. Именно поэтому почтовые клиенты (включая IdPOP3), по дифолту вызывающие именно RETR, получают нормальный заголовок и тело и так же нормально парсят возвращенные данные.

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

Я провел экперимент на ICS TSyncPOOP3Cli и получил те же результаты, которые показал IdPOP3.


 
Сергей М. ©   (2009-04-16 12:22) [11]

А вот и обещаная "засада":

http://www.temnota.kmv.ru/vm-pop3d/CHANGES

31/Jan/2002 1.1.7
Bug Fix: Changed pop3_top (top.c) so it wouldn"t think headers
were finished, when a header is 80 characters long. (Reported by
Tomi Hakala.)

А у тебя допотопная версия 1.1.6)

Так что прежде чем искать жуков в индейских кущах (хотя их там и действительно немало), сначала ищи эту живность у себя на сервере, регулярно следи за чейнджлогами версий демона и оперативно обновляй)


 
sasha73   (2009-04-16 14:04) [12]

СПАСИБО !

   Вы абсолютно правы. Проблема в POP3-сервере, а не в компоненте.
   Снимаю шляпу и благодарю за потраченное вермя и поиск истины.


> А у тебя допотопная версия 1.1.6)


  А это не совем верно. Я регулярно обновляю порты (это во FreeBSD) и версия этого POP3-сервера заявлена, как финальный релиз. Да и на сайте производителя тоже именно она предложена в разделе "DownLoad".
  А 1.1.7 - это текущая разрабатываемая:

virtualmail-pop3d (aka vm-pop3d)
Current development: 1.1.7f (01/Jul/2003)

  Хотя соглашусь с Вами - сервер не супер и старенький. Достался мне "по наследству" и удобен, тем что прост, мал и быстр.
  Об этой ошибке не задумался и не догадывался, т.к. с него берут почту около 200-х пользователей уже > 2-х лет и о проблемах небыло слышно. Вот сегодня обновил на development. :-)

  Еще раз спасибо, теперь буду внимательнее изучать проблему со всех сторон.


 
Сергей М. ©   (2009-04-16 14:18) [13]


> sasha73   (16.04.09 14:04) [12]


Ну тогда еще один момент остался - нарушение RFC2822 в части строк


X-Spam-Status: No, score=2.9 required=5.0 tests=ALL_TRUSTED,DATE_IN_PAST_03_06,
      TVD_SPACE_RATIO autolearn=no version=3.2.5
>From office  Mon Apr 13 17:45:41 2009
<-- этой


Subject: =?UTF-8?B?0J/RgNC+0LLQtdGA0LrQsCDRgNCw0LHQvtGC0Ysg0L/QvtGH0YLQvtCy?=
=?UTF-8?B?0L7Qs9C+INGA0L7QsdC+0YLQsDI=?=
<-- и этой

Кто нарушает соглашения - твой POP3-сервер ?
Или здесь он ни причем (что получил, то и отдал) ?


 
Сергей М. ©   (2009-04-16 20:59) [14]


> версия .. заявлена.. как финальный релиз


"О сколько нам открытий чудных .." (С) ВНП

Я вот тоже свято верил, что версия MT ROS 3.20 - финальная, як була заявлена разработчиками) .. до нек.момента .. пока не получил граблищами по лбу)

Шишку прочесал, успокоился, залез в чейджлог - а там нонче м 3.22 в финале уже числится))

О как)


 
sasha73   (2009-04-17 13:38) [15]


> Кто нарушает соглашения - твой POP3-сервер ?Или здесь он
> ни причем (что получил, то и отдал) ?


  К счастью, хоть тут он не при чем. :-) Это по пути в ящик почтовые клиенты и MTA "балуются". :-) Меня это не смущало, т.к. когда-то неск. лет назад писал почтового робота и разбирал заголовки писем в большом количестве. Очень часто встречались отклонения от стандартов и пришлось их учитывать. Особенно спамеры тогда что-попало слали. Это сейчас их сложно отличить. :-)

  Текущая версия этого POP3-севера оказалась нестабильной. Хотя еще не разобирался точно, от чего он падал. Да и это неважно - будет морочить голову, мы его наконец-то заменим. Он и так явно не лидер в этом направлении. :-)

  О слежении за версиями, согласен, бывает всякое - нужно стараться следить и внимательно изучать.

  Еще раз спасибо, а то я уже собирался перейти на другой компонент или вручную тело разбирать. Хотя, IdPOP3 все такие кое-чем не понравился. В отличии от той версии, что была еще в D6, в D7 MsgRecive.Subject возвращает уже декодированную стоку (переведенную к кодировку Win-1251), а это не всегда хорошо. Т.к. он не знает даже кодировки koi8-r и других некоторых, поэтому пришлось брать тему как MsgRecive.Headers.Values["Subject"] и самому декодировать. В остальном хорошая вещица.

  Интересно, можно ли заставить этот компонент не умничать и не декодировать заголовок, или отдельно тему?


 
app ©   (2009-04-17 14:04) [16]

> sasha73  (17.04.2009 13:38:15)  [15]

Это отдельная тема


 
Сергей М. ©   (2009-04-17 16:35) [17]


> можно ли заставить этот компонент не умничать и не декодировать
> заголовок, или отдельно тему?


А чем эта фича тебе помешала ?
Или тебе raw-данные заголовков нужны ?


 
sasha73   (2009-04-17 16:44) [18]


> А чем эта фича тебе помешала ?

Ну я же говорю, она не все кодировки знает, и соотв. выдает неверный результат.
Т.е. когда Subject="=?koi8-r?B?4vTrIOvJxdc=?=" она выдает "&#226;&#244;&#235; &#235;&#201;&#197;&#215;", т.е. уже и кодировка становится неизвестна (когда она в других полях заголовка уже не указана) и результат неверный.

  Как ее заставить не декодировать тему, From  и т.д. ?  Пока только так получилось:

MsgRecive.Headers.Values["Subject"]


 
Сергей М. ©   (2009-04-17 17:33) [19]


> Пока только так получилось


Это ты взял RAW-данные


> Как ее заставить не декодировать тему, From  и т.д. ?


Не надо ее "заставлять", надо помочь !)

Читай справку к классу TIdHeaderCoderPlain.

Пример "помощи":


unit MsgHdrCoders;

interface

uses
 IdHeaderCoderPlain;

type
 TCodeMatrix = array[1..255] of char;

const
 FirstCodes =
   #1#2#3#4#5#6#7#8#9#10#11#12#13#14#15#16#17#18#19#20#21#22#23#24#25#26#27#28+
  #29#30#31" !"#$%&""()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^" +
   "_`abcdefghijklmnopqrstuvwxyz{|}~";
 cmAnsiToKoi8R: TCodeMatrix = FirstCodes
 + "ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—?™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·Ј—є»јЅѕїбвчздецъй"
   + "клмнопртуфхжигюыэящшьасБВЧЗДЕЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС";
 cmAnsiToKoi8U: TCodeMatrix = FirstCodes
 + "ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—?™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·Ј—є»јЅѕїбвчздецъй"
   + "клмнопртуфхжигюыэящшьасБВЧЗДЕЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС";
 cmKoi8RToAnsi: TCodeMatrix = FirstCodes
 + "-¦-¬L-++T++---¦¦---?¦•v??? ?°?·?=¦-ёг㬬¬LLL---¦¦¦¦Ё¦¦TTT¦¦¦+++©юабцдефгх"
   + "ийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ";
 cmKoi8UToAnsi: TCodeMatrix = FirstCodes
 + "-¦-¬L-++T++---¦¦---?¦•v??? ?°?·?=¦-ёєгії¬LLL-ґў¦¦¦¦ЁЄ¦ІЇT¦¦¦+ҐЎ©юабцдефгх"
   + "ийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ";
 cmOemDosToAnsi: TCodeMatrix = FirstCodes
 + "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп---¦+¦¦¬¬¦¦¬---¬L+T+-+¦¦L"
   + "г¦T¦=+¦¦TTLL-г++----¦¦-рстуфхцчшщъыьэюяЁёЄєЇїЎў°•·v№¤¦ ";
 cmIsoToAnsi: TCodeMatrix = FirstCodes
 + "???????????????????????????????? ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШ"
   + "ЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ";
type

 TIdHeaderCoderKOI8 = class(TIdHeaderCoderPlain)
 public
   class function Decode(const ACharSet, AData: String): String; override;
   class function Encode(const ACharSet, AData: String): String; override;
   class function CanHandle(const ACharSet: String): Boolean; override;
 end;

function ConvertCharset(AString: String; AMatrix: TCodeMatrix): String;

implementation

uses IdGlobal, IdHeaderCoderBase;

function ConvertCharset(AString: String; AMatrix: TCodeMatrix): String;
var
 i: Integer;
begin
 Result := "";
 for i:= 1 to Length(AString) do
   Result := Result + AMatrix[Ord(AString[i])];
end;

{ TIdHeaderCoderKOI8 }

class function TIdHeaderCoderKOI8.CanHandle(const ACharSet: String): Boolean;
begin
 Result := TextIsSame(ACharSet, "KOI8-R") or TextIsSame(ACharSet, "KOI8-U");
end;

class function TIdHeaderCoderKOI8.Decode(const ACharSet, AData: String): String;
begin
 if TextIsSame(ACharSet, "KOI8-R") then
   Result := ConvertCharset(AData, cmKoi8RToAnsi)
 else if TextIsSame(ACharSet, "KOI8-U") then
   Result := ConvertCharset(AData, cmKoi8UToAnsi);
end;

class function TIdHeaderCoderKOI8.Encode(const ACharSet, AData: String): String;
begin
 if TextIsSame(ACharSet, "KOI8-R") then
   Result := ConvertCharset(AData, cmAnsiToKoi8R)
 else if TextIsSame(ACharSet, "KOI8-U") then
   Result := ConvertCharset(AData, cmAnsiToKoi8U);
end;

initialization
 RegisterHeaderCoder(TIdHeaderCoderKOI8);
finalization
 UnregisterHeaderCoder(TIdHeaderCoderKOI8);

end.


 
имя   (2009-04-18 21:00) [20]

Удалено модератором


 
sasha73   (2009-04-21 13:54) [21]


> Это ты взял RAW-данные


  Да, я понимаю.


> Читай справку к классу TIdHeaderCoderPlain.
  Пример "помощи":


  Спасибо, отлично. То, что нужно.



Страницы: 1 вся ветка

Текущий архив: 2011.08.07;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.008 c
2-1303980851
stud92
2011-04-28 12:54
2011.08.07
отношение между таблицами бд


2-1302509942
Максон
2011-04-11 12:19
2011.08.07
StringGrid и таблица Word


15-1303109431
Дмитрий Тимохов
2011-04-18 10:50
2011.08.07
Нежелательная обработка сообщений


1-1261562629
DL
2009-12-23 13:03
2011.08.07
парсин строки имени файла


15-1303154153
т116
2011-04-18 23:15
2011.08.07
ищу учителя