home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 December / Chip_2001-12_cd1.bin / zkuste / delphi / unity / d23456 / SYNAPSE.ZIP / source / lib / SMTPsend.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2001-08-13  |  15.2 KB  |  505 lines

  1. {==============================================================================|
  2. | Project : Delphree - Synapse                                   | 002.001.004 |
  3. |==============================================================================|
  4. | Content: SMTP client                                                         |
  5. |==============================================================================|
  6. | The contents of this file are Subject to the Mozilla Public License Ver. 1.1 |
  7. | (the "License"); you may not use this file except in compliance with the     |
  8. | License. You may obtain a Copy of the License at http://www.mozilla.org/MPL/ |
  9. |                                                                              |
  10. | Software distributed under the License is distributed on an "AS IS" basis,   |
  11. | WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for |
  12. | the specific language governing rights and limitations under the License.    |
  13. |==============================================================================|
  14. | The Original Code is Synapse Delphi Library.                                 |
  15. |==============================================================================|
  16. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  17. | Portions created by Lukas Gebauer are Copyright (c) 1999,2000,2001.          |
  18. | All Rights Reserved.                                                         |
  19. |==============================================================================|
  20. | Contributor(s):                                                              |
  21. |==============================================================================|
  22. | History: see HISTORY.HTM from distribution package                           |
  23. |          (Found at URL: http://www.ararat.cz/synapse/)                       |
  24. |==============================================================================}
  25.  
  26. {$WEAKPACKAGEUNIT ON}
  27.  
  28. unit SMTPsend;
  29.  
  30. interface
  31.  
  32. uses
  33.   SysUtils, Classes,
  34.   blcksock, SynaUtil, SynaCode;
  35.  
  36. const
  37.   cSmtpProtocol = 'smtp';
  38.  
  39. type
  40.   TSMTPSend = class(TObject)
  41.   private
  42.     FSock: TTCPBlockSocket;
  43.     FTimeout: Integer;
  44.     FSMTPHost: string;
  45.     FSMTPPort: string;
  46.     FResultCode: Integer;
  47.     FResultString: string;
  48.     FFullResult: TStringList;
  49.     FESMTPcap: TStringList;
  50.     FESMTP: Boolean;
  51.     FUsername: string;
  52.     FPassword: string;
  53.     FAuthDone: Boolean;
  54.     FESMTPSize: Boolean;
  55.     FMaxSize: Integer;
  56.     FEnhCode1: Integer;
  57.     FEnhCode2: Integer;
  58.     FEnhCode3: Integer;
  59.     FSystemName: string;
  60.     procedure EnhancedCode(const Value: string);
  61.     function ReadResult: Integer;
  62.     function AuthLogin: Boolean;
  63.     function AuthCram: Boolean;
  64.     function Helo: Boolean;
  65.     function Ehlo: Boolean;
  66.     function Connect: Boolean;
  67.   public
  68.     constructor Create;
  69.     destructor Destroy; override;
  70.     function Login: Boolean;
  71.     procedure Logout;
  72.     function Reset: Boolean;
  73.     function NoOp: Boolean;
  74.     function MailFrom(const Value: string; Size: Integer): Boolean;
  75.     function MailTo(const Value: string): Boolean;
  76.     function MailData(const Value: Tstrings): Boolean;
  77.     function Etrn(const Value: string): Boolean;
  78.     function Verify(const Value: string): Boolean;
  79.     function EnhCodeString: string;
  80.     function FindCap(const Value: string): string;
  81.   published
  82.     property Timeout: Integer read FTimeout Write FTimeout;
  83.     property SMTPHost: string read FSMTPHost Write FSMTPHost;
  84.     property SMTPPort: string read FSMTPPort Write FSMTPPort;
  85.     property ResultCode: Integer read FResultCode;
  86.     property ResultString: string read FResultString;
  87.     property FullResult: TStringList read FFullResult;
  88.     property ESMTPcap: TStringList read FESMTPcap;
  89.     property ESMTP: Boolean read FESMTP;
  90.     property Username: string read FUsername Write FUsername;
  91.     property Password: string read FPassword Write FPassword;
  92.     property AuthDone: Boolean read FAuthDone;
  93.     property ESMTPSize: Boolean read FESMTPSize;
  94.     property MaxSize: Integer read FMaxSize;
  95.     property EnhCode1: Integer read FEnhCode1;
  96.     property EnhCode2: Integer read FEnhCode2;
  97.     property EnhCode3: Integer read FEnhCode3;
  98.     property SystemName: string read FSystemName Write FSystemName;
  99.     property Sock: TTCPBlockSocket read FSock;
  100.   end;
  101.  
  102. function SendToRaw(const MailFrom, MailTo, SMTPHost: string;
  103.   const MailData: TStrings; const Username, Password: string): Boolean;
  104. function SendTo(const MailFrom, MailTo, Subject, SMTPHost: string;
  105.   const MailData: TStrings): Boolean;
  106. function SendToEx(const MailFrom, MailTo, Subject, SMTPHost: string;
  107.   const MailData: TStrings; const Username, Password: string): Boolean;
  108.  
  109. implementation
  110.  
  111. const
  112.   CRLF = #13#10;
  113.  
  114. constructor TSMTPSend.Create;
  115. begin
  116.   inherited Create;
  117.   FFullResult := TStringList.Create;
  118.   FESMTPcap := TStringList.Create;
  119.   FSock := TTCPBlockSocket.Create;
  120.   FSock.CreateSocket;
  121.   FTimeout := 300000;
  122.   FSMTPhost := cLocalhost;
  123.   FSMTPPort := cSmtpProtocol;
  124.   FUsername := '';
  125.   FPassword := '';
  126.   FSystemName := FSock.LocalName;
  127. end;
  128.  
  129. destructor TSMTPSend.Destroy;
  130. begin
  131.   FSock.Free;
  132.   FESMTPcap.Free;
  133.   FFullResult.Free;
  134.   inherited Destroy;
  135. end;
  136.  
  137. procedure TSMTPSend.EnhancedCode(const Value: string);
  138. var
  139.   s, t: string;
  140.   e1, e2, e3: Integer;
  141. begin
  142.   FEnhCode1 := 0;
  143.   FEnhCode2 := 0;
  144.   FEnhCode3 := 0;
  145.   s := Copy(Value, 5, Length(Value) - 4);
  146.   t := SeparateLeft(s, '.');
  147.   s := SeparateRight(s, '.');
  148.   if t = '' then
  149.     Exit;
  150.   if Length(t) > 1 then
  151.     Exit;
  152.   e1 := StrToIntDef(t, 0);
  153.   if e1 = 0 then
  154.     Exit;
  155.   t := SeparateLeft(s, '.');
  156.   s := SeparateRight(s, '.');
  157.   if t = '' then
  158.     Exit;
  159.   if Length(t) > 3 then
  160.     Exit;
  161.   e2 := StrToIntDef(t, 0);
  162.   t := SeparateLeft(s, ' ');
  163.   if t = '' then
  164.     Exit;
  165.   if Length(t) > 3 then
  166.     Exit;
  167.   e3 := StrToIntDef(t, 0);
  168.   FEnhCode1 := e1;
  169.   FEnhCode2 := e2;
  170.   FEnhCode3 := e3;
  171. end;
  172.  
  173. function TSMTPSend.ReadResult: Integer;
  174. var
  175.   s: string;
  176. begin
  177.   Result := 0;
  178.   FFullResult.Clear;
  179.   repeat
  180.     s := FSock.RecvString(FTimeout);
  181.     FResultString := s;
  182.     FFullResult.Add(s);
  183.     if FSock.LastError <> 0 then
  184.       Break;
  185.   until Pos('-', s) <> 4;
  186.   s := FFullResult[0];
  187.   if Length(s) >= 3 then
  188.     Result := StrToIntDef(Copy(s, 1, 3), 0);
  189.   FResultCode := Result;
  190.   EnhancedCode(s);
  191. end;
  192.  
  193. function TSMTPSend.AuthLogin: Boolean;
  194. begin
  195.   Result := False;
  196.   FSock.SendString('AUTH LOGIN' + CRLF);
  197.   if ReadResult <> 334 then
  198.     Exit;
  199.   FSock.SendString(EncodeBase64(FUsername) + CRLF);
  200.   if ReadResult <> 334 then
  201.     Exit;
  202.   FSock.SendString(EncodeBase64(FPassword) + CRLF);
  203.   Result := ReadResult = 235;
  204. end;
  205.  
  206. function TSMTPSend.AuthCram: Boolean;
  207. var
  208.   s: string;
  209. begin
  210.   Result := False;
  211.   FSock.SendString('AUTH CRAM-MD5' + CRLF);
  212.   if ReadResult <> 334 then
  213.     Exit;
  214.   s := Copy(FResultString, 5, Length(FResultString) - 4);
  215.   s := DecodeBase64(s);
  216.   s := HMAC_MD5(s, FPassword);
  217.   s := FUsername + ' ' + StrToHex(s);
  218.   FSock.SendString(EncodeBase64(s) + CRLF);
  219.   Result := ReadResult = 235;
  220. end;
  221.  
  222. function TSMTPSend.Connect: Boolean;
  223. begin
  224.   FSock.CloseSocket;
  225.   FSock.CreateSocket;
  226.   FSock.Connect(FSMTPHost, FSMTPPort);
  227.   Result := FSock.LastError = 0;
  228. end;
  229.  
  230. function TSMTPSend.Helo: Boolean;
  231. var
  232.   x: Integer;
  233. begin
  234.   FSock.SendString('HELO ' + FSystemName + CRLF);
  235.   x := ReadResult;
  236.   Result := (x >= 250) and (x <= 259);
  237. end;
  238.  
  239. function TSMTPSend.Ehlo: Boolean;
  240. var
  241.   x: Integer;
  242. begin
  243.   FSock.SendString('EHLO ' + FSystemName + CRLF);
  244.   x := ReadResult;
  245.   Result := (x >= 250) and (x <= 259);
  246. end;
  247.  
  248. function TSMTPSend.Login: Boolean;
  249. var
  250.   n: Integer;
  251.   auths: string;
  252.   s: string;
  253. begin
  254.   Result := False;
  255.   FESMTP := True;
  256.   FAuthDone := False;
  257.   FESMTPcap.clear;
  258.   FESMTPSize := False;
  259.   FMaxSize := 0;
  260.   if not Connect then
  261.     Exit;
  262.   if ReadResult <> 220 then
  263.     Exit;
  264.   if not Ehlo then
  265.   begin
  266.     FESMTP := False;
  267.     if not Helo then
  268.       Exit;
  269.   end;
  270.   Result := True;
  271.   if FESMTP then
  272.   begin
  273.     for n := 1 to FFullResult.Count - 1 do
  274.       FESMTPcap.Add(Copy(FFullResult[n], 5, Length(FFullResult[n]) - 4));
  275.     if not ((FUsername = '') and (FPassword = '')) then
  276.     begin
  277.       s := FindCap('AUTH ');
  278.       if s = '' then
  279.         s := FindCap('AUTH=');
  280.       auths := UpperCase(s);
  281.       if s <> '' then
  282.       begin
  283.         if Pos('CRAM-MD5', auths) > 0 then
  284.           FAuthDone := AuthCram;
  285.         if (Pos('LOGIN', auths) > 0) and (not FauthDone) then
  286.           FAuthDone := AuthLogin;
  287.       end;
  288.       if FAuthDone then
  289.         Ehlo;
  290.     end;
  291.     s := FindCap('SIZE');
  292.     if s <> '' then
  293.     begin
  294.       FESMTPsize := True;
  295.       FMaxSize := StrToIntDef(Copy(s, 6, Length(s) - 5), 0);
  296.     end;
  297.   end;
  298. end;
  299.  
  300. procedure TSMTPSend.Logout;
  301. begin
  302.   FSock.SendString('QUIT' + CRLF);
  303.   ReadResult;
  304.   FSock.CloseSocket;
  305. end;
  306.  
  307. function TSMTPSend.Reset: Boolean;
  308. begin
  309.   FSock.SendString('RSET' + CRLF);
  310.   Result := ReadResult = 250;
  311. end;
  312.  
  313. function TSMTPSend.NoOp: Boolean;
  314. begin
  315.   FSock.SendString('NOOP' + CRLF);
  316.   Result := ReadResult = 250;
  317. end;
  318.  
  319. function TSMTPSend.MailFrom(const Value: string; Size: Integer): Boolean;
  320. var
  321.   s: string;
  322. begin
  323.   s := 'MAIL FROM:<' + Value + '>';
  324.   if FESMTPsize and (Size > 0) then
  325.     s := s + ' SIZE=' + IntToStr(Size);
  326.   FSock.SendString(s + CRLF);
  327.   Result := ReadResult = 250;
  328. end;
  329.  
  330. function TSMTPSend.MailTo(const Value: string): Boolean;
  331. begin
  332.   FSock.SendString('RCPT TO:<' + Value + '>' + CRLF);
  333.   Result := ReadResult = 250;
  334. end;
  335.  
  336. function TSMTPSend.MailData(const Value: TStrings): Boolean;
  337. var
  338.   n: Integer;
  339.   s: string;
  340. begin
  341.   Result := False;
  342.   FSock.SendString('DATA' + CRLF);
  343.   if ReadResult <> 354 then
  344.     Exit;
  345.   for n := 0 to Value.Count - 1 do
  346.   begin
  347.     s := Value[n];
  348.     if Length(s) >= 1 then
  349.       if s[1] = '.' then
  350.         s := '.' + s;
  351.     FSock.SendString(s + CRLF);
  352.   end;
  353.   FSock.SendString('.' + CRLF);
  354.   Result := ReadResult = 250;
  355. end;
  356.  
  357. function TSMTPSend.Etrn(const Value: string): Boolean;
  358. var
  359.   x: Integer;
  360. begin
  361.   FSock.SendString('ETRN ' + Value + CRLF);
  362.   x := ReadResult;
  363.   Result := (x >= 250) and (x <= 259);
  364. end;
  365.  
  366. function TSMTPSend.Verify(const Value: string): Boolean;
  367. var
  368.   x: Integer;
  369. begin
  370.   FSock.SendString('VRFY ' + Value + CRLF);
  371.   x := ReadResult;
  372.   Result := (x >= 250) and (x <= 259);
  373. end;
  374.  
  375. function TSMTPSend.EnhCodeString: string;
  376. var
  377.   s, t: string;
  378. begin
  379.   s := IntToStr(FEnhCode2) + '.' + IntToStr(FEnhCode3);
  380.   t := '';
  381.   if s = '0.0' then t := 'Other undefined Status';
  382.   if s = '1.0' then t := 'Other address status';
  383.   if s = '1.1' then t := 'Bad destination mailbox address';
  384.   if s = '1.2' then t := 'Bad destination system address';
  385.   if s = '1.3' then t := 'Bad destination mailbox address syntax';
  386.   if s = '1.4' then t := 'Destination mailbox address ambiguous';
  387.   if s = '1.5' then t := 'Destination mailbox address valid';
  388.   if s = '1.6' then t := 'Mailbox has moved';
  389.   if s = '1.7' then t := 'Bad sender''s mailbox address syntax';
  390.   if s = '1.8' then t := 'Bad sender''s system address';
  391.   if s = '2.0' then t := 'Other or undefined mailbox status';
  392.   if s = '2.1' then t := 'Mailbox disabled, not accepting messages';
  393.   if s = '2.2' then t := 'Mailbox full';
  394.   if s = '2.3' then t := 'Message Length exceeds administrative limit';
  395.   if s = '2.4' then t := 'Mailing list expansion problem';
  396.   if s = '3.0' then t := 'Other or undefined mail system status';
  397.   if s = '3.1' then t := 'Mail system full';
  398.   if s = '3.2' then t := 'System not accepting network messages';
  399.   if s = '3.3' then t := 'System not capable of selected features';
  400.   if s = '3.4' then t := 'Message too big for system';
  401.   if s = '3.5' then t := 'System incorrectly configured';
  402.   if s = '4.0' then t := 'Other or undefined network or routing status';
  403.   if s = '4.1' then t := 'No answer from host';
  404.   if s = '4.2' then t := 'Bad connection';
  405.   if s = '4.3' then t := 'Routing server failure';
  406.   if s = '4.4' then t := 'Unable to route';
  407.   if s = '4.5' then t := 'Network congestion';
  408.   if s = '4.6' then t := 'Routing loop detected';
  409.   if s = '4.7' then t := 'Delivery time expired';
  410.   if s = '5.0' then t := 'Other or undefined protocol status';
  411.   if s = '5.1' then t := 'Invalid command';
  412.   if s = '5.2' then t := 'Syntax error';
  413.   if s = '5.3' then t := 'Too many recipients';
  414.   if s = '5.4' then t := 'Invalid command arguments';
  415.   if s = '5.5' then t := 'Wrong protocol version';
  416.   if s = '6.0' then t := 'Other or undefined media error';
  417.   if s = '6.1' then t := 'Media not supported';
  418.   if s = '6.2' then t := 'Conversion required and prohibited';
  419.   if s = '6.3' then t := 'Conversion required but not supported';
  420.   if s = '6.4' then t := 'Conversion with loss performed';
  421.   if s = '6.5' then t := 'Conversion failed';
  422.   if s = '7.0' then t := 'Other or undefined security status';
  423.   if s = '7.1' then t := 'Delivery not authorized, message refused';
  424.   if s = '7.2' then t := 'Mailing list expansion prohibited';
  425.   if s = '7.3' then t := 'Security conversion required but not possible';
  426.   if s = '7.4' then t := 'Security features not supported';
  427.   if s = '7.5' then t := 'Cryptographic failure';
  428.   if s = '7.6' then t := 'Cryptographic algorithm not supported';
  429.   if s = '7.7' then t := 'Message integrity failure';
  430.   s := '???-';
  431.   if FEnhCode1 = 2 then s := 'Success-';
  432.   if FEnhCode1 = 4 then s := 'Persistent Transient Failure-';
  433.   if FEnhCode1 = 5 then s := 'Permanent Failure-';
  434.   Result := s + t;
  435. end;
  436.  
  437. function TSMTPSend.FindCap(const Value: string): string;
  438. var
  439.   n: Integer;
  440.   s: string;
  441. begin
  442.   s := UpperCase(Value);
  443.   Result := '';
  444.   for n := 0 to FESMTPcap.Count - 1 do
  445.     if Pos(s, UpperCase(FESMTPcap[n])) = 1 then
  446.     begin
  447.       Result := FESMTPcap[n];
  448.       Break;
  449.     end;
  450. end;
  451.  
  452. {==============================================================================}
  453.  
  454. function SendToRaw(const MailFrom, MailTo, SMTPHost: string;
  455.   const MailData: TStrings; const Username, Password: string): Boolean;
  456. var
  457.   SMTP: TSMTPSend;
  458. begin
  459.   Result := False;
  460.   SMTP := TSMTPSend.Create;
  461.   try
  462.     SMTP.SMTPHost := SMTPHost;
  463.     SMTP.Username := Username;
  464.     SMTP.Password := Password;
  465.     if SMTP.Login then
  466.     begin
  467.       if SMTP.MailFrom(MailFrom, Length(MailData.Text)) then
  468.         if SMTP.MailTo(MailTo) then
  469.           if SMTP.MailData(MailData) then
  470.             Result := True;
  471.       SMTP.Logout;
  472.     end;
  473.   finally
  474.     SMTP.Free;
  475.   end;
  476. end;
  477.  
  478. function SendToEx(const MailFrom, MailTo, Subject, SMTPHost: string;
  479.   const MailData: TStrings; const Username, Password: string): Boolean;
  480. var
  481.   t: TStrings;
  482. begin
  483.   t := TStringList.Create;
  484.   try
  485.     t.Assign(MailData);
  486.     t.Insert(0, '');
  487.     t.Insert(0, 'x-mailer: Synapse - Delphi TCP/IP library by Lukas Gebauer');
  488.     t.Insert(0, 'subject: ' + Subject);
  489.     t.Insert(0, 'date: ' + Rfc822DateTime(now));
  490.     t.Insert(0, 'to: ' + MailTo);
  491.     t.Insert(0, 'from: ' + MailFrom);
  492.     Result := SendToRaw(MailFrom, MailTo, SMTPHost, t, Username, Password);
  493.   finally
  494.     t.Free;
  495.   end;
  496. end;
  497.  
  498. function SendTo(const MailFrom, MailTo, Subject, SMTPHost: string;
  499.   const MailData: TStrings): Boolean;
  500. begin
  501.   Result := SendToEx(MailFrom, MailTo, Subject, SMTPHost, MailData, '', '');
  502. end;
  503.  
  504. end.
  505.