![]() |
email-downloader as as service
Hallo,
Da ich Performance-Probleme bei einer Webapplication habe, die eMails downloadet und in eine Firebird SQL Datenbank schreibt - suche ich nun eine Möglichkeit das ganze als eigenen Dienst zu realisieren... Gibt es da zufällig schon irgendeinen Demo-Sourcecode - wo der Download via Pop (Intervall alle x Minuten -inkl. abspeichern der Mail als HTML UND Eintrag in Datenbank - abspeichern der Attachement) realisiert wurde? Vielen Dank für Hinweise Erich |
AW: email-downloader as as service
Erzähl doch mal mehr wo genau bei dir die Performanceprobleme auftreten.
Ich glaube es ist sinnvoller diese zu beheben als diese durch das "verstecken" in einem Diest nur scheinbar zu lösen. |
AW: email-downloader as as service
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
vielen Dank für deine Nachfrage: Hab jetzt - das was ich in der Webapp hatte - in einen Service gepackt .. ABER: Ob das, was ich da so zusammengeschustert hab auch wirklich stabil läuft ist ne andere Frage ????
Code:
program mailservice;
uses Vcl.SvcMgr, Unit1 in 'Unit1.pas' {MountainWebMailer: TService}; {$R *.RES} begin if not Application.DelayInitialize or Application.Installing then Application.Initialize; Application.CreateForm(TMountainWebMailer, MountainWebMailer); Application.Run; end.
Code:
unit Unit1;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs, ZAbstractConnection, ZConnection, Data.DB, ZAbstractRODataset,ComCtrls, ZAbstractDataset, ZDataset, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdMessage, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase,IdAttachment, IdMessageClient, IdPOP3,IniFiles, Vcl.ExtCtrls,IdText,Registry; type TMountainWebMailer = class(TService) pop: TIdPOP3; msg: TIdMessage; IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL; MAILDATENBANK: TZQuery; DMAILDATENBANK: TDataSource; MAILKONTEN: TZQuery; DMAILKONTEN: TDataSource; Z_NUMMER: TZQuery; ZConnection1: TZConnection; Timer1: TTimer; procedure Timer1Timer(Sender: TObject); private { Private-Deklarationen } ini: TIniFile; filename:String; public function GetServiceController: TServiceController; override; { Public-Deklarationen } end; var MountainWebMailer: TMountainWebMailer; implementation {$R *.DFM} procedure ServiceController(CtrlCode: DWord); stdcall; begin MountainWebMailer.Controller(CtrlCode); end; function TMountainWebMailer.GetServiceController: TServiceController; begin Result := ServiceController; end; procedure TMountainWebMailer.Timer1Timer(Sender: TObject); var MailCount,Mailgroesse,intIndex :Integer; itm:TListItem; i:integer; s,extensio:string; neue_nummer:String; ininame:String; lokaler_pfad, hostname, datenpfad, installationspfad, domain_name :String; begin with TEventLogger.Create('Mailservice') do begin try LogMessage('ServiceStart...', EVENTLOG_INFORMATION_TYPE); finally Free; end; end; ininame := extractfilepath(ParamStr(0)) + 'server.ini'; filename := extractfilepath(ParamStr(0)); ini := TIniFile.Create(ininame); try lokaler_pfad := ini.ReadString('DATABASE','Pfad',extractfilepath(ParamStr(0))+'files\database\DATABASE.FDB'); hostname := ini.ReadString('DATABASE','Host','localhost'); datenpfad := ini.ReadString('FILES', 'Pfad',extractfilepath(ParamStr(0))); installationspfad := ini.ReadString('PFAD', 'Pfad',''); domain_name := ini.ReadString('DATABASE','Domain',''); finally ini.Free; end; with TEventLogger.Create('Mailservice') do begin try ZConnection1.Disconnect; ZConnection1.HostName:=hostname; ZConnection1.Port:=3050; ZConnection1.Database:=lokaler_pfad; ZConnection1.User:='SYSDBA'; ZConnection1.Password:='masterkey'; ZConnection1.Connect; LogMessage('Connection.Connect ...', EVENTLOG_INFORMATION_TYPE); LogMessage('Connection.Database ...' + lokaler_pfad, EVENTLOG_INFORMATION_TYPE); finally Free; end; end; with TEventLogger.Create('Mailservice') do begin try LogMessage('Loop starts ...', EVENTLOG_INFORMATION_TYPE); finally Free; end; end; with TEventLogger.Create('Mailservice') do begin try MAILKONTEN.SQL.Clear; MAILKONTEN.SQL.Append('SELECT * FROM MAILKONTEN'); MAILKONTEN.Open; LogMessage('MAILKONTEN Open...', EVENTLOG_INFORMATION_TYPE); finally Free; end; end; while not MAILKONTEN.Eof do begin POP.Disconnect; POP.Host := MAILKONTEN.FieldByName('POP3').AsString; POP.Port := strtoint(MAILKONTEN.FieldByName('PORT_POP3').AsString); POP.Username := MAILKONTEN.FieldByName('BENUTZERNAME').AsString; POP.Password := MAILKONTEN.FieldByName('KENNWORT').AsString; POP.Connect; MailCount := POP.CheckMessages; LogMessage('MAILKONTO "'+POP.Username+'" hat '+inttostr(MailCount)+' Mails', EVENTLOG_INFORMATION_TYPE); if MailCount > 0 then begin for intIndex := 1 to MailCount do begin msg.Clear; pop.Retrieve(intIndex, Msg); MAILDATENBANK.SQL.Clear; MAILDATENBANK.SQL.Append('SELECT MESSAGID FROM MAILDATENBANK WHERE MESSAGID = '+#39+msg.MsgId+#39+''); MAILDATENBANK.Open; // Die Mail habe ich noch nicht !!!!!!!!! if MAILDATENBANK.RecordCount = 0 then begin Z_NUMMER.SQL.Clear; Z_NUMMER.SQL.add('SELECT GEN_ID( POOL, 1 ) AS IDR FROM RDB$DATABASE'); Z_NUMMER.open; neue_nummer:=inttostr(Z_NUMMER.FieldByName('IDR').AsInteger); MAILDATENBANK.SQL.Clear; MAILDATENBANK.SQL.Append('SELECT * FROM MAILDATENBANK WHERE INR = -1'); MAILDATENBANK.Open; MAILKONTEN.SQL.Clear; MAILKONTEN.SQL.Append('SELECT * FROM MAILKONTEN WHERE INR = -1'); MAILKONTEN.Open; MAILDATENBANK.Append; //MAILDATENBANK.FieldByName('USER').AsInteger:=strtoint(main.MainForm.benutzernummer); MAILDATENBANK.FieldByName('INR').AsString:=neue_nummer; MAILDATENBANK.FieldByName('VON').AsString:=Msg.From.Text; MAILDATENBANK.FieldByName('ANTWORTADRESSE').AsString:=msg.from.Address; MAILDATENBANK.FieldByName('BETREFF').AsString:=Msg.Subject; MAILDATENBANK.FieldByName('DATUM').AsDateTime:=Msg.Date; MAILDATENBANK.FieldByName('MIMETYPE').AsString:=msg.AttachmentEncoding; MAILDATENBANK.FieldByName('CONTENTTYPE').AsString:=msg.ContentType; MAILDATENBANK.FieldByName('MESSAGID').AsString:=msg.MsgId; MAILDATENBANK.FieldByName('KONTONAME').AsString:=MAILKONTEN.FieldByName('KONTONAME').AsString; MAILDATENBANK.FieldByName('KONTONUMMER').AsString:=MAILKONTEN.FieldByName('INR').AsString; if Msg.MessageParts.Count = 0 then MAILDATENBANK.FieldByName('ANHANG').AsString:=''; if Msg.MessageParts.Count > 0 then MAILDATENBANK.FieldByName('ANHANG').AsString:='Anhang'; MAILDATENBANK.FieldByName('GELESEN').AsInteger:=0; MAILDATENBANK.FieldByName('PR').AsInteger:=0; MAILDATENBANK.FieldByName('ZUORDNUNG').AsString:=''; MAILDATENBANK.Post; //Anhang for i := 0 to Msg.MessageParts.Count-1 do begin if Msg.MessageParts.Items[i] is tIdAttachment then begin s := (Msg.MessageParts.Items[i] as tIdAttachment).Filename; // Extension ändern extensio:= ExtractFileExt(s) ; (Msg.MessageParts.Items[i] as tIdAttachment).savetofile(filename +'files\Mails\Anhang_' + neue_nummer +extensio); end; end; // HTML Mail if msg.MessageParts.Count > 0 then begin for i := 0 to Msg.MessageParts.Count-1 do begin if Msg.MessageParts.Items[i] is TIdText then begin //Logger.AddLogStrings(TIdText(Msg.MessageParts.Items[i]).Body); TIdText(Msg.MessageParts.Items[i]).Body.SaveToFile(filename +'files\Mails\html_' + neue_nummer + '.html'); end; end; end; // Text Mail if msg.ContentType = 'text/html' then begin //Logger.AddLogStrings(msg.body); Msg.Body.SaveToFile(filename +'files\Mails\html_' + neue_nummer + '.html'); end; // Text Mail if msg.ContentType = 'text/plain' then begin //Logger.AddLogStrings(msg.body); Msg.Body.SaveToFile(filename +'files\Mails\text_' + neue_nummer + '.txt'); end; end; // Die Mail habe ich noch nicht /////// //Kopie am Server belassen: also NICHT löschen //pop.Delete(intIndex); // Löscht die aktuelle Mail !!!! end; end; // POP.Disconnect; MAILKONTEN.Next; end; with TEventLogger.Create('Mailservice') do begin try LogMessage('ServiceStop...', EVENTLOG_INFORMATION_TYPE); finally Free; end; end; ZConnection1.Disconnect; end; // procedure end. |
AW: email-downloader as as service
Man kann auch PAS-Dateien anhängen.
Macht Thread's bei langem Code lesbarer und lohnt sich, wenn eh ganze Units gepostet werden. |
AW: email-downloader as as service
Bzgl. der Performance: Du loggst doch. WO genau treten denn die Performanceprobleme auf? Du solltest Dich zunächst mal auf die Queries konzentieren:
* Parametrisieren statt zusammensetzen * Konstante Queries nicht jedes mal neu erzeugen sondern stehen lassen und dann jeweils öffnen / schliessen * Active anstelle von Open / Close verwenden, das ist (minimal) weniger Stack und Laufzeit |
AW: email-downloader as as service
Zitat:
TEventLogger.Create Free Create Free Create Free Create Free ... Und wenn es in der Schleife knallt, dann wird kein Disconnect gemacht. |
AW: email-downloader as as service
Hallo und vielen Dank für eure Hinweise...
Hab jetzt Try Except verbessert .. und Logger deaktiviert :-) Jetzt hätte ich eine weitere Frage: In manchen Mails sind bilder als CID integriert ... Wie schaffe ich es, die Mails als HTML abzuspeichern - die Links der CID href="cid:xxxx ... ) im Quelltext zu verändern .. und die CID´s als Datei irgendwo lokal hinterlegen? Vielen Dank Erich |
AW: email-downloader as as service
Damit die Maildaten wirklich protabel sind, bette die Bilder base64-encoded in die Mail ein (referenziert via data:image/jpeg;base64). Externe images dafür einzulesen können aber Deinen Service zum Absturz bringen oder zu Timeouts führen und stellen ein Sicherheitsrisiko dar.
|
AW: email-downloader as as service
Hallo Union :-)
danke für deinen Tipp - leider werden die Mails ja nicht von mir erstellt sondern werden von allen möglichen Absendern erzeugt ... Ich will sie darstellen - was schon gut klappt. Das Abspeichern der Anhänge funktioniert auch. Nur die Bilder, die als cid eingebettet sind bereiten mir Kopfzerbrechen ;-) Vielen Dank erich |
AW: email-downloader as as service
Zitat:
D. H.: Du musst die entsprechenden Mails (automatisiert) bearbeiten und dann die bearbeitete Version speichern. |
AW: email-downloader as as service
Hmm..
Mal ne ganz andere Idee: Wieso 'zerlegst' Du die Mail? Anstelle alles einzeln abzuspeichern, kannst Du die Mail doch direkt als Stream in deine DB speichern, dann hast Du immer alle Anhänge, eingebettete Bilder und so weiter enthalten. Somit hast Du nur für die schnelle Suche die Kopfdaten und zur Anzeige wird die Message dann mit LoadFromStream geladen und angezeigt. Wenn die Anhänge dann doch extern benötigt werden, dann kann der User diese aus der Ansicht heraus dort speichern, wo er sie benötigt. So bleiben alle Bestandteile deiner Mail zusammen, incl. der Eingebetteten Bilder. Wenn Du dir sorgen um die Datenbankgröße machst, dann kannst Du den Mailstream vor dem speichern in die DB ja noch packen. Nur mal so ne Idee.. ;) Nach dem Pronziep arbeiten eigendlich die meisten EMail-Programme (Outlook/Thunderbird). ;) |
AW: email-downloader as as service
Hallo HolgerX
vielen Dank für deinen Tipp - hab jetzt deinen Ansatz angefangen .. die Mails werden jetzt in ein BLOB Field gespeichert Nun hab ich aber ein Problem: Wenn ich den Stream lade und in einen Iframe sende sehe ich nun den Quelltext der Mail: Zitat:
Ich mache momentan folgendes zum Speichern:
Delphi-Quellcode:
pop.Retrieve(intIndex, Msg);
.... Msg.SaveToStream(BlobStream); BlobStream.Position := 0; MAILDATENBANK.Close; MAILDATENBANK.SQL.Text := 'insert into MAILDATENBANK (INR, USER_INR, DATEN) values (:inr, :user_inr, :daten)'; MAILDATENBANK.ParamByName('inr').AsString := neue_nummer; MAILDATENBANK.ParamByName('user_inr').AsInteger := USER_INR; MAILDATENBANK.ParamByName('daten').LoadFromStream(BlobStream, ftBlob); MAILDATENBANK.ExecSQL; BlobStream.Free; Irgendwie verstehe ich das ganze nicht ... ich brauch für die Darstellung der Mail die Binärdaten der eingebetteten Bilder -- aber zur Darstellung der Mail benötige ich die Msg.Body-Daten Keine Ahnung, wie ich nun diesen eMail-Stream darstellen könnte (und das für alle möglichen Content-Types) Bei meiner "alten" Lösung habe ich Msg.ContentType verwendet...
Delphi-Quellcode:
if Msg.ContentType = 'text/html' then
begin Msg.Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; if AnsiContainsStr(Msg.ContentType, 'text/plain') then begin Msg.Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; if Msg.ContentType = 'multipart/alternative' then begin Msg.Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; if Msg.ContentType = 'multipart/mixed' then begin Msg.Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; if Msg.ContentType = 'multipart/related; type="multipart/alternative"' then begin Msg.Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; if AnsiContainsStr(Msg.ContentType, 'application/pdf') then begin Msg.Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; //Mailteile for i := 0 to Msg.MessageParts.Count-1 do begin erledigt:=0; if Msg.MessageParts.Items[i] is tIdAttachment then begin anzahl_anhang:=anzahl_anhang+1; s := (Msg.MessageParts.Items[i] as tIdAttachment).Filename; extensio:= ExtractFileExt(s) ; (Msg.MessageParts.Items[i] as tIdAttachment).savetofile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\Anhang_' + neue_nummer +'_'+inttostr(anzahl_anhang)+extensio); MAILDATENBANK.Edit; MAILDATENBANK.FieldByName('ANHANG_ANZAHL').AsInteger:=anzahl_anhang; MAILDATENBANK.Post; Z_NUMMER.SQL.Clear; Z_NUMMER.SQL.add('SELECT GEN_ID( POOL, 1 ) AS IDR FROM RDB$DATABASE'); Z_NUMMER.open; MAILANHANG.Append; MAILANHANG.FieldByName('INR').AsInteger:=Z_NUMMER.FieldByName('IDR').AsInteger; MAILANHANG.FieldByName('PR').AsString:=neue_nummer; MAILANHANG.FieldByName('ORIGINALNAME').AsString:= (Msg.MessageParts.Items[i] as tIdAttachment).FileName; MAILANHANG.FieldByName('FILE').AsString:= 'Anhang_' + neue_nummer +'_'+inttostr(anzahl_anhang)+extensio; MAILANHANG.Post; end; if Msg.MessageParts.Items[i] is TIdText then begin TIdText(Msg.MessageParts.Items[i]).Body.SaveToFile(filename +'files\Mails\'+inttostr(zaehler1)+'\'+inttostr(neue_nummer_integer)+'\html_' + neue_nummer + '.html',TEncoding.UTF8); end; end; // for i := 0 to Msg.MessageParts.Count-1 do end; // Die Mail habe ich noch nicht |
AW: email-downloader as as service
Hmm..
Ich mache es bei meinem EMail-Viewer so: - Lade die Mail in IDMessage - Speichere alle Anhänge 'Temporär' ins User\temp- Verzeichnis (als weiteres Unterverzeichnis verwende ich dann eine GUID). - Nehme den Body und ersetze die IFrames mit den absoluten Pfadangaben zum Bild. - Gebe den Body an den TWebBrowser zur Anzeige. (bei reinen Text-Bodys um die HTML-Tags ergänzt). Dieser Browser zeigt dann die Mail inclusive der Bilder an. Wenn die Anzeige dieser Mail beendet wird, lösche ich (anhand der Verzeichnisguid identifiziert) die Temporären Dateien wieder. Wenn der Betrachter geschlossen wird, gibt es somit keine Dateien irgendwo liegen. Das gleiche Prinzip nutzen eigentlich alle EMail-Viewer. |
AW: email-downloader as as service
Was mir auffällt, falls Du mal die Mails löschen willst:
Delphi-Quellcode:
for intIndex := 1 to MailCount do solltest Du dann besser rückwärts durchlaufen, sonst bekommst Du Meldungen ala "mail with sequence number 9 was deleted earlier" nur als kleiner Hinweis... Ciao Stefan |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:00 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz