class.smtp.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. <?php
  2. /*~ class.smtp.php
  3. .---------------------------------------------------------------------------.
  4. | Software: PHPMailer - PHP email class |
  5. | Version: 5.2.2-beta1 |
  6. | Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
  7. | ------------------------------------------------------------------------- |
  8. | Admin: Jim Jagielski (project admininistrator) |
  9. | Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
  10. | : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
  11. | : Jim Jagielski (jimjag) jimjag@gmail.com |
  12. | Founder: Brent R. Matzelle (original founder) |
  13. | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
  14. | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
  15. | Copyright (c) 2001-2003, Brent R. Matzelle |
  16. | ------------------------------------------------------------------------- |
  17. | License: Distributed under the Lesser General Public License (LGPL) |
  18. | http://www.gnu.org/copyleft/lesser.html |
  19. | This program is distributed in the hope that it will be useful - WITHOUT |
  20. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
  21. | FITNESS FOR A PARTICULAR PURPOSE. |
  22. '---------------------------------------------------------------------------'
  23. */
  24. /**
  25. * PHPMailer - PHP SMTP email transport class
  26. * NOTE: Designed for use with PHP version 5 and up
  27. * @package PHPMailer
  28. * @author Andy Prevost
  29. * @author Marcus Bointon
  30. * @copyright 2004 - 2008 Andy Prevost
  31. * @author Jim Jagielski
  32. * @copyright 2010 - 2012 Jim Jagielski
  33. * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
  34. */
  35. /**
  36. * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
  37. * commands except TURN which will always return a not implemented
  38. * error. SMTP also provides some utility methods for sending mail
  39. * to an SMTP server.
  40. * original author: Chris Ryan
  41. */
  42. class SMTP {
  43. /**
  44. * SMTP server port
  45. * @var int
  46. */
  47. public $SMTP_PORT = 25;
  48. /**
  49. * SMTP reply line ending
  50. * @var string
  51. */
  52. public $CRLF = "\r\n";
  53. /**
  54. * Sets whether debugging is turned on
  55. * @var bool
  56. */
  57. public $do_debug; // the level of debug to perform
  58. /**
  59. * Sets the function/method to use for debugging output.
  60. * Right now we only honor "echo" or "error_log"
  61. * @var string
  62. */
  63. public $Debugoutput = "echo";
  64. /**
  65. * Sets VERP use on/off (default is off)
  66. * @var bool
  67. */
  68. public $do_verp = false;
  69. /**
  70. * Sets the SMTP timeout value for reads, in seconds
  71. * @var int
  72. */
  73. public $Timeout = 15;
  74. /**
  75. * Sets the SMTP timelimit value for reads, in seconds
  76. * @var int
  77. */
  78. public $Timelimit = 30;
  79. /**
  80. * Sets the SMTP PHPMailer Version number
  81. * @var string
  82. */
  83. public $Version = '5.2.2-beta1';
  84. /////////////////////////////////////////////////
  85. // PROPERTIES, PRIVATE AND PROTECTED
  86. /////////////////////////////////////////////////
  87. private $smtp_conn; // the socket to the server
  88. private $error; // error if any on the last call
  89. private $helo_rply; // the reply the server sent to us for HELO
  90. /**
  91. * Outputs debugging info via user-defined method
  92. * @param string $str
  93. */
  94. private function edebug($str) {
  95. if ($this->Debugoutput == "error_log") {
  96. error_log($str);
  97. } else {
  98. echo $str;
  99. }
  100. }
  101. /**
  102. * Initialize the class so that the data is in a known state.
  103. * @access public
  104. * @return void
  105. */
  106. public function __construct() {
  107. $this->smtp_conn = 0;
  108. $this->error = null;
  109. $this->helo_rply = null;
  110. $this->do_debug = 0;
  111. }
  112. /////////////////////////////////////////////////
  113. // CONNECTION FUNCTIONS
  114. /////////////////////////////////////////////////
  115. /**
  116. * Connect to the server specified on the port specified.
  117. * If the port is not specified use the default SMTP_PORT.
  118. * If tval is specified then a connection will try and be
  119. * established with the server for that number of seconds.
  120. * If tval is not specified the default is 30 seconds to
  121. * try on the connection.
  122. *
  123. * SMTP CODE SUCCESS: 220
  124. * SMTP CODE FAILURE: 421
  125. * @access public
  126. * @return bool
  127. */
  128. public function Connect($host, $port = 0, $tval = 30) {
  129. // set the error val to null so there is no confusion
  130. $this->error = null;
  131. // make sure we are __not__ connected
  132. if($this->connected()) {
  133. // already connected, generate error
  134. $this->error = array("error" => "Already connected to a server");
  135. return false;
  136. }
  137. if(empty($port)) {
  138. $port = $this->SMTP_PORT;
  139. }
  140. // connect to the smtp server
  141. $this->smtp_conn = @fsockopen($host, // the host of the server
  142. $port, // the port to use
  143. $errno, // error number if any
  144. $errstr, // error message if any
  145. $tval); // give up after ? secs
  146. // verify we connected properly
  147. if(empty($this->smtp_conn)) {
  148. $this->error = array("error" => "Failed to connect to server",
  149. "errno" => $errno,
  150. "errstr" => $errstr);
  151. if($this->do_debug >= 1) {
  152. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />');
  153. }
  154. return false;
  155. }
  156. // SMTP server can take longer to respond, give longer timeout for first read
  157. // Windows does not have support for this timeout function
  158. if(substr(PHP_OS, 0, 3) != "WIN") {
  159. $max = ini_get('max_execution_time');
  160. if ($max != 0 && $tval > $max) { // don't bother if unlimited
  161. @set_time_limit($tval);
  162. }
  163. stream_set_timeout($this->smtp_conn, $tval, 0);
  164. }
  165. // get any announcement
  166. $announce = $this->get_lines();
  167. if($this->do_debug >= 2) {
  168. $this->edebug("SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />');
  169. }
  170. return true;
  171. }
  172. /**
  173. * Initiate a TLS communication with the server.
  174. *
  175. * SMTP CODE 220 Ready to start TLS
  176. * SMTP CODE 501 Syntax error (no parameters allowed)
  177. * SMTP CODE 454 TLS not available due to temporary reason
  178. * @access public
  179. * @return bool success
  180. */
  181. public function StartTLS() {
  182. $this->error = null; # to avoid confusion
  183. if(!$this->connected()) {
  184. $this->error = array("error" => "Called StartTLS() without being connected");
  185. return false;
  186. }
  187. fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
  188. $rply = $this->get_lines();
  189. $code = substr($rply,0,3);
  190. if($this->do_debug >= 2) {
  191. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  192. }
  193. if($code != 220) {
  194. $this->error =
  195. array("error" => "STARTTLS not accepted from server",
  196. "smtp_code" => $code,
  197. "smtp_msg" => substr($rply,4));
  198. if($this->do_debug >= 1) {
  199. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  200. }
  201. return false;
  202. }
  203. // Begin encrypted connection
  204. if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
  205. return false;
  206. }
  207. return true;
  208. }
  209. /**
  210. * Performs SMTP authentication. Must be run after running the
  211. * Hello() method. Returns true if successfully authenticated.
  212. * @access public
  213. * @return bool
  214. */
  215. public function Authenticate($username, $password, $authtype='LOGIN', $realm='',
  216. $workstation='') {
  217. if (empty($authtype)) {
  218. $authtype = 'LOGIN';
  219. }
  220. switch ($authtype) {
  221. case 'LOGIN':
  222. // Start authentication
  223. fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
  224. $rply = $this->get_lines();
  225. $code = substr($rply,0,3);
  226. if($code != 334) {
  227. $this->error =
  228. array("error" => "AUTH not accepted from server",
  229. "smtp_code" => $code,
  230. "smtp_msg" => substr($rply,4));
  231. if($this->do_debug >= 1) {
  232. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  233. }
  234. return false;
  235. }
  236. // Send encoded username
  237. fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
  238. $rply = $this->get_lines();
  239. $code = substr($rply,0,3);
  240. if($code != 334) {
  241. $this->error =
  242. array("error" => "Username not accepted from server",
  243. "smtp_code" => $code,
  244. "smtp_msg" => substr($rply,4));
  245. if($this->do_debug >= 1) {
  246. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  247. }
  248. return false;
  249. }
  250. // Send encoded password
  251. fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
  252. $rply = $this->get_lines();
  253. $code = substr($rply,0,3);
  254. if($code != 235) {
  255. $this->error =
  256. array("error" => "Password not accepted from server",
  257. "smtp_code" => $code,
  258. "smtp_msg" => substr($rply,4));
  259. if($this->do_debug >= 1) {
  260. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  261. }
  262. return false;
  263. }
  264. break;
  265. case 'NTLM':
  266. /*
  267. * ntlm_sasl_client.php
  268. ** Bundled with Permission
  269. **
  270. ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
  271. ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
  272. */
  273. require_once('ntlm_sasl_client.php');
  274. $temp = new stdClass();
  275. $ntlm_client = new ntlm_sasl_client_class;
  276. if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
  277. $this->error = array("error" => $temp->error);
  278. if($this->do_debug >= 1) {
  279. $this->edebug("You need to enable some modules in your php.ini file: " . $this->error["error"] . $this->CRLF);
  280. }
  281. return false;
  282. }
  283. $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
  284. fputs($this->smtp_conn,"AUTH NTLM " . base64_encode($msg1) . $this->CRLF);
  285. $rply = $this->get_lines();
  286. $code = substr($rply,0,3);
  287. if($code != 334) {
  288. $this->error =
  289. array("error" => "AUTH not accepted from server",
  290. "smtp_code" => $code,
  291. "smtp_msg" => substr($rply,4));
  292. if($this->do_debug >= 1) {
  293. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
  294. }
  295. return false;
  296. }
  297. $challange = substr($rply,3);//though 0 based, there is a white space after the 3 digit number....//msg2
  298. $challange = base64_decode($challange);
  299. $ntlm_res = $ntlm_client->NTLMResponse(substr($challange,24,8),$password);
  300. $msg3 = $ntlm_client->TypeMsg3($ntlm_res,$username,$realm,$workstation);//msg3
  301. // Send encoded username
  302. fputs($this->smtp_conn, base64_encode($msg3) . $this->CRLF);
  303. $rply = $this->get_lines();
  304. $code = substr($rply,0,3);
  305. if($code != 235) {
  306. $this->error =
  307. array("error" => "Could not authenticate",
  308. "smtp_code" => $code,
  309. "smtp_msg" => substr($rply,4));
  310. if($this->do_debug >= 1) {
  311. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF);
  312. }
  313. return false;
  314. }
  315. break;
  316. }
  317. return true;
  318. }
  319. /**
  320. * Returns true if connected to a server otherwise false
  321. * @access public
  322. * @return bool
  323. */
  324. public function Connected() {
  325. if(!empty($this->smtp_conn)) {
  326. $sock_status = socket_get_status($this->smtp_conn);
  327. if($sock_status["eof"]) {
  328. // the socket is valid but we are not connected
  329. if($this->do_debug >= 1) {
  330. $this->edebug("SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected");
  331. }
  332. $this->Close();
  333. return false;
  334. }
  335. return true; // everything looks good
  336. }
  337. return false;
  338. }
  339. /**
  340. * Closes the socket and cleans up the state of the class.
  341. * It is not considered good to use this function without
  342. * first trying to use QUIT.
  343. * @access public
  344. * @return void
  345. */
  346. public function Close() {
  347. $this->error = null; // so there is no confusion
  348. $this->helo_rply = null;
  349. if(!empty($this->smtp_conn)) {
  350. // close the connection and cleanup
  351. fclose($this->smtp_conn);
  352. $this->smtp_conn = 0;
  353. }
  354. }
  355. /////////////////////////////////////////////////
  356. // SMTP COMMANDS
  357. /////////////////////////////////////////////////
  358. /**
  359. * Issues a data command and sends the msg_data to the server
  360. * finializing the mail transaction. $msg_data is the message
  361. * that is to be send with the headers. Each header needs to be
  362. * on a single line followed by a <CRLF> with the message headers
  363. * and the message body being seperated by and additional <CRLF>.
  364. *
  365. * Implements rfc 821: DATA <CRLF>
  366. *
  367. * SMTP CODE INTERMEDIATE: 354
  368. * [data]
  369. * <CRLF>.<CRLF>
  370. * SMTP CODE SUCCESS: 250
  371. * SMTP CODE FAILURE: 552,554,451,452
  372. * SMTP CODE FAILURE: 451,554
  373. * SMTP CODE ERROR : 500,501,503,421
  374. * @access public
  375. * @return bool
  376. */
  377. public function Data($msg_data) {
  378. $this->error = null; // so no confusion is caused
  379. if(!$this->connected()) {
  380. $this->error = array(
  381. "error" => "Called Data() without being connected");
  382. return false;
  383. }
  384. fputs($this->smtp_conn,"DATA" . $this->CRLF);
  385. $rply = $this->get_lines();
  386. $code = substr($rply,0,3);
  387. if($this->do_debug >= 2) {
  388. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  389. }
  390. if($code != 354) {
  391. $this->error =
  392. array("error" => "DATA command not accepted from server",
  393. "smtp_code" => $code,
  394. "smtp_msg" => substr($rply,4));
  395. if($this->do_debug >= 1) {
  396. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  397. }
  398. return false;
  399. }
  400. /* the server is ready to accept data!
  401. * according to rfc 821 we should not send more than 1000
  402. * including the CRLF
  403. * characters on a single line so we will break the data up
  404. * into lines by \r and/or \n then if needed we will break
  405. * each of those into smaller lines to fit within the limit.
  406. * in addition we will be looking for lines that start with
  407. * a period '.' and append and additional period '.' to that
  408. * line. NOTE: this does not count towards limit.
  409. */
  410. // normalize the line breaks so we know the explode works
  411. $msg_data = str_replace("\r\n","\n",$msg_data);
  412. $msg_data = str_replace("\r","\n",$msg_data);
  413. $lines = explode("\n",$msg_data);
  414. /* we need to find a good way to determine is headers are
  415. * in the msg_data or if it is a straight msg body
  416. * currently I am assuming rfc 822 definitions of msg headers
  417. * and if the first field of the first line (':' sperated)
  418. * does not contain a space then it _should_ be a header
  419. * and we can process all lines before a blank "" line as
  420. * headers.
  421. */
  422. $field = substr($lines[0],0,strpos($lines[0],":"));
  423. $in_headers = false;
  424. if(!empty($field) && !strstr($field," ")) {
  425. $in_headers = true;
  426. }
  427. $max_line_length = 998; // used below; set here for ease in change
  428. while(list(,$line) = @each($lines)) {
  429. $lines_out = null;
  430. if($line == "" && $in_headers) {
  431. $in_headers = false;
  432. }
  433. // ok we need to break this line up into several smaller lines
  434. while(strlen($line) > $max_line_length) {
  435. $pos = strrpos(substr($line,0,$max_line_length)," ");
  436. // Patch to fix DOS attack
  437. if(!$pos) {
  438. $pos = $max_line_length - 1;
  439. $lines_out[] = substr($line,0,$pos);
  440. $line = substr($line,$pos);
  441. } else {
  442. $lines_out[] = substr($line,0,$pos);
  443. $line = substr($line,$pos + 1);
  444. }
  445. /* if processing headers add a LWSP-char to the front of new line
  446. * rfc 822 on long msg headers
  447. */
  448. if($in_headers) {
  449. $line = "\t" . $line;
  450. }
  451. }
  452. $lines_out[] = $line;
  453. // send the lines to the server
  454. while(list(,$line_out) = @each($lines_out)) {
  455. if(strlen($line_out) > 0)
  456. {
  457. if(substr($line_out, 0, 1) == ".") {
  458. $line_out = "." . $line_out;
  459. }
  460. }
  461. fputs($this->smtp_conn,$line_out . $this->CRLF);
  462. }
  463. }
  464. // message data has been sent
  465. fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
  466. $rply = $this->get_lines();
  467. $code = substr($rply,0,3);
  468. if($this->do_debug >= 2) {
  469. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  470. }
  471. if($code != 250) {
  472. $this->error =
  473. array("error" => "DATA not accepted from server",
  474. "smtp_code" => $code,
  475. "smtp_msg" => substr($rply,4));
  476. if($this->do_debug >= 1) {
  477. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  478. }
  479. return false;
  480. }
  481. return true;
  482. }
  483. /**
  484. * Sends the HELO command to the smtp server.
  485. * This makes sure that we and the server are in
  486. * the same known state.
  487. *
  488. * Implements from rfc 821: HELO <SP> <domain> <CRLF>
  489. *
  490. * SMTP CODE SUCCESS: 250
  491. * SMTP CODE ERROR : 500, 501, 504, 421
  492. * @access public
  493. * @return bool
  494. */
  495. public function Hello($host = '') {
  496. $this->error = null; // so no confusion is caused
  497. if(!$this->connected()) {
  498. $this->error = array(
  499. "error" => "Called Hello() without being connected");
  500. return false;
  501. }
  502. // if hostname for HELO was not specified send default
  503. if(empty($host)) {
  504. // determine appropriate default to send to server
  505. $host = "localhost";
  506. }
  507. // Send extended hello first (RFC 2821)
  508. if(!$this->SendHello("EHLO", $host)) {
  509. if(!$this->SendHello("HELO", $host)) {
  510. return false;
  511. }
  512. }
  513. return true;
  514. }
  515. /**
  516. * Sends a HELO/EHLO command.
  517. * @access private
  518. * @return bool
  519. */
  520. private function SendHello($hello, $host) {
  521. fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
  522. $rply = $this->get_lines();
  523. $code = substr($rply,0,3);
  524. if($this->do_debug >= 2) {
  525. $this->edebug("SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />');
  526. }
  527. if($code != 250) {
  528. $this->error =
  529. array("error" => $hello . " not accepted from server",
  530. "smtp_code" => $code,
  531. "smtp_msg" => substr($rply,4));
  532. if($this->do_debug >= 1) {
  533. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  534. }
  535. return false;
  536. }
  537. $this->helo_rply = $rply;
  538. return true;
  539. }
  540. /**
  541. * Starts a mail transaction from the email address specified in
  542. * $from. Returns true if successful or false otherwise. If True
  543. * the mail transaction is started and then one or more Recipient
  544. * commands may be called followed by a Data command.
  545. *
  546. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  547. *
  548. * SMTP CODE SUCCESS: 250
  549. * SMTP CODE SUCCESS: 552,451,452
  550. * SMTP CODE SUCCESS: 500,501,421
  551. * @access public
  552. * @return bool
  553. */
  554. public function Mail($from) {
  555. $this->error = null; // so no confusion is caused
  556. if(!$this->connected()) {
  557. $this->error = array(
  558. "error" => "Called Mail() without being connected");
  559. return false;
  560. }
  561. $useVerp = ($this->do_verp ? "XVERP" : "");
  562. fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
  563. $rply = $this->get_lines();
  564. $code = substr($rply,0,3);
  565. if($this->do_debug >= 2) {
  566. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  567. }
  568. if($code != 250) {
  569. $this->error =
  570. array("error" => "MAIL not accepted from server",
  571. "smtp_code" => $code,
  572. "smtp_msg" => substr($rply,4));
  573. if($this->do_debug >= 1) {
  574. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  575. }
  576. return false;
  577. }
  578. return true;
  579. }
  580. /**
  581. * Sends the quit command to the server and then closes the socket
  582. * if there is no error or the $close_on_error argument is true.
  583. *
  584. * Implements from rfc 821: QUIT <CRLF>
  585. *
  586. * SMTP CODE SUCCESS: 221
  587. * SMTP CODE ERROR : 500
  588. * @access public
  589. * @return bool
  590. */
  591. public function Quit($close_on_error = true) {
  592. $this->error = null; // so there is no confusion
  593. if(!$this->connected()) {
  594. $this->error = array(
  595. "error" => "Called Quit() without being connected");
  596. return false;
  597. }
  598. // send the quit command to the server
  599. fputs($this->smtp_conn,"quit" . $this->CRLF);
  600. // get any good-bye messages
  601. $byemsg = $this->get_lines();
  602. if($this->do_debug >= 2) {
  603. $this->edebug("SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />');
  604. }
  605. $rval = true;
  606. $e = null;
  607. $code = substr($byemsg,0,3);
  608. if($code != 221) {
  609. // use e as a tmp var cause Close will overwrite $this->error
  610. $e = array("error" => "SMTP server rejected quit command",
  611. "smtp_code" => $code,
  612. "smtp_rply" => substr($byemsg,4));
  613. $rval = false;
  614. if($this->do_debug >= 1) {
  615. $this->edebug("SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />');
  616. }
  617. }
  618. if(empty($e) || $close_on_error) {
  619. $this->Close();
  620. }
  621. return $rval;
  622. }
  623. /**
  624. * Sends the command RCPT to the SMTP server with the TO: argument of $to.
  625. * Returns true if the recipient was accepted false if it was rejected.
  626. *
  627. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  628. *
  629. * SMTP CODE SUCCESS: 250,251
  630. * SMTP CODE FAILURE: 550,551,552,553,450,451,452
  631. * SMTP CODE ERROR : 500,501,503,421
  632. * @access public
  633. * @return bool
  634. */
  635. public function Recipient($to) {
  636. $this->error = null; // so no confusion is caused
  637. if(!$this->connected()) {
  638. $this->error = array(
  639. "error" => "Called Recipient() without being connected");
  640. return false;
  641. }
  642. fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
  643. $rply = $this->get_lines();
  644. $code = substr($rply,0,3);
  645. if($this->do_debug >= 2) {
  646. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  647. }
  648. if($code != 250 && $code != 251) {
  649. $this->error =
  650. array("error" => "RCPT not accepted from server",
  651. "smtp_code" => $code,
  652. "smtp_msg" => substr($rply,4));
  653. if($this->do_debug >= 1) {
  654. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  655. }
  656. return false;
  657. }
  658. return true;
  659. }
  660. /**
  661. * Sends the RSET command to abort and transaction that is
  662. * currently in progress. Returns true if successful false
  663. * otherwise.
  664. *
  665. * Implements rfc 821: RSET <CRLF>
  666. *
  667. * SMTP CODE SUCCESS: 250
  668. * SMTP CODE ERROR : 500,501,504,421
  669. * @access public
  670. * @return bool
  671. */
  672. public function Reset() {
  673. $this->error = null; // so no confusion is caused
  674. if(!$this->connected()) {
  675. $this->error = array(
  676. "error" => "Called Reset() without being connected");
  677. return false;
  678. }
  679. fputs($this->smtp_conn,"RSET" . $this->CRLF);
  680. $rply = $this->get_lines();
  681. $code = substr($rply,0,3);
  682. if($this->do_debug >= 2) {
  683. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  684. }
  685. if($code != 250) {
  686. $this->error =
  687. array("error" => "RSET failed",
  688. "smtp_code" => $code,
  689. "smtp_msg" => substr($rply,4));
  690. if($this->do_debug >= 1) {
  691. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  692. }
  693. return false;
  694. }
  695. return true;
  696. }
  697. /**
  698. * Starts a mail transaction from the email address specified in
  699. * $from. Returns true if successful or false otherwise. If True
  700. * the mail transaction is started and then one or more Recipient
  701. * commands may be called followed by a Data command. This command
  702. * will send the message to the users terminal if they are logged
  703. * in and send them an email.
  704. *
  705. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  706. *
  707. * SMTP CODE SUCCESS: 250
  708. * SMTP CODE SUCCESS: 552,451,452
  709. * SMTP CODE SUCCESS: 500,501,502,421
  710. * @access public
  711. * @return bool
  712. */
  713. public function SendAndMail($from) {
  714. $this->error = null; // so no confusion is caused
  715. if(!$this->connected()) {
  716. $this->error = array(
  717. "error" => "Called SendAndMail() without being connected");
  718. return false;
  719. }
  720. fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
  721. $rply = $this->get_lines();
  722. $code = substr($rply,0,3);
  723. if($this->do_debug >= 2) {
  724. $this->edebug("SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />');
  725. }
  726. if($code != 250) {
  727. $this->error =
  728. array("error" => "SAML not accepted from server",
  729. "smtp_code" => $code,
  730. "smtp_msg" => substr($rply,4));
  731. if($this->do_debug >= 1) {
  732. $this->edebug("SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />');
  733. }
  734. return false;
  735. }
  736. return true;
  737. }
  738. /**
  739. * This is an optional command for SMTP that this class does not
  740. * support. This method is here to make the RFC821 Definition
  741. * complete for this class and __may__ be implimented in the future
  742. *
  743. * Implements from rfc 821: TURN <CRLF>
  744. *
  745. * SMTP CODE SUCCESS: 250
  746. * SMTP CODE FAILURE: 502
  747. * SMTP CODE ERROR : 500, 503
  748. * @access public
  749. * @return bool
  750. */
  751. public function Turn() {
  752. $this->error = array("error" => "This method, TURN, of the SMTP ".
  753. "is not implemented");
  754. if($this->do_debug >= 1) {
  755. $this->edebug("SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />');
  756. }
  757. return false;
  758. }
  759. /**
  760. * Get the current error
  761. * @access public
  762. * @return array
  763. */
  764. public function getError() {
  765. return $this->error;
  766. }
  767. /////////////////////////////////////////////////
  768. // INTERNAL FUNCTIONS
  769. /////////////////////////////////////////////////
  770. /**
  771. * Read in as many lines as possible
  772. * either before eof or socket timeout occurs on the operation.
  773. * With SMTP we can tell if we have more lines to read if the
  774. * 4th character is '-' symbol. If it is a space then we don't
  775. * need to read anything else.
  776. * @access private
  777. * @return string
  778. */
  779. private function get_lines() {
  780. $data = "";
  781. $endtime = 0;
  782. stream_set_timeout($this->smtp_conn, $this->Timeout);
  783. if ($this->Timelimit > 0) {
  784. $endtime = time() + $this->Timelimit;
  785. }
  786. while(!feof($this->smtp_conn)) {
  787. $str = @fgets($this->smtp_conn,515);
  788. if($this->do_debug >= 4) {
  789. $this->edebug("SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />');
  790. $this->edebug("SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />');
  791. }
  792. $data .= $str;
  793. if($this->do_debug >= 4) {
  794. $this->edebug("SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />');
  795. }
  796. // if 4th character is a space, we are done reading, break the loop
  797. if(substr($str,3,1) == " ") { break; }
  798. // Timed-out? Log and break
  799. $info = stream_get_meta_data($this->smtp_conn);
  800. if ($info['timed_out']) {
  801. if($this->do_debug >= 4) {
  802. $this->edebug("SMTP -> get_lines(): timed-out (" . $this->Timeout . " seconds) <br />");
  803. }
  804. break;
  805. }
  806. // Now check if reads took too long
  807. if ($endtime) {
  808. if (time() > $endtime) {
  809. if($this->do_debug >= 4) {
  810. $this->edebug("SMTP -> get_lines(): timelimit reached (" . $this->Timelimit . " seconds) <br />");
  811. }
  812. break;
  813. }
  814. }
  815. }
  816. return $data;
  817. }
  818. }
  819. ?>