class.smtp.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. <?php
  2. /*~ class.smtp.php
  3. .---------------------------------------------------------------------------.
  4. | Software: PHPMailer - PHP email class |
  5. | Version: 2.0.4 |
  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. | Author: Andy Prevost (project admininistrator) |
  11. | Author: Brent R. Matzelle (original founder) |
  12. | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved. |
  13. | Copyright (c) 2001-2003, Brent R. Matzelle |
  14. | ------------------------------------------------------------------------- |
  15. | License: Distributed under the Lesser General Public License (LGPL) |
  16. | http://www.gnu.org/copyleft/lesser.html |
  17. | This program is distributed in the hope that it will be useful - WITHOUT |
  18. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
  19. | FITNESS FOR A PARTICULAR PURPOSE. |
  20. | ------------------------------------------------------------------------- |
  21. | We offer a number of paid services (www.codeworxtech.com): |
  22. | - Web Hosting on highly optimized fast and secure servers |
  23. | - Technology Consulting |
  24. | - Oursourcing (highly qualified programmers and graphic designers) |
  25. '---------------------------------------------------------------------------'
  26. /**
  27. * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP
  28. * commands except TURN which will always return a not implemented
  29. * error. SMTP also provides some utility methods for sending mail
  30. * to an SMTP server.
  31. * @package PHPMailer
  32. * @author Chris Ryan
  33. */
  34. class SMTP
  35. {
  36. /**
  37. * SMTP server port
  38. * @var int
  39. */
  40. var $SMTP_PORT = 25;
  41. /**
  42. * SMTP reply line ending
  43. * @var string
  44. */
  45. var $CRLF = "\r\n";
  46. /**
  47. * Sets whether debugging is turned on
  48. * @var bool
  49. */
  50. var $do_debug; # the level of debug to perform
  51. /**
  52. * Sets VERP use on/off (default is off)
  53. * @var bool
  54. */
  55. var $do_verp = false;
  56. /**#@+
  57. * @access private
  58. */
  59. var $smtp_conn; # the socket to the server
  60. var $error; # error if any on the last call
  61. var $helo_rply; # the reply the server sent to us for HELO
  62. /**#@-*/
  63. /**
  64. * Initialize the class so that the data is in a known state.
  65. * @access public
  66. * @return void
  67. */
  68. function SMTP() {
  69. $this->smtp_conn = 0;
  70. $this->error = null;
  71. $this->helo_rply = null;
  72. $this->do_debug = 0;
  73. }
  74. /*************************************************************
  75. * CONNECTION FUNCTIONS *
  76. ***********************************************************/
  77. /**
  78. * Connect to the server specified on the port specified.
  79. * If the port is not specified use the default SMTP_PORT.
  80. * If tval is specified then a connection will try and be
  81. * established with the server for that number of seconds.
  82. * If tval is not specified the default is 30 seconds to
  83. * try on the connection.
  84. *
  85. * SMTP CODE SUCCESS: 220
  86. * SMTP CODE FAILURE: 421
  87. * @access public
  88. * @return bool
  89. */
  90. function Connect($host,$port=0,$tval=30) {
  91. # set the error val to null so there is no confusion
  92. $this->error = null;
  93. # make sure we are __not__ connected
  94. if($this->connected()) {
  95. # ok we are connected! what should we do?
  96. # for now we will just give an error saying we
  97. # are already connected
  98. $this->error = array("error" => "Already connected to a server");
  99. return false;
  100. }
  101. if(empty($port)) {
  102. $port = $this->SMTP_PORT;
  103. }
  104. #connect to the smtp server
  105. $this->smtp_conn = fsockopen($host, # the host of the server
  106. $port, # the port to use
  107. $errno, # error number if any
  108. $errstr, # error message if any
  109. $tval); # give up after ? secs
  110. # verify we connected properly
  111. if(empty($this->smtp_conn)) {
  112. $this->error = array("error" => "Failed to connect to server",
  113. "errno" => $errno,
  114. "errstr" => $errstr);
  115. if($this->do_debug >= 1) {
  116. echo "SMTP -> ERROR: " . $this->error["error"] .
  117. ": $errstr ($errno)" . $this->CRLF;
  118. }
  119. return false;
  120. }
  121. # sometimes the SMTP server takes a little longer to respond
  122. # so we will give it a longer timeout for the first read
  123. // Windows still does not have support for this timeout function
  124. if(substr(PHP_OS, 0, 3) != "WIN")
  125. socket_set_timeout($this->smtp_conn, $tval, 0);
  126. # get any announcement stuff
  127. $announce = $this->get_lines();
  128. # set the timeout of any socket functions at 1/10 of a second
  129. //if(function_exists("socket_set_timeout"))
  130. // socket_set_timeout($this->smtp_conn, 0, 100000);
  131. if($this->do_debug >= 2) {
  132. echo "SMTP -> FROM SERVER:" . $this->CRLF . $announce;
  133. }
  134. return true;
  135. }
  136. /**
  137. * Performs SMTP authentication. Must be run after running the
  138. * Hello() method. Returns true if successfully authenticated.
  139. * @access public
  140. * @return bool
  141. */
  142. function Authenticate($username, $password) {
  143. // Start authentication
  144. fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
  145. $rply = $this->get_lines();
  146. $code = substr($rply,0,3);
  147. if($code != 334) {
  148. $this->error =
  149. array("error" => "AUTH not accepted from server",
  150. "smtp_code" => $code,
  151. "smtp_msg" => substr($rply,4));
  152. if($this->do_debug >= 1) {
  153. echo "SMTP -> ERROR: " . $this->error["error"] .
  154. ": " . $rply . $this->CRLF;
  155. }
  156. return false;
  157. }
  158. // Send encoded username
  159. fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
  160. $rply = $this->get_lines();
  161. $code = substr($rply,0,3);
  162. if($code != 334) {
  163. $this->error =
  164. array("error" => "Username 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"] .
  169. ": " . $rply . $this->CRLF;
  170. }
  171. return false;
  172. }
  173. // Send encoded password
  174. fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
  175. $rply = $this->get_lines();
  176. $code = substr($rply,0,3);
  177. if($code != 235) {
  178. $this->error =
  179. array("error" => "Password not accepted from server",
  180. "smtp_code" => $code,
  181. "smtp_msg" => substr($rply,4));
  182. if($this->do_debug >= 1) {
  183. echo "SMTP -> ERROR: " . $this->error["error"] .
  184. ": " . $rply . $this->CRLF;
  185. }
  186. return false;
  187. }
  188. return true;
  189. }
  190. /**
  191. * Returns true if connected to a server otherwise false
  192. * @access private
  193. * @return bool
  194. */
  195. function Connected() {
  196. if(!empty($this->smtp_conn)) {
  197. $sock_status = socket_get_status($this->smtp_conn);
  198. if($sock_status["eof"]) {
  199. # hmm this is an odd situation... the socket is
  200. # valid but we are not connected anymore
  201. if($this->do_debug >= 1) {
  202. echo "SMTP -> NOTICE:" . $this->CRLF .
  203. "EOF caught while checking if connected";
  204. }
  205. $this->Close();
  206. return false;
  207. }
  208. return true; # everything looks good
  209. }
  210. return false;
  211. }
  212. /**
  213. * Closes the socket and cleans up the state of the class.
  214. * It is not considered good to use this function without
  215. * first trying to use QUIT.
  216. * @access public
  217. * @return void
  218. */
  219. function Close() {
  220. $this->error = null; # so there is no confusion
  221. $this->helo_rply = null;
  222. if(!empty($this->smtp_conn)) {
  223. # close the connection and cleanup
  224. fclose($this->smtp_conn);
  225. $this->smtp_conn = 0;
  226. }
  227. }
  228. /***************************************************************
  229. * SMTP COMMANDS *
  230. *************************************************************/
  231. /**
  232. * Issues a data command and sends the msg_data to the server
  233. * finializing the mail transaction. $msg_data is the message
  234. * that is to be send with the headers. Each header needs to be
  235. * on a single line followed by a <CRLF> with the message headers
  236. * and the message body being seperated by and additional <CRLF>.
  237. *
  238. * Implements rfc 821: DATA <CRLF>
  239. *
  240. * SMTP CODE INTERMEDIATE: 354
  241. * [data]
  242. * <CRLF>.<CRLF>
  243. * SMTP CODE SUCCESS: 250
  244. * SMTP CODE FAILURE: 552,554,451,452
  245. * SMTP CODE FAILURE: 451,554
  246. * SMTP CODE ERROR : 500,501,503,421
  247. * @access public
  248. * @return bool
  249. */
  250. function Data($msg_data) {
  251. $this->error = null; # so no confusion is caused
  252. if(!$this->connected()) {
  253. $this->error = array(
  254. "error" => "Called Data() without being connected");
  255. return false;
  256. }
  257. fputs($this->smtp_conn,"DATA" . $this->CRLF);
  258. $rply = $this->get_lines();
  259. $code = substr($rply,0,3);
  260. if($this->do_debug >= 2) {
  261. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  262. }
  263. if($code != 354) {
  264. $this->error =
  265. array("error" => "DATA command not accepted from server",
  266. "smtp_code" => $code,
  267. "smtp_msg" => substr($rply,4));
  268. if($this->do_debug >= 1) {
  269. echo "SMTP -> ERROR: " . $this->error["error"] .
  270. ": " . $rply . $this->CRLF;
  271. }
  272. return false;
  273. }
  274. # the server is ready to accept data!
  275. # according to rfc 821 we should not send more than 1000
  276. # including the CRLF
  277. # characters on a single line so we will break the data up
  278. # into lines by \r and/or \n then if needed we will break
  279. # each of those into smaller lines to fit within the limit.
  280. # in addition we will be looking for lines that start with
  281. # a period '.' and append and additional period '.' to that
  282. # line. NOTE: this does not count towards are limit.
  283. # normalize the line breaks so we know the explode works
  284. $msg_data = str_replace("\r\n","\n",$msg_data);
  285. $msg_data = str_replace("\r","\n",$msg_data);
  286. $lines = explode("\n",$msg_data);
  287. # we need to find a good way to determine is headers are
  288. # in the msg_data or if it is a straight msg body
  289. # currently I am assuming rfc 822 definitions of msg headers
  290. # and if the first field of the first line (':' sperated)
  291. # does not contain a space then it _should_ be a header
  292. # and we can process all lines before a blank "" line as
  293. # headers.
  294. $field = substr($lines[0],0,strpos($lines[0],":"));
  295. $in_headers = false;
  296. if(!empty($field) && !strstr($field," ")) {
  297. $in_headers = true;
  298. }
  299. $max_line_length = 998; # used below; set here for ease in change
  300. while(list(,$line) = @each($lines)) {
  301. $lines_out = null;
  302. if($line == "" && $in_headers) {
  303. $in_headers = false;
  304. }
  305. # ok we need to break this line up into several
  306. # smaller lines
  307. while(strlen($line) > $max_line_length) {
  308. $pos = strrpos(substr($line,0,$max_line_length)," ");
  309. # Patch to fix DOS attack
  310. if(!$pos) {
  311. $pos = $max_line_length - 1;
  312. }
  313. $lines_out[] = substr($line,0,$pos);
  314. $line = substr($line,$pos + 1);
  315. # if we are processing headers we need to
  316. # add a LWSP-char to the front of the new line
  317. # rfc 822 on long msg headers
  318. if($in_headers) {
  319. $line = "\t" . $line;
  320. }
  321. }
  322. $lines_out[] = $line;
  323. # now send the lines to the server
  324. while(list(,$line_out) = @each($lines_out)) {
  325. if(strlen($line_out) > 0)
  326. {
  327. if(substr($line_out, 0, 1) == ".") {
  328. $line_out = "." . $line_out;
  329. }
  330. }
  331. fputs($this->smtp_conn,$line_out . $this->CRLF);
  332. }
  333. }
  334. # ok all the message data has been sent so lets get this
  335. # over with aleady
  336. fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
  337. $rply = $this->get_lines();
  338. $code = substr($rply,0,3);
  339. if($this->do_debug >= 2) {
  340. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  341. }
  342. if($code != 250) {
  343. $this->error =
  344. array("error" => "DATA not accepted from server",
  345. "smtp_code" => $code,
  346. "smtp_msg" => substr($rply,4));
  347. if($this->do_debug >= 1) {
  348. echo "SMTP -> ERROR: " . $this->error["error"] .
  349. ": " . $rply . $this->CRLF;
  350. }
  351. return false;
  352. }
  353. return true;
  354. }
  355. /**
  356. * Expand takes the name and asks the server to list all the
  357. * people who are members of the _list_. Expand will return
  358. * back and array of the result or false if an error occurs.
  359. * Each value in the array returned has the format of:
  360. * [ <full-name> <sp> ] <path>
  361. * The definition of <path> is defined in rfc 821
  362. *
  363. * Implements rfc 821: EXPN <SP> <string> <CRLF>
  364. *
  365. * SMTP CODE SUCCESS: 250
  366. * SMTP CODE FAILURE: 550
  367. * SMTP CODE ERROR : 500,501,502,504,421
  368. * @access public
  369. * @return string array
  370. */
  371. function Expand($name) {
  372. $this->error = null; # so no confusion is caused
  373. if(!$this->connected()) {
  374. $this->error = array(
  375. "error" => "Called Expand() without being connected");
  376. return false;
  377. }
  378. fputs($this->smtp_conn,"EXPN " . $name . $this->CRLF);
  379. $rply = $this->get_lines();
  380. $code = substr($rply,0,3);
  381. if($this->do_debug >= 2) {
  382. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  383. }
  384. if($code != 250) {
  385. $this->error =
  386. array("error" => "EXPN not accepted from server",
  387. "smtp_code" => $code,
  388. "smtp_msg" => substr($rply,4));
  389. if($this->do_debug >= 1) {
  390. echo "SMTP -> ERROR: " . $this->error["error"] .
  391. ": " . $rply . $this->CRLF;
  392. }
  393. return false;
  394. }
  395. # parse the reply and place in our array to return to user
  396. $entries = explode($this->CRLF,$rply);
  397. while(list(,$l) = @each($entries)) {
  398. $list[] = substr($l,4);
  399. }
  400. return $list;
  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. * @access public
  412. * @return bool
  413. */
  414. function Hello($host="") {
  415. $this->error = null; # so no confusion is caused
  416. if(!$this->connected()) {
  417. $this->error = array(
  418. "error" => "Called Hello() without being connected");
  419. return false;
  420. }
  421. # if a hostname for the HELO was not specified determine
  422. # a suitable one to send
  423. if(empty($host)) {
  424. # we need to determine some sort of appopiate default
  425. # to send to the server
  426. $host = "localhost";
  427. }
  428. // Send extended hello first (RFC 2821)
  429. if(!$this->SendHello("EHLO", $host))
  430. {
  431. if(!$this->SendHello("HELO", $host))
  432. return false;
  433. }
  434. return true;
  435. }
  436. /**
  437. * Sends a HELO/EHLO command.
  438. * @access private
  439. * @return bool
  440. */
  441. function SendHello($hello, $host) {
  442. fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
  443. $rply = $this->get_lines();
  444. $code = substr($rply,0,3);
  445. if($this->do_debug >= 2) {
  446. echo "SMTP -> FROM SERVER: " . $this->CRLF . $rply;
  447. }
  448. if($code != 250) {
  449. $this->error =
  450. array("error" => $hello . " not accepted from server",
  451. "smtp_code" => $code,
  452. "smtp_msg" => substr($rply,4));
  453. if($this->do_debug >= 1) {
  454. echo "SMTP -> ERROR: " . $this->error["error"] .
  455. ": " . $rply . $this->CRLF;
  456. }
  457. return false;
  458. }
  459. $this->helo_rply = $rply;
  460. return true;
  461. }
  462. /**
  463. * Gets help information on the keyword specified. If the keyword
  464. * is not specified then returns generic help, ussually contianing
  465. * A list of keywords that help is available on. This function
  466. * returns the results back to the user. It is up to the user to
  467. * handle the returned data. If an error occurs then false is
  468. * returned with $this->error set appropiately.
  469. *
  470. * Implements rfc 821: HELP [ <SP> <string> ] <CRLF>
  471. *
  472. * SMTP CODE SUCCESS: 211,214
  473. * SMTP CODE ERROR : 500,501,502,504,421
  474. * @access public
  475. * @return string
  476. */
  477. function Help($keyword="") {
  478. $this->error = null; # to avoid confusion
  479. if(!$this->connected()) {
  480. $this->error = array(
  481. "error" => "Called Help() without being connected");
  482. return false;
  483. }
  484. $extra = "";
  485. if(!empty($keyword)) {
  486. $extra = " " . $keyword;
  487. }
  488. fputs($this->smtp_conn,"HELP" . $extra . $this->CRLF);
  489. $rply = $this->get_lines();
  490. $code = substr($rply,0,3);
  491. if($this->do_debug >= 2) {
  492. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  493. }
  494. if($code != 211 && $code != 214) {
  495. $this->error =
  496. array("error" => "HELP not accepted from server",
  497. "smtp_code" => $code,
  498. "smtp_msg" => substr($rply,4));
  499. if($this->do_debug >= 1) {
  500. echo "SMTP -> ERROR: " . $this->error["error"] .
  501. ": " . $rply . $this->CRLF;
  502. }
  503. return false;
  504. }
  505. return $rply;
  506. }
  507. /**
  508. * Starts a mail transaction from the email address specified in
  509. * $from. Returns true if successful or false otherwise. If True
  510. * the mail transaction is started and then one or more Recipient
  511. * commands may be called followed by a Data command.
  512. *
  513. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  514. *
  515. * SMTP CODE SUCCESS: 250
  516. * SMTP CODE SUCCESS: 552,451,452
  517. * SMTP CODE SUCCESS: 500,501,421
  518. * @access public
  519. * @return bool
  520. */
  521. function Mail($from) {
  522. $this->error = null; # so no confusion is caused
  523. if(!$this->connected()) {
  524. $this->error = array(
  525. "error" => "Called Mail() without being connected");
  526. return false;
  527. }
  528. $useVerp = ($this->do_verp ? "XVERP" : "");
  529. fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
  530. $rply = $this->get_lines();
  531. $code = substr($rply,0,3);
  532. if($this->do_debug >= 2) {
  533. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  534. }
  535. if($code != 250) {
  536. $this->error =
  537. array("error" => "MAIL not accepted from server",
  538. "smtp_code" => $code,
  539. "smtp_msg" => substr($rply,4));
  540. if($this->do_debug >= 1) {
  541. echo "SMTP -> ERROR: " . $this->error["error"] .
  542. ": " . $rply . $this->CRLF;
  543. }
  544. return false;
  545. }
  546. return true;
  547. }
  548. /**
  549. * Sends the command NOOP to the SMTP server.
  550. *
  551. * Implements from rfc 821: NOOP <CRLF>
  552. *
  553. * SMTP CODE SUCCESS: 250
  554. * SMTP CODE ERROR : 500, 421
  555. * @access public
  556. * @return bool
  557. */
  558. function Noop() {
  559. $this->error = null; # so no confusion is caused
  560. if(!$this->connected()) {
  561. $this->error = array(
  562. "error" => "Called Noop() without being connected");
  563. return false;
  564. }
  565. fputs($this->smtp_conn,"NOOP" . $this->CRLF);
  566. $rply = $this->get_lines();
  567. $code = substr($rply,0,3);
  568. if($this->do_debug >= 2) {
  569. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  570. }
  571. if($code != 250) {
  572. $this->error =
  573. array("error" => "NOOP not accepted from server",
  574. "smtp_code" => $code,
  575. "smtp_msg" => substr($rply,4));
  576. if($this->do_debug >= 1) {
  577. echo "SMTP -> ERROR: " . $this->error["error"] .
  578. ": " . $rply . $this->CRLF;
  579. }
  580. return false;
  581. }
  582. return true;
  583. }
  584. /**
  585. * Sends the quit command to the server and then closes the socket
  586. * if there is no error or the $close_on_error argument is true.
  587. *
  588. * Implements from rfc 821: QUIT <CRLF>
  589. *
  590. * SMTP CODE SUCCESS: 221
  591. * SMTP CODE ERROR : 500
  592. * @access public
  593. * @return bool
  594. */
  595. function Quit($close_on_error=true) {
  596. $this->error = null; # so there is no confusion
  597. if(!$this->connected()) {
  598. $this->error = array(
  599. "error" => "Called Quit() without being connected");
  600. return false;
  601. }
  602. # send the quit command to the server
  603. fputs($this->smtp_conn,"quit" . $this->CRLF);
  604. # get any good-bye messages
  605. $byemsg = $this->get_lines();
  606. if($this->do_debug >= 2) {
  607. echo "SMTP -> FROM SERVER:" . $this->CRLF . $byemsg;
  608. }
  609. $rval = true;
  610. $e = null;
  611. $code = substr($byemsg,0,3);
  612. if($code != 221) {
  613. # use e as a tmp var cause Close will overwrite $this->error
  614. $e = array("error" => "SMTP server rejected quit command",
  615. "smtp_code" => $code,
  616. "smtp_rply" => substr($byemsg,4));
  617. $rval = false;
  618. if($this->do_debug >= 1) {
  619. echo "SMTP -> ERROR: " . $e["error"] . ": " .
  620. $byemsg . $this->CRLF;
  621. }
  622. }
  623. if(empty($e) || $close_on_error) {
  624. $this->Close();
  625. }
  626. return $rval;
  627. }
  628. /**
  629. * Sends the command RCPT to the SMTP server with the TO: argument of $to.
  630. * Returns true if the recipient was accepted false if it was rejected.
  631. *
  632. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  633. *
  634. * SMTP CODE SUCCESS: 250,251
  635. * SMTP CODE FAILURE: 550,551,552,553,450,451,452
  636. * SMTP CODE ERROR : 500,501,503,421
  637. * @access public
  638. * @return bool
  639. */
  640. function Recipient($to) {
  641. $this->error = null; # so no confusion is caused
  642. if(!$this->connected()) {
  643. $this->error = array(
  644. "error" => "Called Recipient() without being connected");
  645. return false;
  646. }
  647. fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
  648. $rply = $this->get_lines();
  649. $code = substr($rply,0,3);
  650. if($this->do_debug >= 2) {
  651. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  652. }
  653. if($code != 250 && $code != 251) {
  654. $this->error =
  655. array("error" => "RCPT not accepted from server",
  656. "smtp_code" => $code,
  657. "smtp_msg" => substr($rply,4));
  658. if($this->do_debug >= 1) {
  659. echo "SMTP -> ERROR: " . $this->error["error"] .
  660. ": " . $rply . $this->CRLF;
  661. }
  662. return false;
  663. }
  664. return true;
  665. }
  666. /**
  667. * Sends the RSET command to abort and transaction that is
  668. * currently in progress. Returns true if successful false
  669. * otherwise.
  670. *
  671. * Implements rfc 821: RSET <CRLF>
  672. *
  673. * SMTP CODE SUCCESS: 250
  674. * SMTP CODE ERROR : 500,501,504,421
  675. * @access public
  676. * @return bool
  677. */
  678. function Reset() {
  679. $this->error = null; # so no confusion is caused
  680. if(!$this->connected()) {
  681. $this->error = array(
  682. "error" => "Called Reset() without being connected");
  683. return false;
  684. }
  685. fputs($this->smtp_conn,"RSET" . $this->CRLF);
  686. $rply = $this->get_lines();
  687. $code = substr($rply,0,3);
  688. if($this->do_debug >= 2) {
  689. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  690. }
  691. if($code != 250) {
  692. $this->error =
  693. array("error" => "RSET failed",
  694. "smtp_code" => $code,
  695. "smtp_msg" => substr($rply,4));
  696. if($this->do_debug >= 1) {
  697. echo "SMTP -> ERROR: " . $this->error["error"] .
  698. ": " . $rply . $this->CRLF;
  699. }
  700. return false;
  701. }
  702. return true;
  703. }
  704. /**
  705. * Starts a mail transaction from the email address specified in
  706. * $from. Returns true if successful or false otherwise. If True
  707. * the mail transaction is started and then one or more Recipient
  708. * commands may be called followed by a Data command. This command
  709. * will send the message to the users terminal if they are logged
  710. * in.
  711. *
  712. * Implements rfc 821: SEND <SP> FROM:<reverse-path> <CRLF>
  713. *
  714. * SMTP CODE SUCCESS: 250
  715. * SMTP CODE SUCCESS: 552,451,452
  716. * SMTP CODE SUCCESS: 500,501,502,421
  717. * @access public
  718. * @return bool
  719. */
  720. function Send($from) {
  721. $this->error = null; # so no confusion is caused
  722. if(!$this->connected()) {
  723. $this->error = array(
  724. "error" => "Called Send() without being connected");
  725. return false;
  726. }
  727. fputs($this->smtp_conn,"SEND FROM:" . $from . $this->CRLF);
  728. $rply = $this->get_lines();
  729. $code = substr($rply,0,3);
  730. if($this->do_debug >= 2) {
  731. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  732. }
  733. if($code != 250) {
  734. $this->error =
  735. array("error" => "SEND not accepted from server",
  736. "smtp_code" => $code,
  737. "smtp_msg" => substr($rply,4));
  738. if($this->do_debug >= 1) {
  739. echo "SMTP -> ERROR: " . $this->error["error"] .
  740. ": " . $rply . $this->CRLF;
  741. }
  742. return false;
  743. }
  744. return true;
  745. }
  746. /**
  747. * Starts a mail transaction from the email address specified in
  748. * $from. Returns true if successful or false otherwise. If True
  749. * the mail transaction is started and then one or more Recipient
  750. * commands may be called followed by a Data command. This command
  751. * will send the message to the users terminal if they are logged
  752. * in and send them an email.
  753. *
  754. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  755. *
  756. * SMTP CODE SUCCESS: 250
  757. * SMTP CODE SUCCESS: 552,451,452
  758. * SMTP CODE SUCCESS: 500,501,502,421
  759. * @access public
  760. * @return bool
  761. */
  762. function SendAndMail($from) {
  763. $this->error = null; # so no confusion is caused
  764. if(!$this->connected()) {
  765. $this->error = array(
  766. "error" => "Called SendAndMail() without being connected");
  767. return false;
  768. }
  769. fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
  770. $rply = $this->get_lines();
  771. $code = substr($rply,0,3);
  772. if($this->do_debug >= 2) {
  773. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  774. }
  775. if($code != 250) {
  776. $this->error =
  777. array("error" => "SAML not accepted from server",
  778. "smtp_code" => $code,
  779. "smtp_msg" => substr($rply,4));
  780. if($this->do_debug >= 1) {
  781. echo "SMTP -> ERROR: " . $this->error["error"] .
  782. ": " . $rply . $this->CRLF;
  783. }
  784. return false;
  785. }
  786. return true;
  787. }
  788. /**
  789. * Starts a mail transaction from the email address specified in
  790. * $from. Returns true if successful or false otherwise. If True
  791. * the mail transaction is started and then one or more Recipient
  792. * commands may be called followed by a Data command. This command
  793. * will send the message to the users terminal if they are logged
  794. * in or mail it to them if they are not.
  795. *
  796. * Implements rfc 821: SOML <SP> FROM:<reverse-path> <CRLF>
  797. *
  798. * SMTP CODE SUCCESS: 250
  799. * SMTP CODE SUCCESS: 552,451,452
  800. * SMTP CODE SUCCESS: 500,501,502,421
  801. * @access public
  802. * @return bool
  803. */
  804. function SendOrMail($from) {
  805. $this->error = null; # so no confusion is caused
  806. if(!$this->connected()) {
  807. $this->error = array(
  808. "error" => "Called SendOrMail() without being connected");
  809. return false;
  810. }
  811. fputs($this->smtp_conn,"SOML FROM:" . $from . $this->CRLF);
  812. $rply = $this->get_lines();
  813. $code = substr($rply,0,3);
  814. if($this->do_debug >= 2) {
  815. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  816. }
  817. if($code != 250) {
  818. $this->error =
  819. array("error" => "SOML not accepted from server",
  820. "smtp_code" => $code,
  821. "smtp_msg" => substr($rply,4));
  822. if($this->do_debug >= 1) {
  823. echo "SMTP -> ERROR: " . $this->error["error"] .
  824. ": " . $rply . $this->CRLF;
  825. }
  826. return false;
  827. }
  828. return true;
  829. }
  830. /**
  831. * This is an optional command for SMTP that this class does not
  832. * support. This method is here to make the RFC821 Definition
  833. * complete for this class and __may__ be implimented in the future
  834. *
  835. * Implements from rfc 821: TURN <CRLF>
  836. *
  837. * SMTP CODE SUCCESS: 250
  838. * SMTP CODE FAILURE: 502
  839. * SMTP CODE ERROR : 500, 503
  840. * @access public
  841. * @return bool
  842. */
  843. function Turn() {
  844. $this->error = array("error" => "This method, TURN, of the SMTP ".
  845. "is not implemented");
  846. if($this->do_debug >= 1) {
  847. echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF;
  848. }
  849. return false;
  850. }
  851. /**
  852. * Verifies that the name is recognized by the server.
  853. * Returns false if the name could not be verified otherwise
  854. * the response from the server is returned.
  855. *
  856. * Implements rfc 821: VRFY <SP> <string> <CRLF>
  857. *
  858. * SMTP CODE SUCCESS: 250,251
  859. * SMTP CODE FAILURE: 550,551,553
  860. * SMTP CODE ERROR : 500,501,502,421
  861. * @access public
  862. * @return int
  863. */
  864. function Verify($name) {
  865. $this->error = null; # so no confusion is caused
  866. if(!$this->connected()) {
  867. $this->error = array(
  868. "error" => "Called Verify() without being connected");
  869. return false;
  870. }
  871. fputs($this->smtp_conn,"VRFY " . $name . $this->CRLF);
  872. $rply = $this->get_lines();
  873. $code = substr($rply,0,3);
  874. if($this->do_debug >= 2) {
  875. echo "SMTP -> FROM SERVER:" . $this->CRLF . $rply;
  876. }
  877. if($code != 250 && $code != 251) {
  878. $this->error =
  879. array("error" => "VRFY failed on name '$name'",
  880. "smtp_code" => $code,
  881. "smtp_msg" => substr($rply,4));
  882. if($this->do_debug >= 1) {
  883. echo "SMTP -> ERROR: " . $this->error["error"] .
  884. ": " . $rply . $this->CRLF;
  885. }
  886. return false;
  887. }
  888. return $rply;
  889. }
  890. /*******************************************************************
  891. * INTERNAL FUNCTIONS *
  892. ******************************************************************/
  893. /**
  894. * Read in as many lines as possible
  895. * either before eof or socket timeout occurs on the operation.
  896. * With SMTP we can tell if we have more lines to read if the
  897. * 4th character is '-' symbol. If it is a space then we don't
  898. * need to read anything else.
  899. * @access private
  900. * @return string
  901. */
  902. function get_lines() {
  903. $data = "";
  904. while($str = @fgets($this->smtp_conn,515)) {
  905. if($this->do_debug >= 4) {
  906. echo "SMTP -> get_lines(): \$data was \"$data\"" .
  907. $this->CRLF;
  908. echo "SMTP -> get_lines(): \$str is \"$str\"" .
  909. $this->CRLF;
  910. }
  911. $data .= $str;
  912. if($this->do_debug >= 4) {
  913. echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF;
  914. }
  915. # if the 4th character is a space then we are done reading
  916. # so just break the loop
  917. if(substr($str,3,1) == " ") { break; }
  918. }
  919. return $data;
  920. }
  921. }
  922. ?>