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