class.smtp.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
  1. <?php
  2. /*~ class.smtp.php
  3. .---------------------------------------------------------------------------.
  4. | Software: PHPMailer - PHP email class |
  5. | Version: 5.2 |
  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-2011, 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 - 2011 Jim Jagielski
  33. * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
  34. * @version $Id: class.smtp.php 450 2010-06-23 16:46:33Z coolbru $
  35. */
  36. /**
  37. * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
  38. * commands except TURN which will always return a not implemented
  39. * error. SMTP also provides some utility methods for sending mail
  40. * to an SMTP server.
  41. * original author: Chris Ryan
  42. */
  43. class SMTP {
  44. /**
  45. * SMTP server port
  46. * @var int
  47. */
  48. public $SMTP_PORT = 25;
  49. /**
  50. * SMTP reply line ending
  51. * @var string
  52. */
  53. public $CRLF = "\r\n";
  54. /**
  55. * Sets whether debugging is turned on
  56. * @var bool
  57. */
  58. public $do_debug; // the level of debug to perform
  59. /**
  60. * Sets VERP use on/off (default is off)
  61. * @var bool
  62. */
  63. public $do_verp = false;
  64. /**
  65. * Sets the SMTP PHPMailer Version number
  66. * @var string
  67. */
  68. public $Version = '5.2';
  69. /////////////////////////////////////////////////
  70. // PROPERTIES, PRIVATE AND PROTECTED
  71. /////////////////////////////////////////////////
  72. private $smtp_conn; // the socket to the server
  73. private $error; // error if any on the last call
  74. private $helo_rply; // the reply the server sent to us for HELO
  75. /**
  76. * Initialize the class so that the data is in a known state.
  77. * @access public
  78. * @return void
  79. */
  80. public function __construct() {
  81. $this->smtp_conn = 0;
  82. $this->error = null;
  83. $this->helo_rply = null;
  84. $this->do_debug = 0;
  85. }
  86. /////////////////////////////////////////////////
  87. // CONNECTION FUNCTIONS
  88. /////////////////////////////////////////////////
  89. /**
  90. * Connect to the server specified on the port specified.
  91. * If the port is not specified use the default SMTP_PORT.
  92. * If tval is specified then a connection will try and be
  93. * established with the server for that number of seconds.
  94. * If tval is not specified the default is 30 seconds to
  95. * try on the connection.
  96. *
  97. * SMTP CODE SUCCESS: 220
  98. * SMTP CODE FAILURE: 421
  99. * @access public
  100. * @return bool
  101. */
  102. public function Connect($host, $port = 0, $tval = 30) {
  103. // set the error val to null so there is no confusion
  104. $this->error = null;
  105. // make sure we are __not__ connected
  106. if($this->connected()) {
  107. // already connected, generate error
  108. $this->error = array("error" => "Already connected to a server");
  109. return false;
  110. }
  111. if(empty($port)) {
  112. $port = $this->SMTP_PORT;
  113. }
  114. // connect to the smtp server
  115. $this->smtp_conn = @fsockopen($host, // the host of the server
  116. $port, // the port to use
  117. $errno, // error number if any
  118. $errstr, // error message if any
  119. $tval); // give up after ? secs
  120. // verify we connected properly
  121. if(empty($this->smtp_conn)) {
  122. $this->error = array("error" => "Failed to connect to server",
  123. "errno" => $errno,
  124. "errstr" => $errstr);
  125. if($this->do_debug >= 1) {
  126. echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
  127. }
  128. return false;
  129. }
  130. // SMTP server can take longer to respond, give longer timeout for first read
  131. // Windows does not have support for this timeout function
  132. if(substr(PHP_OS, 0, 3) != "WIN")
  133. socket_set_timeout($this->smtp_conn, $tval, 0);
  134. // get any announcement
  135. $announce = $this->get_lines();
  136. if($this->do_debug >= 2) {
  137. echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
  138. }
  139. return true;
  140. }
  141. /**
  142. * Initiate a TLS communication with the server.
  143. *
  144. * SMTP CODE 220 Ready to start TLS
  145. * SMTP CODE 501 Syntax error (no parameters allowed)
  146. * SMTP CODE 454 TLS not available due to temporary reason
  147. * @access public
  148. * @return bool success
  149. */
  150. public function StartTLS() {
  151. $this->error = null; # to avoid confusion
  152. if(!$this->connected()) {
  153. $this->error = array("error" => "Called StartTLS() without being connected");
  154. return false;
  155. }
  156. fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
  157. $rply = $this->get_lines();
  158. $code = substr($rply,0,3);
  159. if($this->do_debug >= 2) {
  160. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  161. }
  162. if($code != 220) {
  163. $this->error =
  164. array("error" => "STARTTLS not accepted from server",
  165. "smtp_code" => $code,
  166. "smtp_msg" => substr($rply,4));
  167. if($this->do_debug >= 1) {
  168. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  169. }
  170. return false;
  171. }
  172. // Begin encrypted connection
  173. if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
  174. return false;
  175. }
  176. return true;
  177. }
  178. /**
  179. * Performs SMTP authentication. Must be run after running the
  180. * Hello() method. Returns true if successfully authenticated.
  181. * @access public
  182. * @return bool
  183. */
  184. public function Authenticate($username, $password) {
  185. // Start authentication
  186. fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
  187. $rply = $this->get_lines();
  188. $code = substr($rply,0,3);
  189. if($code != 334) {
  190. $this->error =
  191. array("error" => "AUTH not accepted from server",
  192. "smtp_code" => $code,
  193. "smtp_msg" => substr($rply,4));
  194. if($this->do_debug >= 1) {
  195. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  196. }
  197. return false;
  198. }
  199. // Send encoded username
  200. fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
  201. $rply = $this->get_lines();
  202. $code = substr($rply,0,3);
  203. if($code != 334) {
  204. $this->error =
  205. array("error" => "Username not accepted from server",
  206. "smtp_code" => $code,
  207. "smtp_msg" => substr($rply,4));
  208. if($this->do_debug >= 1) {
  209. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  210. }
  211. return false;
  212. }
  213. // Send encoded password
  214. fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
  215. $rply = $this->get_lines();
  216. $code = substr($rply,0,3);
  217. if($code != 235) {
  218. $this->error =
  219. array("error" => "Password not accepted from server",
  220. "smtp_code" => $code,
  221. "smtp_msg" => substr($rply,4));
  222. if($this->do_debug >= 1) {
  223. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  224. }
  225. return false;
  226. }
  227. return true;
  228. }
  229. /**
  230. * Returns true if connected to a server otherwise false
  231. * @access public
  232. * @return bool
  233. */
  234. public function Connected() {
  235. if(!empty($this->smtp_conn)) {
  236. $sock_status = socket_get_status($this->smtp_conn);
  237. if($sock_status["eof"]) {
  238. // the socket is valid but we are not connected
  239. if($this->do_debug >= 1) {
  240. echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
  241. }
  242. $this->Close();
  243. return false;
  244. }
  245. return true; // everything looks good
  246. }
  247. return false;
  248. }
  249. /**
  250. * Closes the socket and cleans up the state of the class.
  251. * It is not considered good to use this function without
  252. * first trying to use QUIT.
  253. * @access public
  254. * @return void
  255. */
  256. public function Close() {
  257. $this->error = null; // so there is no confusion
  258. $this->helo_rply = null;
  259. if(!empty($this->smtp_conn)) {
  260. // close the connection and cleanup
  261. fclose($this->smtp_conn);
  262. $this->smtp_conn = 0;
  263. }
  264. }
  265. /////////////////////////////////////////////////
  266. // SMTP COMMANDS
  267. /////////////////////////////////////////////////
  268. /**
  269. * Issues a data command and sends the msg_data to the server
  270. * finializing the mail transaction. $msg_data is the message
  271. * that is to be send with the headers. Each header needs to be
  272. * on a single line followed by a <CRLF> with the message headers
  273. * and the message body being seperated by and additional <CRLF>.
  274. *
  275. * Implements rfc 821: DATA <CRLF>
  276. *
  277. * SMTP CODE INTERMEDIATE: 354
  278. * [data]
  279. * <CRLF>.<CRLF>
  280. * SMTP CODE SUCCESS: 250
  281. * SMTP CODE FAILURE: 552,554,451,452
  282. * SMTP CODE FAILURE: 451,554
  283. * SMTP CODE ERROR : 500,501,503,421
  284. * @access public
  285. * @return bool
  286. */
  287. public function Data($msg_data) {
  288. $this->error = null; // so no confusion is caused
  289. if(!$this->connected()) {
  290. $this->error = array(
  291. "error" => "Called Data() without being connected");
  292. return false;
  293. }
  294. fputs($this->smtp_conn,"DATA" . $this->CRLF);
  295. $rply = $this->get_lines();
  296. $code = substr($rply,0,3);
  297. if($this->do_debug >= 2) {
  298. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  299. }
  300. if($code != 354) {
  301. $this->error =
  302. array("error" => "DATA command not accepted from server",
  303. "smtp_code" => $code,
  304. "smtp_msg" => substr($rply,4));
  305. if($this->do_debug >= 1) {
  306. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  307. }
  308. return false;
  309. }
  310. /* the server is ready to accept data!
  311. * according to rfc 821 we should not send more than 1000
  312. * including the CRLF
  313. * characters on a single line so we will break the data up
  314. * into lines by \r and/or \n then if needed we will break
  315. * each of those into smaller lines to fit within the limit.
  316. * in addition we will be looking for lines that start with
  317. * a period '.' and append and additional period '.' to that
  318. * line. NOTE: this does not count towards limit.
  319. */
  320. // normalize the line breaks so we know the explode works
  321. $msg_data = str_replace("\r\n","\n",$msg_data);
  322. $msg_data = str_replace("\r","\n",$msg_data);
  323. $lines = explode("\n",$msg_data);
  324. /* we need to find a good way to determine is headers are
  325. * in the msg_data or if it is a straight msg body
  326. * currently I am assuming rfc 822 definitions of msg headers
  327. * and if the first field of the first line (':' sperated)
  328. * does not contain a space then it _should_ be a header
  329. * and we can process all lines before a blank "" line as
  330. * headers.
  331. */
  332. $field = substr($lines[0],0,strpos($lines[0],":"));
  333. $in_headers = false;
  334. if(!empty($field) && !strstr($field," ")) {
  335. $in_headers = true;
  336. }
  337. $max_line_length = 998; // used below; set here for ease in change
  338. while(list(,$line) = @each($lines)) {
  339. $lines_out = null;
  340. if($line == "" && $in_headers) {
  341. $in_headers = false;
  342. }
  343. // ok we need to break this line up into several smaller lines
  344. while(strlen($line) > $max_line_length) {
  345. $pos = strrpos(substr($line,0,$max_line_length)," ");
  346. // Patch to fix DOS attack
  347. if(!$pos) {
  348. $pos = $max_line_length - 1;
  349. $lines_out[] = substr($line,0,$pos);
  350. $line = substr($line,$pos);
  351. } else {
  352. $lines_out[] = substr($line,0,$pos);
  353. $line = substr($line,$pos + 1);
  354. }
  355. /* if processing headers add a LWSP-char to the front of new line
  356. * rfc 822 on long msg headers
  357. */
  358. if($in_headers) {
  359. $line = "\t" . $line;
  360. }
  361. }
  362. $lines_out[] = $line;
  363. // send the lines to the server
  364. while(list(,$line_out) = @each($lines_out)) {
  365. if(strlen($line_out) > 0)
  366. {
  367. if(substr($line_out, 0, 1) == ".") {
  368. $line_out = "." . $line_out;
  369. }
  370. }
  371. fputs($this->smtp_conn,$line_out . $this->CRLF);
  372. }
  373. }
  374. // message data has been sent
  375. fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
  376. $rply = $this->get_lines();
  377. $code = substr($rply,0,3);
  378. if($this->do_debug >= 2) {
  379. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  380. }
  381. if($code != 250) {
  382. $this->error =
  383. array("error" => "DATA not accepted from server",
  384. "smtp_code" => $code,
  385. "smtp_msg" => substr($rply,4));
  386. if($this->do_debug >= 1) {
  387. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  388. }
  389. return false;
  390. }
  391. return true;
  392. }
  393. /**
  394. * Sends the HELO command to the smtp server.
  395. * This makes sure that we and the server are in
  396. * the same known state.
  397. *
  398. * Implements from rfc 821: HELO <SP> <domain> <CRLF>
  399. *
  400. * SMTP CODE SUCCESS: 250
  401. * SMTP CODE ERROR : 500, 501, 504, 421
  402. * @access public
  403. * @return bool
  404. */
  405. public function Hello($host = '') {
  406. $this->error = null; // so no confusion is caused
  407. if(!$this->connected()) {
  408. $this->error = array(
  409. "error" => "Called Hello() without being connected");
  410. return false;
  411. }
  412. // if hostname for HELO was not specified send default
  413. if(empty($host)) {
  414. // determine appropriate default to send to server
  415. $host = "localhost";
  416. }
  417. // Send extended hello first (RFC 2821)
  418. if(!$this->SendHello("EHLO", $host)) {
  419. if(!$this->SendHello("HELO", $host)) {
  420. return false;
  421. }
  422. }
  423. return true;
  424. }
  425. /**
  426. * Sends a HELO/EHLO command.
  427. * @access private
  428. * @return bool
  429. */
  430. private function SendHello($hello, $host) {
  431. fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
  432. $rply = $this->get_lines();
  433. $code = substr($rply,0,3);
  434. if($this->do_debug >= 2) {
  435. echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
  436. }
  437. if($code != 250) {
  438. $this->error =
  439. array("error" => $hello . " not accepted from server",
  440. "smtp_code" => $code,
  441. "smtp_msg" => substr($rply,4));
  442. if($this->do_debug >= 1) {
  443. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  444. }
  445. return false;
  446. }
  447. $this->helo_rply = $rply;
  448. return true;
  449. }
  450. /**
  451. * Starts a mail transaction from the email address specified in
  452. * $from. Returns true if successful or false otherwise. If True
  453. * the mail transaction is started and then one or more Recipient
  454. * commands may be called followed by a Data command.
  455. *
  456. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  457. *
  458. * SMTP CODE SUCCESS: 250
  459. * SMTP CODE SUCCESS: 552,451,452
  460. * SMTP CODE SUCCESS: 500,501,421
  461. * @access public
  462. * @return bool
  463. */
  464. public function Mail($from) {
  465. $this->error = null; // so no confusion is caused
  466. if(!$this->connected()) {
  467. $this->error = array(
  468. "error" => "Called Mail() without being connected");
  469. return false;
  470. }
  471. $useVerp = ($this->do_verp ? "XVERP" : "");
  472. fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
  473. $rply = $this->get_lines();
  474. $code = substr($rply,0,3);
  475. if($this->do_debug >= 2) {
  476. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  477. }
  478. if($code != 250) {
  479. $this->error =
  480. array("error" => "MAIL not accepted from server",
  481. "smtp_code" => $code,
  482. "smtp_msg" => substr($rply,4));
  483. if($this->do_debug >= 1) {
  484. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  485. }
  486. return false;
  487. }
  488. return true;
  489. }
  490. /**
  491. * Sends the quit command to the server and then closes the socket
  492. * if there is no error or the $close_on_error argument is true.
  493. *
  494. * Implements from rfc 821: QUIT <CRLF>
  495. *
  496. * SMTP CODE SUCCESS: 221
  497. * SMTP CODE ERROR : 500
  498. * @access public
  499. * @return bool
  500. */
  501. public function Quit($close_on_error = true) {
  502. $this->error = null; // so there is no confusion
  503. if(!$this->connected()) {
  504. $this->error = array(
  505. "error" => "Called Quit() without being connected");
  506. return false;
  507. }
  508. // send the quit command to the server
  509. fputs($this->smtp_conn,"quit" . $this->CRLF);
  510. // get any good-bye messages
  511. $byemsg = $this->get_lines();
  512. if($this->do_debug >= 2) {
  513. echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
  514. }
  515. $rval = true;
  516. $e = null;
  517. $code = substr($byemsg,0,3);
  518. if($code != 221) {
  519. // use e as a tmp var cause Close will overwrite $this->error
  520. $e = array("error" => "SMTP server rejected quit command",
  521. "smtp_code" => $code,
  522. "smtp_rply" => substr($byemsg,4));
  523. $rval = false;
  524. if($this->do_debug >= 1) {
  525. echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
  526. }
  527. }
  528. if(empty($e) || $close_on_error) {
  529. $this->Close();
  530. }
  531. return $rval;
  532. }
  533. /**
  534. * Sends the command RCPT to the SMTP server with the TO: argument of $to.
  535. * Returns true if the recipient was accepted false if it was rejected.
  536. *
  537. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  538. *
  539. * SMTP CODE SUCCESS: 250,251
  540. * SMTP CODE FAILURE: 550,551,552,553,450,451,452
  541. * SMTP CODE ERROR : 500,501,503,421
  542. * @access public
  543. * @return bool
  544. */
  545. public function Recipient($to) {
  546. $this->error = null; // so no confusion is caused
  547. if(!$this->connected()) {
  548. $this->error = array(
  549. "error" => "Called Recipient() without being connected");
  550. return false;
  551. }
  552. fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
  553. $rply = $this->get_lines();
  554. $code = substr($rply,0,3);
  555. if($this->do_debug >= 2) {
  556. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  557. }
  558. if($code != 250 && $code != 251) {
  559. $this->error =
  560. array("error" => "RCPT not accepted from server",
  561. "smtp_code" => $code,
  562. "smtp_msg" => substr($rply,4));
  563. if($this->do_debug >= 1) {
  564. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  565. }
  566. return false;
  567. }
  568. return true;
  569. }
  570. /**
  571. * Sends the RSET command to abort and transaction that is
  572. * currently in progress. Returns true if successful false
  573. * otherwise.
  574. *
  575. * Implements rfc 821: RSET <CRLF>
  576. *
  577. * SMTP CODE SUCCESS: 250
  578. * SMTP CODE ERROR : 500,501,504,421
  579. * @access public
  580. * @return bool
  581. */
  582. public function Reset() {
  583. $this->error = null; // so no confusion is caused
  584. if(!$this->connected()) {
  585. $this->error = array(
  586. "error" => "Called Reset() without being connected");
  587. return false;
  588. }
  589. fputs($this->smtp_conn,"RSET" . $this->CRLF);
  590. $rply = $this->get_lines();
  591. $code = substr($rply,0,3);
  592. if($this->do_debug >= 2) {
  593. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  594. }
  595. if($code != 250) {
  596. $this->error =
  597. array("error" => "RSET failed",
  598. "smtp_code" => $code,
  599. "smtp_msg" => substr($rply,4));
  600. if($this->do_debug >= 1) {
  601. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  602. }
  603. return false;
  604. }
  605. return true;
  606. }
  607. /**
  608. * Starts a mail transaction from the email address specified in
  609. * $from. Returns true if successful or false otherwise. If True
  610. * the mail transaction is started and then one or more Recipient
  611. * commands may be called followed by a Data command. This command
  612. * will send the message to the users terminal if they are logged
  613. * in and send them an email.
  614. *
  615. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  616. *
  617. * SMTP CODE SUCCESS: 250
  618. * SMTP CODE SUCCESS: 552,451,452
  619. * SMTP CODE SUCCESS: 500,501,502,421
  620. * @access public
  621. * @return bool
  622. */
  623. public function SendAndMail($from) {
  624. $this->error = null; // so no confusion is caused
  625. if(!$this->connected()) {
  626. $this->error = array(
  627. "error" => "Called SendAndMail() without being connected");
  628. return false;
  629. }
  630. fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
  631. $rply = $this->get_lines();
  632. $code = substr($rply,0,3);
  633. if($this->do_debug >= 2) {
  634. echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
  635. }
  636. if($code != 250) {
  637. $this->error =
  638. array("error" => "SAML not accepted from server",
  639. "smtp_code" => $code,
  640. "smtp_msg" => substr($rply,4));
  641. if($this->do_debug >= 1) {
  642. echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
  643. }
  644. return false;
  645. }
  646. return true;
  647. }
  648. /**
  649. * This is an optional command for SMTP that this class does not
  650. * support. This method is here to make the RFC821 Definition
  651. * complete for this class and __may__ be implimented in the future
  652. *
  653. * Implements from rfc 821: TURN <CRLF>
  654. *
  655. * SMTP CODE SUCCESS: 250
  656. * SMTP CODE FAILURE: 502
  657. * SMTP CODE ERROR : 500, 503
  658. * @access public
  659. * @return bool
  660. */
  661. public function Turn() {
  662. $this->error = array("error" => "This method, TURN, of the SMTP ".
  663. "is not implemented");
  664. if($this->do_debug >= 1) {
  665. echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
  666. }
  667. return false;
  668. }
  669. /**
  670. * Get the current error
  671. * @access public
  672. * @return array
  673. */
  674. public function getError() {
  675. return $this->error;
  676. }
  677. /////////////////////////////////////////////////
  678. // INTERNAL FUNCTIONS
  679. /////////////////////////////////////////////////
  680. /**
  681. * Read in as many lines as possible
  682. * either before eof or socket timeout occurs on the operation.
  683. * With SMTP we can tell if we have more lines to read if the
  684. * 4th character is '-' symbol. If it is a space then we don't
  685. * need to read anything else.
  686. * @access private
  687. * @return string
  688. */
  689. private function get_lines() {
  690. $data = "";
  691. while($str = @fgets($this->smtp_conn,515)) {
  692. if($this->do_debug >= 4) {
  693. echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
  694. echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
  695. }
  696. $data .= $str;
  697. if($this->do_debug >= 4) {
  698. echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
  699. }
  700. // if 4th character is a space, we are done reading, break the loop
  701. if(substr($str,3,1) == " ") { break; }
  702. }
  703. return $data;
  704. }
  705. }
  706. ?>