Migracja Indy > Synapse

0

Mam pytanie. Walczę od jakiegoś czasu z pewnym bugiem w najnowszym Indy i na horyzoncie nie widać rozwiązania. Bug jest na tyle upierdliwy, że wywala 'application-exception' którego nie sposób przechwycić try exceptem. Na forum indy winę zwalają na zaśmiecone środowisko, podczas gdy problem występuje na goluśkim świeżo postawionym OS, Delphi, Indy.

Jako że zaczyna mnie to już denerwować, szukam wyjścia. A że wielu ludzi zachwala synapse, pomyślałem, że póki co mógłbym przenieść tylko tą niedziałającą wysyłkę maili na synapse'a.

Moje oczekiwania (czyli to co moja aplikacja oferuje teraz i co musi oferować po zmianach):

  • maile z HTML'em, częscią tekstową, obrazkami, załącznikami
  • kodowanie tekstu (UTF-8 lub ISO) chce móc to ustawić
  • obsługa TLS/SSL
  • thread safe - część kodu działa jak usługa na serwerze, gdzie w osobnym wątku wysyłane są maile
  • postęp wysyłki, szczególnie maili z załącznikami
  • free for commercial use
  1. Czy synapse to ma ?
  2. Gdzie szukać przykładów wypaśnego klienta SMTP z ficzerami wymienionymi wyżej ?
  3. Jak z rozwojem tego pakietu ? Ostatni stable jest z przed ponad roku - to się jeszcze rozwija ?
  4. Jak z supportem ? Ktoś miał okazję kontaktu z autorem ?

Z góry dziękuję za odpowiedzi.
b

0

Podłącze się pod post :) chętnie poznam odpowiedzi na to :D to co pamiętam bo dawno tu nie zaglądałem Misiekd obyty w synapse chyba był :>

0

Co do wysyłki to chyba trzeba używać unit smtpsend. Z tego co widzę progressu wysyłki brak. Ale stosunkowo prosto było by dodać. Tak na pierwszy rzut oka, kod w porównaniu do Indy wydaje się być po stokroś czytelniejszy. Tylko czy to będzie działać ?

b

0

Ja mam jako tako opanowane korzystanie w Synapse z HTTP i FTP.
Co do e-maili to się trochę męczyłem. Ale jakoś w dwoch prostych,
dla przykładu stworzonych programach dałem radę. Kiedyś Misiekd
wklejał tutaj klasę do obslugi e-maili - o ile dobrze pamiętam. A co
do postępu to obslużysz go w zdarzeniu SMTPSend.Sock.OnStatus.
Więcej informacji powinieneś znaleźć w dokumentacji i przykładach
dołaczonych do pakietu. Co do kontaktu z autorem - to nie miałem
tej przyjemności. Fakt, że pakiet jest ostatnio nie rozwijany. I jest
jeden minus, pakiet nie działa prawidłowo bodajże od Delphi 2009.

0
olesio napisał(a)

Ja mam jako tako opanowane korzystanie w Synapse z HTTP i FTP.
Co do e-maili to się trochę męczyłem. Ale jakoś w dwoch prostych,
dla przykładu stworzonych programach dałem radę. Kiedyś Misiekd
wklejał tutaj klasę do obslugi e-maili - o ile dobrze pamiętam. A co
do postępu to obslużysz go w zdarzeniu SMTPSend.Sock.OnStatus.
Więcej informacji powinieneś znaleźć w dokumentacji i przykładach
dołaczonych do pakietu. Co do kontaktu z autorem - to nie miałem
tej przyjemności. Fakt, że pakiet jest ostatnio nie rozwijany. I jest
jeden minus, pakiet nie działa prawidłowo bodajże od Delphi 2009.

Na to OnStatus nie wpadłem, a nie wiesz czy to tylko status czy możliwość zrobienia progressbara ?

Co do maili to mam pytanie, jak wysłać mail'a tak żeby w temacie miał UTF'a ?

procedure TForm1.Button1Click(Sender: TObject);
var
m:TMimemess;
l:tstringlist;
p: TMimepart;
begin
m:=TMimemess.create;
l:=tstringlist.create;
try
p := m.AddPartMultipart('mixed', nil);
l.text := 'Żółw szedĹ‚ ociężale jak wÄ…ĹĽ ыфвалодŃĐ»Ń„Đ˛ĐľĐ”Đ›ĐžĐŁĐžĐ Đ›Đ¤Đ’Đ Đ´Đ»Ń„Ń‹ĐľĐ˛Đ°Ń ŃŃ';
m.AddPartTextEx(l, p,
UTF_8, // PartCharset: TMimeChar;
True, // Raw: Boolean;
ME_QUOTED_PRINTABLE);//PartEncoding: TMimeEncoding);
// m.header.CharsetCode := UtF_8;
m.header.from:= 'xxx';
m.header.tolist.add('xxx');
m.header.subject:='Żółw szedĹ‚ ociężale jak wÄ…ĹĽ ыфвалодŃĐ»Ń„Đ˛ĐľĐ”Đ›ĐžĐŁĐžĐ Đ›Đ¤Đ’Đ Đ´Đ»Ń„Ń‹ĐľĐ˛Đ°Ń ŃŃ';
m.EncodeMessage;
SendToRaw('xxx', 'xxx', 'xxx', m.lines, 'xxx', 'xxx');
finally
m.free;
l.free;
end;
end;

No i nie chce temat się wyświetlać jak trzeba, koduje mi go jako ISO-8859-2. W dokumentacji pisze że:

property CharsetCode: TMimeChar read FCharsetCode Write FCharsetCode;
Specify base charset. By default is used system charset.

No ale jak go ustawiam na UTF_8 to nie działa. Część tekstowa wyświetla się super. Ale tam jest parametr Raw który mówi żeby mi nie robił żadnej konwersji, a co z headerem ?

b

0

Ciekawe czy to tak ma być czy nie, pomogło dopisanie do

{:Default set of charsets for @Link(IdealCharsetCoding) function.}
IdealCharsets: TMimeSetChar =

Charsetu UTF_8, albo to bug, ale można to zrobić inaczej. Oczwiście nie chciał bym tego robić przez CustomHeaders - powinno to działać samo.

No nic grzebię dalej.

b

0

Co do postępu to w przypadku SynDL : THttpSend, robiłem tak i działalo ok,
ale nie wiem jak to się zachowa w przypadku e-maili. Nie wiem jak ustawić w
ich przypadku Maxa, bo postęp na pewno przez Value. Co do zakodowania w
odpowiedni sposób nagłowka, to może Misiekd albo ktoś inny tutaj Tobie coś
więcej doradzi, bo ja wiem, że EncodeMessage powinno pomóc, w jednym z
prostych programów ktory mial odpisywać automatycznie jeżeli wśród emaili
po pobraniu były jakieś o określonym temacie użyłem DecodeMessage i mi z
tekstem wprowadzonym w polu edycyjnym zadziałal kiedy porównywalem z
sobą dwa tematy, ten z wiadomości odkodowany i ten z pola edycyjnego. A
może coś Tobie podpowiedzą te dwa źródła. Wrzucilem na swoje konto - w
MediaFire, to linki raczej nie wygasną. Archiwa ważą trochę bo ja zawsze,
wszystkie potrzebne pliki do skompilowania staram się trzymać w katalogu
z plikiem projektu, a dodalem też biblioteki dla kont z SSL (choćby gmail):
http://www.mediafire.com/file/za6lz57g39ar7zv/autor_response_email.rar
oraz http://www.mediafire.com/file/i4gupz1pz8o94o7/wysylanie_emaili.rar

procedure TProgressForm.SockCallBack(Sender : TObject; Reason : THookSocketReason; const Value : string);
begin
  begin
    if SynDL.DownloadSize > 0 then
    begin
      DownloadedPB.Max := SynDL.DownloadSize;
      if (Reason = HR_ReadCount) then
      begin
        DownloadedPB.Position := DownloadedPB.Position + StrToInt(Value);
        DownloadedGB.Caption := Format('%s %d z: %d', [DownloadedText, DownloadedPB.Position, SynDL.DownloadSize]);
      end;
      if SynDL.Document.Size = SynDL.DownloadSize then
      begin
        DownloadedPB.Position := SynDL.Document.Size;
        DownloadedGB.Caption := Format('%s %d z: %d', [DownloadedText, DownloadedPB.Position, SynDL.DownloadSize]);
      end;
    end;
  end;
end;
0
olesio napisał(a)

Co do postępu to w przypadku SynDL : THttpSend, robiłem tak i działalo ok,
ale nie wiem jak to się zachowa w przypadku e-maili.

Z tym się będę bawił na końcu, najpierw czy da się wysłać wszystko : )

olesio napisał(a)

Co do zakodowania w
odpowiedni sposób nagłowka, to może Misiekd albo ktoś inny tutaj Tobie coś
więcej doradzi, bo ja wiem, że EncodeMessage powinno pomóc, w jednym z
prostych programów ktory mial odpisywać automatycznie jeżeli wśród emaili
po pobraniu były jakieś o określonym temacie użyłem DecodeMessage i mi z
tekstem wprowadzonym w polu edycyjnym zadziałal kiedy porównywalem z
sobą dwa tematy, ten z wiadomości odkodowany i ten z pola edycyjnego.

Dzięki, ale już sobie poradziłem.

olesio napisał(a)

A może coś Tobie podpowiedzą te dwa źródła. Wrzucilem na swoje konto - w
MediaFire, to linki raczej nie wygasną. Archiwa ważą trochę bo ja zawsze,
wszystkie potrzebne pliki do skompilowania staram się trzymać w katalogu
z plikiem projektu, a dodalem też biblioteki dla kont z SSL (choćby gmail):
http://www.mediafire.com/file/za6lz57g39ar7zv/autor_response_email.rar
oraz http://www.mediafire.com/file/i4gupz1pz8o94o7/wysylanie_emaili.rar

Uhm, łudziłem się że może będziesz miał tam HTML'a : ) Teraz z tym walczę.
Trochę ten synapse mi się wydaje niedokończony / niedorobiony. Jest fajna metoda AddPartTextEx, ale już AddParthHTMLEx nie ma, i trzeba drugi raz wywoływać EncodePart po wyłączeniu konwersji charsetu.

Tak czy siak da się, czyli w zasadzie:

  • maile z HTML'em, częscią tekstową, obrazkami, załącznikami
  • kodowanie tekstu (UTF-8 lub ISO) chce móc to ustawić

spełnione. Zerkając na SendToRaw:

// if you need support for upgrade session to TSL/SSL, uncomment next lines:
// SMTP.AutoTLS := True;
// if you need support for TSL/SSL tunnel, uncomment next lines:
// SMTP.FullSSL := True;

Można by zakładać że obsługa TLS/SSL też jest. Chociaż opcja jej włączania przed odkomentowanie linii jest ... uhm. Może autor stawiał przede wszystkim na prostotę kodu - niewątpliwie mu się udało.

Jeśli chodzi o thread-safe - z tego co widziałem używasz tego w wątkach - nie masz z tym problemów ? Z tego co widzę w kilku unitach są zmienne globalne, ale pare razy widziałem też sekcje krytyczne, więc może jest thread safe.

Została licencja ...

http://ararat.cz/synapse/doku.php/license

Czyli - na tyle na ile znam angielski - trzeba zamieścić info w aplikacji ?

No i progressbar. Coś w blcksock niby jest, jakieś OnStatus, OnMonitor, OnHeartBeat ... na pierwszy rzut oka bardziej kuszące było by jednak dołożenie callback'a do function TSMTPSend.MailData(const Value: TStrings): Boolean;, tam jest pętla po wszystkich liniach zencodowanej wiadomości. Więc zarówno callback do postępu, jak i możliwość przerwania wysyłki prosto dało by się zrobić.

Ale to już nie na tą godzinę (bez pepsi).

b

0

SSL i TLS śmiga aż miło. Tylko też tak ciężko się przyzwyczaić, że jak się poda złe hasło, to nie ma żadnego wyjątku.

0

Ja się na wątkach znam słabo, ale wydaję mi się, że Synapse - jest
Thread Safe, bo na pewno korzystałem w wielu swoich programach
z THttpSend w wątkach i nie zauważyłem żadnych problemów. Zaś
co do htmla, to musisz pokombinować, ja wysyłalem jak widzisz w
kodach źródłowych tylko plain text. Co do tego pokazania postępu
to może Misiekd jak będzie coś więcej Tobie doradzi w tej kwestii.
A i jeszcze słowo o TLS. Obie biblioteki do jego obslugi, pochodzą
ze strony projektu Synapse. Kiedy początkowo pobrałem je - o ile
pamiętam, z innej strony polecanej jako źródło do pluginu Secure
FTP dla Total Commandera - stworzonego przez autora programu,
to SSL nie chcialo działać. Dopiero po pobraniu ich w tejże wersji,
dopstępnej na www projektu wszystko zaczeło hulać. Wniosekuje
stąd, że być może są one w starszej wersji i się po prostu różnią.

0

jeszcze raz moja klasa :)

unit cSendThread;

interface

uses
  uTypes,
  blcksock,
  smtpsend,
  mimemess,
  mimepart,
  cEmail,
  Classes;

type
  TSendEmail = class(TThread)
  private
    FEmail: TEmail;
    FPos: Integer;
    FCount: Integer;
    FTime: TDateTime;
    FStatus: string;
    FError: string;
    FSendData: Boolean;
    FOnChangeStatus: TChangeStatusProc;
    FOnProgress: TProgressProc;
    FOnSendingData: TSendingDataProc;
    FOnDone: TThreadDoneProc;
  protected
    procedure Execute; override;
    function Send: Boolean;
    procedure DoSendingData;
    procedure DoProgress;
    procedure DoChangeStatus;
    procedure OnStatus(Sender: TObject; Reason: THookSocketReason; const Value: string);
    procedure OnMonitor(Sender: TObject; Writing: Boolean; const Buffer: TMemory; Len: Integer);
    procedure DoDone;
  public
    constructor Create(Email: TEmail);
    property OnSendingData: TSendingDataProc read FOnSendingData write FOnSendingData;
    property OnProgress: TProgressProc read FOnProgress write FOnProgress;
    property OnChangeStatus: TChangeStatusProc read FOnChangeStatus write FOnChangeStatus;
    property OnDone: TThreadDoneProc read FOnDone write FOnDone;
  end;

implementation

uses
  ssl_cryptlib,
  synautil,
  SysUtils,
  uConsts;

{ TSendEmail }

constructor TSendEmail.Create(Email: TEmail);
begin
  FreeOnTerminate := True;
  FEmail := Email;
  FSendData := False;
  inherited Create(True);
end;

procedure TSendEmail.DoChangeStatus;
begin
  if Assigned(FOnChangeStatus) then
    FOnChangeStatus(nil, FStatus);
end;

procedure TSendEmail.DoProgress;
begin
  if Assigned(FOnProgress) then
    FOnProgress(nil, FPos);
end;

procedure TSendEmail.DoSendingData;
begin
  if Assigned(FOnSendingData) then
    FOnSendingData(nil, FCount, FTime);
end;

procedure TSendEmail.Execute;
begin
  inherited;
  FStatus := sStartSending;
  Synchronize(DoChangeStatus);
  if Send then
    FStatus := sDone
  else
    FStatus := FError;
  Synchronize(DoChangeStatus);
  Synchronize(DoDone);
end;

procedure TSendEmail.DoDone;
begin
  if Assigned(FOnDone) then
    FOnDone(nil, FStatus <> sDone, FStatus);
end;

procedure TSendEmail.OnMonitor(Sender: TObject; Writing: Boolean;
  const Buffer: TMemory; Len: Integer);
var
  buf: AnsiString;
begin
  buf := PChar(buffer);
  SetLength(buf, Len);
  if Pos('DATA'#13#10, AnsiUpperCase(buf)) = 1 then
  begin
    FSendData := True;
    FStatus := sSendingData;
    FPos := 0;
    FTime := Now;
    Synchronize(DoSendingData);
    Synchronize(DoChangeStatus);
  end
  else if Pos('ESMTP', AnsiUpperCase(buf)) > 0 then
  begin
    FStatus := sLogin;
    Synchronize(DoChangeStatus);
  end
  else if Pos('MAIL FROM', AnsiUpperCase(buf)) > 0 then
  begin
    FStatus := sMailFrom;
    Synchronize(DoChangeStatus);
  end
  else if Pos('RCPT TO', AnsiUpperCase(buf)) > 0 then
  begin
    FStatus := sMailTo;
    Synchronize(DoChangeStatus);
  end
  else if buf = '.' then
  begin
    FStatus := sLogOut;
    Synchronize(DoChangeStatus);
  end;
end;

procedure TSendEmail.OnStatus(Sender: TObject; Reason: THookSocketReason;
  const Value: string);
begin
  if FSendData then
  begin
    if (Reason = HR_WriteCount) and (StrToIntDef(Value, 0) > 10) then
    begin
      FPos := FPos + StrToIntDef(Value, 0);
      Synchronize(DoProgress);
    end;
  end;
end;

function TSendEmail.Send: Boolean;
var
  SMTPSend: TSMTPSend;
  MimeMsg: TMimeMess;
  MIMEPart, MIMEFile: TMimePart;
  i: Integer;
begin
  Result := True;
  SMTPSend := TSMTPSend.Create;
  MimeMsg := TMimeMess.Create;
  try
    FSendData := False;
    SMTPSend.Sock.OnStatus := OnStatus;
    SMTPSend.Sock.OnMonitor := OnMonitor;

    FStatus := sCreatingEmail;
    Synchronize(DoChangeStatus);

    MimeMsg.Header.From := FEmail.Account.FromName + ' <' + FEmail.Account.FromAddress + '>';
    MimeMsg.Header.ToList.Assign(FEmail.Ct);
    MimeMsg.Header.CCList.Assign(FEmail.Cc);
    MimeMsg.Header.Subject := FEmail.Subject;
    MimeMsg.Header.Organization := FEmail.Account.Organisation;
    MimeMsg.Header.Date := Now;
    MimeMsg.Header.XMailer := 'mailer by Misiekd';
    MimeMsg.Header.CharsetCode := FEmail.Encode; //Encode jest typu TMimeChar
    MimeMsg.Header.ReplyTo := FEmail.Account.ReplyToName + ' <' + FEmail.Account.ReplyToAddress + '>';

    MIMEPart := MimeMsg.AddPartMultipart('mixed', nil);

    MimeMsg.AddPartText(FEmail.Body, MIMEPart);
    for i := 0 to FEmail.AttachmentList.Count - 1 do
    begin
      MIMEFile := MimeMsg.AddPartBinary(FEmail.AttachmentList[i], FEmail.AttachmentList[i].AttachmentName, MIMEPart);
      MIMEFile.EncodingCode := ME_BASE64;
    end;
    MimeMsg.EncodeMessage;
    SMTPSend.TargetHost := FEmail.Account.Host;
    SMTPSend.TargetPort := IntToStr(FEmail.Account.Port);
    SMTPSend.UserName := FEmail.Account.UserName;
    SMTPSend.Password := FEmail.Account.UserPass;
    SMTPSend.AutoTLS := True;
    if SMTPSend.Login then
    begin
      if SMTPSend.AuthDone then
      begin
        SMTPSend.MailFrom(FEmail.Account.UserName + '@' + FEmail.Account.Host, Length(MimeMsg.Lines.Text));
        for i := 0 to FEmail.Ct.Count - 1 do
          SMTPSend.MailTo(GetEmailAddr(FEmail.Ct[i]));
        for i := 0 to FEmail.Cc.Count - 1 do
          SMTPSend.MailTo(GetEmailAddr(FEmail.Cc[i]));
        for i := 0 to FEmail.Bcc.Count - 1 do
          SMTPSend.MailTo(GetEmailAddr(FEmail.Bcc[i]));

        FCount := Length(MimeMsg.Lines.Text);
        if SMTPSend.MailData(MimeMsg.Lines) then
          SMTPSend.Logout
        else begin
          FError := sErrSendData;
          Result := False;
        end;
      end
      else begin
        FError := sErrSendAuth;
        Result := False;
      end;
    end
    else begin
      FError := sErrLogin;
      Result := False;
    end;
  finally
    FreeAndNil(MimeMsg);
    FreeAndNil(SMTPSend);
  end;
end;

end.

co do ssla to ja po prostu dodałem ssl_cryptlib do uses i tyle. Może masz jakąś inną wersję synapse :/
powinieneś się domyśleć co ma w sobie klasa TEmail - myślę, że pola są dość dobrze nazwane :)
Wyłapuje i zgłasza różne błędy (w tym błędny login), możesz podpiąć progress i informację tekstową. Działa to od paru lat u klienta, wysyła dość dużo maili, głównie z załącznikami. Jak coś to pytaj

0
Misiekd napisał(a)

jeszcze raz moja klasa :)
{...}
Jak coś to pytaj

W zasadzie nie mam pytań. Właśnie wróciłem z weekendu i miałem sobie coś podobnego przemyśleć - dzięki : )

Będzie mi potrzeba też synchroniczna wersja wysyłki, ale to raczej nie problem, bo synapse z tego co widzę jest w większości synchroniczny. No i kilka drobnych zmian w mimemess: AddPartHTMLEx, IdealCharsets, ... Chyba nieco inaczej ten progress zaimplementuję, raczej zmodyfikuję MailData, wtedy w prosty sposób będzie można zrobić przerywanie wysyłki.

A miałeś misiekd jakieś problemy z synapsem ? Próbowałeś kiedyś uzyskać jakiś "support" ? I czy masz jakieś info czy projekt jest wciąż żyw ? Co prawda na ten moment potrzebuję tylko SMTP, ale że kod całego pakietu wydaje się lekki prosty i przyjemny, może docelowo skorzystałbym z niego w większym zakresie.

b

0

problemów nie miałem. Dosyć dobrze mam przerobione wysyłanie i odbieranie maili na różnych skrzynkach (w tym na gmail). W kilku programach używam też "gołych" gniazd i też jest ok. Dodatkowo masz źródła, które są lekkie i w miarę dobrze opisane. Nigdy nie musiałem korzystać z supportu. BTW generalnie od kilku lat nie było (a przynajmniej mi nic na ten temat nie wiadomo) żadnych większych zmian w protokołach więc nie widzę co by można poprawiać poza błędami :). Zobacz sobie na changeloga tam generalnie są tylko drobne poprawki do poszczególnych klas. Zerknij sobie na listę mailingową http://sourceforge.net/mailarchive/forum.php?forum_name=synalist-public ona cały czas żyje. BTW2 podejrzewam, że najlepszym wyjściem będzie pobranie źródeł z SVNa - będziesz miał pewność, że większość błędów z przed roku będzie poprawiona

1 użytkowników online, w tym zalogowanych: 0, gości: 1