IdTestSMTPServer.pas 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. unit IdTestSMTPServer;
  2. //odd: TIdCommandHandler.DoCommand: Response.Assign(Self.Response);
  3. interface
  4. uses
  5. IdGlobal,
  6. IdReplySMTP,
  7. IdTCPClient,
  8. IdSMTPServer,
  9. IdMessage,
  10. IdObjs,
  11. IdSMTP,
  12. IdSys,
  13. IdLogDebug,
  14. IdTest;
  15. type
  16. TIdTestSMTPServer = class(TIdTest)
  17. private
  18. FReceivedMsg:TIdMessage;
  19. FServer:TIdSMTPServer;
  20. FClient:TIdSMTP;
  21. FDebug:TIdLogDebug;
  22. //replace setup/teardown with virtuals
  23. procedure mySetup;
  24. procedure myTearDown;
  25. procedure CallbackRcptTo(ASender: TIdSMTPServerContext; const AAddress : string;
  26. var VAction : TIdRCPToReply; var VForward : string);
  27. procedure CallbackMsgReceive(ASender: TIdSMTPServerContext; AMsg : TIdStream;var LAction : TIdDataReply);
  28. procedure CallbackMailFrom(ASender: TIdSMTPServerContext; const AAddress : string;
  29. var VAction : TIdMailFromReply);
  30. published
  31. procedure TestGreeting;
  32. procedure TestReceive;
  33. procedure TestReject;
  34. end;
  35. implementation
  36. const
  37. cTestPort=20202;
  38. cSpammerAddress='[email protected]';
  39. procedure TIdTestSMTPServer.mySetup;
  40. begin
  41. Assert(FReceivedMsg=nil);
  42. FReceivedMsg:=TIdMessage.Create(nil);
  43. Assert(FServer=nil);
  44. FServer:=TIdSMTPServer.Create(nil);
  45. FServer.OnMsgReceive:=CallbackMsgReceive;
  46. FServer.OnRcptTo:=CallbackRcptTo;
  47. FServer.OnMailFrom:=CallbackMailFrom;
  48. FServer.DefaultPort:=cTestPort;
  49. FDebug:=TIdLogDebug.Create;
  50. Assert(FClient=nil);
  51. FClient:=TIdSMTP.Create(nil);
  52. FClient.ReadTimeout:=5000;
  53. FClient.Port:=cTestPort;
  54. FClient.Host:='127.0.0.1';
  55. FClient.CreateIOHandler;
  56. FClient.IOHandler.Intercept := FDebug;
  57. FDebug.Active := True;
  58. end;
  59. procedure TIdTestSMTPServer.myTearDown;
  60. begin
  61. FDebug.Active := False;
  62. Sys.FreeAndNil(FDebug);
  63. Sys.FreeAndNil(FClient);
  64. Sys.FreeAndNil(FServer);
  65. Sys.FreeAndNil(FReceivedMsg);
  66. end;
  67. procedure TIdTestSMTPServer.CallbackMailFrom(ASender: TIdSMTPServerContext;
  68. const AAddress: string; var VAction: TIdMailFromReply);
  69. begin
  70. if AAddress=cSpammerAddress then
  71. begin
  72. VAction:=mReject;
  73. end;
  74. end;
  75. procedure TIdTestSMTPServer.CallbackMsgReceive(
  76. ASender: TIdSMTPServerContext; AMsg: TIdStream;
  77. var LAction: TIdDataReply);
  78. var
  79. aList:TIdStringList;
  80. begin
  81. //do a precheck here.
  82. aList:=TIdStringList.Create;
  83. try
  84. AMsg.Position:=0;
  85. aList.Text:=ReadStringFromStream(AMsg);
  86. //should be at least headers for: received from subject to date
  87. //if this fails, then client hasn't written correctly, or server hasn't read
  88. Assert(aList.Count>=5);
  89. finally
  90. sys.FreeAndNil(aList);
  91. end;
  92. AMsg.Position:=0;
  93. FReceivedMsg.LoadFromStream(AMsg);
  94. end;
  95. procedure TIdTestSMTPServer.CallbackRcptTo(ASender: TIdSMTPServerContext;
  96. const AAddress: string; var VAction: TIdRCPToReply;
  97. var VForward: string);
  98. begin
  99. VAction:=rAddressOk;
  100. end;
  101. procedure TIdTestSMTPServer.TestGreeting;
  102. //checks that the server returns a correct greeting
  103. //uses tcpclient to check directly
  104. var
  105. s:string;
  106. aClient:TIdTCPClient;
  107. const
  108. cGreeting='HELLO';
  109. begin
  110. aClient:=TIdTCPClient.Create(nil);
  111. try
  112. mySetup;
  113. //Set a specific greeting, makes easy to test
  114. (FServer.Greeting as TIdReplySMTP).SetEnhReply(220, '' ,cGreeting);
  115. FServer.Active:=True;
  116. aClient.Port:=cTestPort;
  117. aClient.Host:='127.0.0.1';
  118. aClient.ReadTimeout:=5000;
  119. aClient.Connect;
  120. s:=aClient.IOHandler.Readln;
  121. //real example '220 mail.example.com ESMTP'
  122. Assert(s='220 '+cGreeting);
  123. aClient.Disconnect;
  124. finally
  125. Sys.FreeAndNil(aClient);
  126. myTearDown;
  127. end;
  128. end;
  129. procedure TIdTestSMTPServer.TestReceive;
  130. //do a round-trip message send using smtp client and server
  131. //repeat with/without client pipelining?
  132. var
  133. aMessage:TIdMessage;
  134. const
  135. cFrom='[email protected]';
  136. cSubject='mysubject';
  137. cBody='1,2,3';
  138. cAddress='[email protected]';
  139. cPriority:TIdMessagePriority=mpHigh;
  140. begin
  141. try
  142. mySetup;
  143. FServer.Active:=True;
  144. FClient.Connect;
  145. aMessage := TIdMessage.Create(nil);
  146. try
  147. aMessage.From.Address := cFrom;
  148. aMessage.Subject := cSubject;
  149. aMessage.Body.CommaText := cBody;
  150. //test with multiple recipients
  151. aMessage.Recipients.Add.Address := cAddress;
  152. aMessage.Priority :=cPriority;
  153. aMessage.Encoding := mePlaintext;
  154. FClient.Send(aMessage);
  155. finally
  156. Sys.FreeAndNil(aMessage);
  157. end;
  158. Assert(FClient.LastCmdResult.NumericCode =250, 'Code:' + Sys.IntToStr(FClient.LastCmdResult.NumericCode));
  159. //check that what the server received is same as sent
  160. Assert(FReceivedMsg.From.Address = cFrom, 'From:' + FReceivedMsg.From.Address);
  161. Assert(FReceivedMsg.Subject = cSubject, 'Subject:' + FReceivedMsg.Subject);
  162. Assert(FReceivedMsg.Body.CommaText = cBody, 'Body:' + FReceivedMsg.Body.CommaText);
  163. Assert(FReceivedMsg.Recipients.EMailAddresses = cAddress, 'To:' + FReceivedMsg.Recipients.EMailAddresses);
  164. Assert(FReceivedMsg.Priority = cPriority, 'Priority');
  165. //also check the "Received:" header
  166. //also check attachments
  167. //currently breaks due to ioHandler rev26
  168. finally
  169. myTearDown;
  170. end;
  171. end;
  172. procedure TIdTestSMTPServer.TestReject;
  173. //check that if a message is rejected by server, (here using OnMailFrom)
  174. //the correct status is returned.
  175. var
  176. aMessage:TIdMessage;
  177. begin
  178. try
  179. mySetup;
  180. FServer.Active:=True;
  181. FClient.Connect;
  182. aMessage:=TIdMessage.Create(nil);
  183. try
  184. aMessage.From.Address:=cSpammerAddress;
  185. aMessage.Subject:='spam';
  186. aMessage.Body.CommaText:='spam';
  187. aMessage.Recipients.Add.Address:='[email protected]';
  188. try
  189. FClient.Send(aMessage);
  190. except
  191. //want to ignore the exception here
  192. //EIdSMTPReplyError
  193. //check class,content
  194. on E : Exception do
  195. begin
  196. //You can NOT do:
  197. //
  198. //Assert(FClient.LastCmdResult.NumericCode = 550, FClient.LastCmdResult.FormattedReply.Text);
  199. //
  200. //because the exception may be from a line in a pipelined sequence and
  201. //LastCmdResult probably contains the result from the last command in the pipelined
  202. //sequence
  203. if E is EIdSMTPReplyError then
  204. begin
  205. with (E as EIdSMTPReplyError) do
  206. begin
  207. Assert( (E as EIdSMTPReplyError).ErrorCode = 550, (E as EIdSMTPReplyError).Message);
  208. end;
  209. end;
  210. end;
  211. end;
  212. finally
  213. Sys.FreeAndNil(aMessage);
  214. end;
  215. finally
  216. myTearDown;
  217. end;
  218. end;
  219. initialization
  220. TIdTest.RegisterTest(TIdTestSMTPServer);
  221. end.