class.smtp.php 26 KB

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