123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986 |
- { lNet SMTP unit
- CopyRight (C) 2005-2008 Ales Katona
- This library is Free software; you can rediStribute it and/or modify it
- under the terms of the GNU Library General Public License as published by
- the Free Software Foundation; either version 2 of the License, or (at your
- option) any later version.
- This program is diStributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; withOut even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
- for more details.
- You should have received a Copy of the GNU Library General Public License
- along with This library; if not, Write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
- This license has been modified. See File LICENSE.ADDON for more inFormation.
- Should you find these sources without a LICENSE File, please contact
- me at [email protected]
- }
- unit lsmtp;
- {$mode objfpc}{$H+}
- {$inline on}
- interface
- uses
- Classes, SysUtils, Contnrs, Base64,
- lNet, lEvents, lCommon, lMimeWrapper, lMimeStreams;
-
- type
- TLSMTP = class;
- TLSMTPClient = class;
-
- TLSMTPStatus = (ssNone, ssCon, ssHelo, ssEhlo, ssAuthLogin, ssAuthPlain,
- ssStartTLS, ssMail, ssRcpt, ssData, ssRset, ssQuit, ssLast);
- TLSMTPStatusSet = set of TLSMTPStatus;
- TLSMTPStatusRec = record
- Status: TLSMTPStatus;
- Args: array[1..2] of string;
- end;
-
- { TLSMTPStatusFront }
- {$DEFINE __front_type__ := TLSMTPStatusRec}
- {$i lcontainersh.inc}
- TLSMTPStatusFront = TLFront;
- TLSMTPClientStatusEvent = procedure (aSocket: TLSocket;
- const aStatus: TLSMTPStatus) of object;
-
- { TMail }
- TMail = class
- protected
- FMailText: string;
- FMailStream: TMimeStream;
- FRecipients: string;
- FSender: string;
- FSubject: string;
- function GetCount: Integer;
- function GetSection(i: Integer): TMimeSection;
- procedure SetSection(i: Integer; const AValue: TMimeSection);
- public
- constructor Create;
- destructor Destroy; override;
- procedure AddTextSection(const aText: string; const aCharSet: string = 'UTF-8');
- procedure AddFileSection(const aFileName: string);
- procedure AddStreamSection(aStream: TStream; const FreeStream: Boolean = False);
- procedure DeleteSection(const i: Integer);
- procedure RemoveSection(aSection: TMimeSection);
- procedure Reset;
- public
- property MailText: string read FMailText write FMailText; deprecated; // use sections!
- property Sender: string read FSender write FSender;
- property Recipients: string read FRecipients write FRecipients;
- property Subject: string read FSubject write FSubject;
- property Sections[i: Integer]: TMimeSection read GetSection write SetSection; default;
- property SectionCount: Integer read GetCount;
- end;
- TLSMTP = class(TLComponent)
- protected
- FConnection: TLTcp;
- FFeatureList: TStringList;
- protected
- function GetTimeout: Integer;
- procedure SetTimeout(const AValue: Integer);
-
- function GetSession: TLSession;
- procedure SetSession(const AValue: TLSession);
- procedure SetCreator(AValue: TLComponent); override;
- function GetConnected: Boolean;
- function GetSocketClass: TLSocketClass;
- procedure SetSocketClass(const AValue: TLSocketClass);
-
- function GetEventer: TLEventer;
- procedure SetEventer(Value: TLEventer);
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
-
- function HasFeature(aFeature: string): Boolean;
- public
- property Connected: Boolean read GetConnected;
- property Connection: TLTcp read FConnection;
- property SocketClass: TLSocketClass read GetSocketClass write SetSocketClass;
- property Eventer: TLEventer read GetEventer write SetEventer;
- property Timeout: Integer read GetTimeout write SetTimeout;
- property Session: TLSession read GetSession write SetSession;
- property FeatureList: TStringList read FFeatureList;
- end;
- { TLSMTPClient }
- TLSMTPClient = class(TLSMTP, ILClient)
- protected
- FStatus: TLSMTPStatusFront;
- FCommandFront: TLSMTPStatusFront;
- FPipeLine: Boolean;
- FAuthStep: Integer;
- FOnConnect: TLSocketEvent;
- FOnReceive: TLSocketEvent;
- FOnDisconnect: TLSocketEvent;
- FOnSuccess: TLSMTPClientStatusEvent;
- FOnFailure: TLSMTPClientStatusEvent;
- FOnError: TLSocketErrorEvent;
- FOnSent: TLSocketProgressEvent;
- FSL: TStringList;
- FStatusSet: TLSMTPStatusSet;
- FBuffer: string;
- FDataBuffer: string; // intermediate wait buffer on DATA command
- FTempBuffer: string; // used independently from FBuffer for feature list
- FCharCount: Integer; // count of chars from last CRLF
- FStream: TStream;
- protected
- procedure OnEr(const msg: string; aSocket: TLSocket);
- procedure OnRe(aSocket: TLSocket);
- procedure OnCo(aSocket: TLSocket);
- procedure OnDs(aSocket: TLSocket);
- procedure OnCs(aSocket: TLSocket);
- protected
- function CanContinue(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): Boolean;
-
- function CleanInput(var s: string): Integer;
-
- procedure EvaluateServer;
- procedure EvaluateFeatures;
- procedure EvaluateAnswer(const Ans: string);
- procedure ExecuteFrontCommand;
-
- procedure AddToBuffer(s: string);
- procedure SendData(const FromStream: Boolean = False);
- function EncodeBase64(const s: string): string;
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
-
- function Connect(const aHost: string; const aPort: Word = 25): Boolean; virtual; overload;
- function Connect: Boolean; virtual; overload;
-
- function Get(var aData; const aSize: Integer; aSocket: TLSocket = nil): Integer; virtual;
- function GetMessage(out msg: string; aSocket: TLSocket = nil): Integer; virtual;
- procedure SendMail(From, Recipients, Subject, Msg: string);
- procedure SendMail(From, Recipients, Subject: string; aStream: TStream);
- procedure SendMail(aMail: TMail);
-
- procedure Helo(aHost: string = '');
- procedure Ehlo(aHost: string = '');
- procedure StartTLS;
- procedure AuthLogin(aName, aPass: string);
- procedure AuthPlain(aName, aPass: string);
- procedure Mail(const From: string);
- procedure Rcpt(const RcptTo: string);
- procedure Data(const Msg: string);
- procedure Rset;
- procedure Quit;
-
- procedure Disconnect(const Forced: Boolean = True); override;
-
- procedure CallAction; override;
- public
- property PipeLine: Boolean read FPipeLine write FPipeLine;
- property StatusSet: TLSMTPStatusSet read FStatusSet write FStatusSet;
- property OnConnect: TLSocketEvent read FOnConnect write FOnConnect;
- property OnReceive: TLSocketEvent read FOnReceive write FOnReceive;
- property OnDisconnect: TLSocketEvent read FOnDisconnect write FOnDisconnect;
- property OnSuccess: TLSMTPClientStatusEvent read FOnSuccess write FOnSuccess;
- property OnFailure: TLSMTPClientStatusEvent read FOnFailure write FOnFailure;
- property OnError: TLSocketErrorEvent read FOnError write FOnError;
- property OnSent: TLSocketProgressEvent read FOnSent write FOnSent;
- end;
- implementation
- const
- EMPTY_REC: TLSMTPStatusRec = (Status: ssNone; Args: ('', ''));
- {$i lcontainers.inc}
- function StatusToStr(const aStatus: TLSMTPStatus): string;
- const
- STATAR: array[ssNone..ssLast] of string = ('ssNone', 'ssCon', 'ssHelo', 'ssEhlo',
- 'ssStartTLS', 'ssAuthLogin', 'ssAuthPlain',
- 'ssMail', 'ssRcpt', 'ssData', 'ssRset', 'ssQuit', 'ssLast');
- begin
- Result := STATAR[aStatus];
- end;
- function MakeStatusRec(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): TLSMTPStatusRec;
- begin
- Result.Status := aStatus;
- Result.Args[1] := Arg1;
- Result.Args[2] := Arg2;
- end;
- { TLSMTP }
- function TLSMTP.GetSession: TLSession;
- begin
- Result := FConnection.Session;
- end;
- procedure TLSMTP.SetSession(const AValue: TLSession);
- begin
- FConnection.Session := aValue;
- end;
- procedure TLSMTP.SetCreator(AValue: TLComponent);
- begin
- inherited SetCreator(AValue);
-
- FConnection.Creator := AValue;
- end;
- function TLSMTP.GetTimeout: Integer;
- begin
- Result := FConnection.Timeout;
- end;
- procedure TLSMTP.SetTimeout(const AValue: Integer);
- begin
- FConnection.Timeout := aValue;
- end;
- function TLSMTP.GetConnected: Boolean;
- begin
- Result := FConnection.Connected;
- end;
- function TLSMTP.GetSocketClass: TLSocketClass;
- begin
- Result := FConnection.SocketClass;
- end;
- procedure TLSMTP.SetSocketClass(const AValue: TLSocketClass);
- begin
- FConnection.SocketClass := AValue;
- end;
- function TLSMTP.GetEventer: TLEventer;
- begin
- Result := FConnection.Eventer;
- end;
- procedure TLSMTP.SetEventer(Value: TLEventer);
- begin
- FConnection.Eventer := Value;
- end;
- constructor TLSMTP.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
-
- FFeatureList := TStringList.Create;
- FConnection := TLTcp.Create(nil);
- FConnection.Creator := Self;
- // TODO: rework to use the new TLSocketTCP
- FConnection.SocketClass := TLSocket;
- end;
- destructor TLSMTP.Destroy;
- begin
- FFeatureList.Free;
- FConnection.Free;
- inherited Destroy;
- end;
- function TLSMTP.HasFeature(aFeature: string): Boolean;
- var
- tmp: TStringList;
- i, j: Integer;
- AllArgs: Boolean;
- begin
- Result := False;
- try
- tmp := TStringList.Create;
- aFeature := UpperCase(aFeature);
- aFeature := StringReplace(aFeature, ' ', ',', [rfReplaceAll]);
- tmp.CommaText := aFeature;
- for i := 0 to FFeatureList.Count - 1 do begin
- if Pos(tmp[0], FFeatureList[i]) = 1 then begin
- if tmp.Count = 1 then // no arguments, feature found, just exit true
- Exit(True)
- else begin // check arguments
- AllArgs := True;
- for j := 1 to tmp.Count - 1 do
- if Pos(tmp[j], FFeatureList[i]) <= 0 then begin // some argument not found
- AllArgs := False;
- Break;
- end;
- if AllArgs then
- Exit(True);
- end;
- end;
- end;
- finally
- tmp.Free;
- end;
- end;
- { TLSMTPClient }
- constructor TLSMTPClient.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- FPort := 25;
- FStatusSet := [ssNone..ssLast]; // full set
- FSL := TStringList.Create;
- // {$warning TODO: fix pipelining support when server does it}
- FPipeLine := False;
-
- FConnection.OnError := @OnEr;
- FConnection.OnCanSend := @OnCs;
- FConnection.OnReceive := @OnRe;
- FConnection.OnConnect := @OnCo;
- FConnection.OnDisconnect := @OnDs;
- FStatus := TLSMTPStatusFront.Create(EMPTY_REC);
- FCommandFront := TLSMTPStatusFront.Create(EMPTY_REC);
- end;
- destructor TLSMTPClient.Destroy;
- begin
- if FConnection.Connected then
- Quit;
- FSL.Free;
- FStatus.Free;
- FCommandFront.Free;
- inherited Destroy;
- end;
- procedure TLSMTPClient.OnEr(const msg: string; aSocket: TLSocket);
- begin
- if Assigned(FOnFailure) then begin
- while not FStatus.Empty do
- FOnFailure(aSocket, FStatus.Remove.Status);
- end else
- FStatus.Clear;
- if Assigned(FOnError) then
- FOnError(msg, aSocket);
- end;
- procedure TLSMTPClient.OnRe(aSocket: TLSocket);
- begin
- if Assigned(FOnReceive) then
- FOnReceive(aSocket);
- end;
- procedure TLSMTPClient.OnCo(aSocket: TLSocket);
- begin
- if Assigned(FOnConnect) then
- FOnConnect(aSocket);
- end;
- procedure TLSMTPClient.OnDs(aSocket: TLSocket);
- begin
- if Assigned(FOnDisconnect) then
- FOnDisconnect(aSocket);
- end;
- procedure TLSMTPClient.OnCs(aSocket: TLSocket);
- begin
- SendData(FStatus.First.Status = ssData);
- end;
- function TLSMTPClient.CanContinue(const aStatus: TLSMTPStatus; const Arg1, Arg2: string): Boolean;
- begin
- Result := FPipeLine or FStatus.Empty;
- if not Result then
- FCommandFront.Insert(MakeStatusRec(aStatus, Arg1, Arg2));
- end;
- function TLSMTPClient.CleanInput(var s: string): Integer;
- var
- i: Integer;
- begin
- FSL.Text := s;
- case FStatus.First.Status of // TODO: clear this to a proper place, the whole thing needs an overhaul
- ssCon,
- ssEhlo: FTempBuffer := FTempBuffer + UpperCase(s);
- end;
- if FSL.Count > 0 then
- for i := 0 to FSL.Count - 1 do
- if Length(FSL[i]) > 0 then EvaluateAnswer(FSL[i]);
- s := StringReplace(s, CRLF, LineEnding, [rfReplaceAll]);
- i := Pos('PASS', s);
- if i > 0 then
- s := Copy(s, 1, i-1) + 'PASS';
- Result := Length(s);
- end;
- procedure TLSMTPClient.EvaluateServer;
- begin
- FFeatureList.Clear;
- if Length(FTempBuffer) = 0 then
- Exit;
- if Pos('ESMTP', FTempBuffer) > 0 then
- FFeatureList.Append('EHLO');
- FTempBuffer := '';
- end;
- procedure TLSMTPClient.EvaluateFeatures;
- var
- i: Integer;
- begin
- FFeatureList.Clear;
- if Length(FTempBuffer) = 0 then
- Exit;
- FFeatureList.Text := FTempBuffer;
- FTempBuffer := '';
- FFeatureList.Delete(0);
- i := 0;
- while i < FFeatureList.Count do begin;
- FFeatureList[i] := Copy(FFeatureList[i], 5, Length(FFeatureList[i])); // delete the response code crap
- FFeatureList[i] := StringReplace(FFeatureList[i], '=', ' ', [rfReplaceAll]);
- if FFeatureList.IndexOf(FFeatureList[i]) <> i then begin
- FFeatureList.Delete(i);
- Continue;
- end;
- Inc(i);
- end;
- end;
- procedure TLSMTPClient.EvaluateAnswer(const Ans: string);
- function GetNum: Integer;
- begin
- try
- Result := StrToInt(Copy(Ans, 1, 3));
- except
- Result := -1;
- end;
- end;
-
- function ValidResponse(const Answer: string): Boolean; inline;
- begin
- Result := (Length(Ans) >= 3) and
- (Ans[1] in ['1'..'5']) and
- (Ans[2] in ['0'..'9']) and
- (Ans[3] in ['0'..'9']);
- if Result then
- Result := (Length(Ans) = 3) or ((Length(Ans) > 3) and (Ans[4] = ' '));
- end;
-
- procedure Eventize(const aStatus: TLSMTPStatus; const Res: Boolean);
- begin
- FStatus.Remove;
- if Res then begin
- if Assigned(FOnSuccess) and (aStatus in FStatusSet) then
- FOnSuccess(FConnection.Iterator, aStatus);
- end else begin
- if Assigned(FOnFailure) and (aStatus in FStatusSet) then
- FOnFailure(FConnection.Iterator, aStatus);
- end;
- end;
-
- var
- x: Integer;
- begin
- x := GetNum;
- if ValidResponse(Ans) and not FStatus.Empty then
- case FStatus.First.Status of
- ssCon,
- ssHelo,
- ssEhlo: case x of
- 200..299: begin
- case FStatus.First.Status of
- ssCon : EvaluateServer;
- ssEhlo : EvaluateFeatures;
- end;
- Eventize(FStatus.First.Status, True);
- end;
- else begin
- Eventize(FStatus.First.Status, False);
- Disconnect(False);
- FFeatureList.Clear;
- FTempBuffer := '';
- end;
- end;
-
- ssStartTLS:
- case x of
- 200..299: begin
- Eventize(FStatus.First.Status, True);
- FConnection.Iterator.SetState(ssSSLActive);
- end;
- else begin
- Eventize(FStatus.First.Status, False);
- end;
- end;
-
- ssAuthLogin:
- case x of
- 200..299: begin
- Eventize(FStatus.First.Status, True);
- end;
- 300..399: if FAuthStep = 0 then begin
- AddToBuffer(FStatus.First.Args[1] + CRLF);
- Inc(FAuthStep);
- SendData;
- end else if FAuthStep = 1 then begin
- AddToBuffer(FStatus.First.Args[2] + CRLF);
- Inc(FAuthStep);
- SendData;
- end else begin
- Eventize(FStatus.First.Status, False);
- end;
- else begin
- Eventize(FStatus.First.Status, False);
- end;
- end;
-
- ssAuthPlain:
- case x of
- 200..299: begin
- Eventize(FStatus.First.Status, True);
- end;
- 300..399: begin
- AddToBuffer(FStatus.First.Args[1] + FStatus.First.Args[2] + CRLF);
- SendData;
- end;
- else begin
- Eventize(FStatus.First.Status, False);
- end;
- end;
- ssMail,
- ssRcpt: begin
- Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
- end;
- ssData: case x of
- 200..299: begin
- Eventize(FStatus.First.Status, True);
- end;
- 300..399: begin
- AddToBuffer(FDataBuffer);
- FDataBuffer := '';
- SendData(True);
- end;
- else begin
- FDataBuffer := '';
- Eventize(FStatus.First.Status, False);
- end;
- end;
-
- ssRset: begin
- Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
- end;
-
- ssQuit: begin
- Eventize(FStatus.First.Status, (x >= 200) and (x < 299));
- { if Assigned(FOnDisconnect) then
- FOnDisconnect(FConnection.Iterator);}
- Disconnect(False);
- end;
- end;
-
- if FStatus.Empty and not FCommandFront.Empty then
- ExecuteFrontCommand;
- end;
- procedure TLSMTPClient.ExecuteFrontCommand;
- begin
- with FCommandFront.First do
- case Status of
- ssHelo: Helo(Args[1]);
- ssEhlo: Ehlo(Args[1]);
- ssMail: Mail(Args[1]);
- ssRcpt: Rcpt(Args[1]);
- ssData: Data(Args[1]);
- ssRset: Rset;
- ssQuit: Quit;
- end;
- FCommandFront.Remove;
- end;
- procedure TLSMTPClient.AddToBuffer(s: string);
- var
- i: Integer;
- Skip: Boolean = False;
- begin
- for i := 1 to Length(s) do begin
- if Skip then begin
- Skip := False;
- Continue;
- end;
- if (s[i] = #13) or (s[i] = #10) then begin
- if s[i] = #13 then
- if (i < Length(s)) and (s[i + 1] = #10) then begin
- FCharCount := 0;
- Skip := True; // skip the crlf
- end else begin // insert LF to a standalone CR
- System.Insert(#10, s, i + 1);
- FCharCount := 0;
- Skip := True; // skip the new crlf
- end;
- if s[i] = #10 then begin
- System.Insert(#13, s, i);
- FCharCount := 0;
- Skip := True; // skip the new crlf
- end;
- end else if FCharCount >= 1000 then begin // line too long
- System.Insert(CRLF, s, i);
- FCharCount := 0;
- Skip := True;
- end else
- Inc(FCharCount);
- end;
-
- FBuffer := FBuffer + s;
- end;
- procedure TLSMTPClient.SendData(const FromStream: Boolean = False);
- const
- SBUF_SIZE = 65535;
-
- procedure FillBuffer;
- var
- s: string;
- begin
- SetLength(s, SBUF_SIZE - Length(FBuffer));
- SetLength(s, FStream.Read(s[1], Length(s)));
-
- AddToBuffer(s);
-
- if FStream.Position = FStream.Size then begin // we finished the stream
- AddToBuffer(CRLF + '.' + CRLF);
- FStream := nil;
- end;
- end;
- var
- n: Integer;
- Sent: Integer;
- begin
- if FromStream and Assigned(FStream) then
- FillBuffer;
- n := 1;
- Sent := 0;
- while (Length(FBuffer) > 0) and (n > 0) do begin
- n := FConnection.SendMessage(FBuffer);
- Sent := Sent + n;
- if n > 0 then
- Delete(FBuffer, 1, n);
- if FromStream and Assigned(FStream) and (Length(FBuffer) < SBUF_SIZE) then
- FillBuffer;
- end;
-
- if Assigned(FOnSent) and (FStatus.First.Status = ssData) then
- FOnSent(FConnection.Iterator, Sent);
- end;
- function TLSMTPClient.EncodeBase64(const s: string): string;
- var
- Dummy: TBogusStream;
- Enc: TBase64EncodingStream;
- begin
- Result := '';
- if Length(s) = 0 then
- Exit;
-
- Dummy := TBogusStream.Create;
- Enc := TBase64EncodingStream.Create(Dummy);
- Enc.Write(s[1], Length(s));
- Enc.Free;
- SetLength(Result, Dummy.Size);
- Dummy.Read(Result[1], Dummy.Size);
- Dummy.Free;
- end;
- function TLSMTPClient.Connect(const aHost: string; const aPort: Word = 25): Boolean;
- begin
- Result := False;
- Disconnect(True);
- if FConnection.Connect(aHost, aPort) then begin
- FTempBuffer := '';
- FHost := aHost;
- FPort := aPort;
- FStatus.Insert(MakeStatusRec(ssCon, '', ''));
- Result := True;
- end;
- end;
- function TLSMTPClient.Connect: Boolean;
- begin
- Result := Connect(FHost, FPort);
- end;
- function TLSMTPClient.Get(var aData; const aSize: Integer; aSocket: TLSocket): Integer;
- var
- s: string;
- begin
- Result := FConnection.Get(aData, aSize, aSocket);
- if Result > 0 then begin
- SetLength(s, Result);
- Move(aData, PChar(s)^, Result);
- CleanInput(s);
- end;
- end;
- function TLSMTPClient.GetMessage(out msg: string; aSocket: TLSocket): Integer;
- begin
- Result := FConnection.GetMessage(msg, aSocket);
- if Result > 0 then
- Result := CleanInput(msg);
- end;
- procedure TLSMTPClient.SendMail(From, Recipients, Subject, Msg: string);
- var
- i: Integer;
- begin
- FStream := nil;
- From := EncodeMimeHeaderText(From);
- Recipients := EncodeMimeHeaderText(Recipients);
- Subject := EncodeMimeHeaderText(Subject);
-
- if (Length(Recipients) > 0) and (Length(From) > 0) then begin
- Mail(From);
- FSL.CommaText := StringReplace(Recipients, ' ', ',', [rfReplaceAll]);
- for i := 0 to FSL.Count-1 do
- Rcpt(FSL[i]);
- Data('From: ' + From + CRLF + 'Subject: ' + Subject + CRLF + 'To: ' + FSL.CommaText + CRLF + CRLF + Msg);
- end;
- end;
- procedure TLSMTPClient.SendMail(From, Recipients, Subject: string; aStream: TStream);
- var
- i: Integer;
- begin
- From := EncodeMimeHeaderText(From);
- Recipients := EncodeMimeHeaderText(Recipients);
- Subject := EncodeMimeHeaderText(Subject);
-
- FStream := aStream;
- if (Length(Recipients) > 0) and (Length(From) > 0) then begin
- Mail(From);
- FSL.CommaText := StringReplace(Recipients, ' ', ',', [rfReplaceAll]);
- for i := 0 to FSL.Count-1 do
- Rcpt(FSL[i]);
- Data('From: ' + From + CRLF + 'Subject: ' + Subject + CRLF + 'To: ' + FSL.CommaText + CRLF);
- end;
- end;
- procedure TLSMTPClient.SendMail(aMail: TMail);
- begin
- if Length(aMail.FMailText) > 0 then
- SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.FMailText)
- else if Assigned(aMail.FMailStream) then
- SendMail(aMail.Sender, aMail.Recipients, aMail.Subject, aMail.FMailStream);
- end;
- procedure TLSMTPClient.Helo(aHost: string = '');
- begin
- if Length(aHost) = 0 then
- aHost := FHost;
- if CanContinue(ssHelo, aHost, '') then begin
- AddToBuffer('HELO ' + aHost + CRLF);
- FStatus.Insert(MakeStatusRec(ssHelo, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.Ehlo(aHost: string = '');
- begin
- if Length(aHost) = 0 then
- aHost := FHost;
- if CanContinue(ssEhlo, aHost, '') then begin
- FTempBuffer := ''; // for ehlo response
- AddToBuffer('EHLO ' + aHost + CRLF);
- FStatus.Insert(MakeStatusRec(ssEhlo, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.StartTLS;
- begin
- if CanContinue(ssStartTLS, '', '') then begin
- AddToBuffer('STARTTLS' + CRLF);
- FStatus.Insert(MakeStatusRec(ssStartTLS, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.AuthLogin(aName, aPass: string);
- begin
- aName := EncodeBase64(aName);
- aPass := EncodeBase64(aPass);
- FAuthStep := 0; // first, send username
-
- if CanContinue(ssAuthLogin, aName, aPass) then begin
- AddToBuffer('AUTH LOGIN' + CRLF);
- FStatus.Insert(MakeStatusRec(ssAuthLogin, aName, aPass));
- SendData;
- end;
- end;
- procedure TLSMTPClient.AuthPlain(aName, aPass: string);
- begin
- aName := EncodeBase64(#0 + aName);
- aPass := EncodeBase64(#0 + aPass);
- FAuthStep := 0;
- if CanContinue(ssAuthPlain, aName, aPass) then begin
- AddToBuffer('AUTH PLAIN' + CRLF);
- FStatus.Insert(MakeStatusRec(ssAuthPlain, aName, aPass));
- SendData;
- end;
- end;
- procedure TLSMTPClient.Mail(const From: string);
- begin
- if CanContinue(ssMail, From, '') then begin
- AddToBuffer('MAIL FROM:' + '<' + From + '>' + CRLF);
- FStatus.Insert(MakeStatusRec(ssMail, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.Rcpt(const RcptTo: string);
- begin
- if CanContinue(ssRcpt, RcptTo, '') then begin
- AddToBuffer('RCPT TO:' + '<' + RcptTo + '>' + CRLF);
- FStatus.Insert(MakeStatusRec(ssRcpt, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.Data(const Msg: string);
- begin
- if CanContinue(ssData, Msg, '') then begin
- AddToBuffer('DATA ' + CRLF);
- FDataBuffer := '';
- if Assigned(FStream) then begin
- if Length(Msg) > 0 then
- FDataBuffer := Msg;
- end else
- FDataBuffer := Msg + CRLF + '.' + CRLF;
- FStatus.Insert(MakeStatusRec(ssData, '', ''));
- SendData(False);
- end;
- end;
- procedure TLSMTPClient.Rset;
- begin
- if CanContinue(ssRset, '', '') then begin
- AddToBuffer('RSET' + CRLF);
- FStatus.Insert(MakeStatusRec(ssRset, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.Quit;
- begin
- if CanContinue(ssQuit, '', '') then begin
- AddToBuffer('QUIT' + CRLF);
- FStatus.Insert(MakeStatusRec(ssQuit, '', ''));
- SendData;
- end;
- end;
- procedure TLSMTPClient.Disconnect(const Forced: Boolean = True);
- begin
- FConnection.Disconnect(Forced);
- FStatus.Clear;
- FCommandFront.Clear;
- end;
- procedure TLSMTPClient.CallAction;
- begin
- FConnection.CallAction;
- end;
- { TMail }
- function TMail.GetCount: Integer;
- begin
- Result := FMailStream.Count;
- end;
- function TMail.GetSection(i: Integer): TMimeSection;
- begin
- Result := FMailStream.Sections[i];
- end;
- procedure TMail.SetSection(i: Integer; const AValue: TMimeSection);
- begin
- FMailStream.Sections[i] := aValue;
- end;
- constructor TMail.Create;
- begin
- FMailStream := TMimeStream.Create;
- end;
- destructor TMail.Destroy;
- begin
- FMailStream.Free;
- end;
- procedure TMail.AddTextSection(const aText: string; const aCharSet: string);
- begin
- FMailStream.AddTextSection(aText, aCharSet);
- end;
- procedure TMail.AddFileSection(const aFileName: string);
- begin
- FMailStream.AddFileSection(aFileName);
- end;
- procedure TMail.AddStreamSection(aStream: TStream; const FreeStream: Boolean);
- begin
- FMailStream.AddStreamSection(aStream, FreeStream);
- end;
- procedure TMail.DeleteSection(const i: Integer);
- begin
- FMailStream.Delete(i);
- end;
- procedure TMail.RemoveSection(aSection: TMimeSection);
- begin
- FMailStream.Remove(aSection);
- end;
- procedure TMail.Reset;
- begin
- FMailStream.Reset;
- end;
- end.
|