1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24:
25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
37:
38: 39: 40: 41: 42: 43: 44:
45:
46: class SMTP {
47: 48: 49: 50:
51: public $SMTP_PORT = 25;
52:
53: 54: 55: 56:
57: public $CRLF = "\r\n";
58:
59: 60: 61: 62:
63: public $do_debug;
64:
65: 66: 67: 68:
69: public $do_verp = false;
70:
71: 72: 73: 74:
75: public $Version = '5.2.1';
76:
77:
78:
79:
80:
81: private $smtp_conn;
82: private $error;
83: private $helo_rply;
84:
85: 86: 87: 88: 89:
90: public function __construct() {
91: $this->smtp_conn = 0;
92: $this->error = null;
93: $this->helo_rply = null;
94:
95: $this->do_debug = 0;
96: }
97:
98:
99:
100:
101:
102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114:
115: public function Connect($host, $port = 0, $tval = 30) {
116:
117: $this->error = null;
118:
119:
120: if($this->connected()) {
121:
122: $this->error = array("error" => "Already connected to a server");
123: return false;
124: }
125:
126: if(empty($port)) {
127: $port = $this->SMTP_PORT;
128: }
129:
130:
131: $this->smtp_conn = @fsockopen($host,
132: $port,
133: $errno,
134: $errstr,
135: $tval);
136:
137: if(empty($this->smtp_conn)) {
138: $this->error = array("error" => "Failed to connect to server",
139: "errno" => $errno,
140: "errstr" => $errstr);
141: if($this->do_debug >= 1) {
142: echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
143: }
144: return false;
145: }
146:
147:
148:
149: if(substr(PHP_OS, 0, 3) != "WIN")
150: socket_set_timeout($this->smtp_conn, $tval, 0);
151:
152:
153: $announce = $this->get_lines();
154:
155: if($this->do_debug >= 2) {
156: echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
157: }
158:
159: return true;
160: }
161:
162: 163: 164: 165: 166: 167: 168: 169: 170:
171: public function StartTLS() {
172: $this->error = null;
173:
174: if(!$this->connected()) {
175: $this->error = array("error" => "Called StartTLS() without being connected");
176: return false;
177: }
178:
179: fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
180:
181: $rply = $this->get_lines();
182: $code = substr($rply,0,3);
183:
184: if($this->do_debug >= 2) {
185: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
186: }
187:
188: if($code != 220) {
189: $this->error =
190: array("error" => "STARTTLS not accepted from server",
191: "smtp_code" => $code,
192: "smtp_msg" => substr($rply,4));
193: if($this->do_debug >= 1) {
194: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
195: }
196: return false;
197: }
198:
199:
200: if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
201: return false;
202: }
203:
204: return true;
205: }
206:
207: 208: 209: 210: 211: 212:
213: public function Authenticate($username, $password) {
214:
215: fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
216:
217: $rply = $this->get_lines();
218: $code = substr($rply,0,3);
219:
220: if($code != 334) {
221: $this->error =
222: array("error" => "AUTH not accepted from server",
223: "smtp_code" => $code,
224: "smtp_msg" => substr($rply,4));
225: if($this->do_debug >= 1) {
226: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
227: }
228: return false;
229: }
230:
231:
232: fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
233:
234: $rply = $this->get_lines();
235: $code = substr($rply,0,3);
236:
237: if($code != 334) {
238: $this->error =
239: array("error" => "Username not accepted from server",
240: "smtp_code" => $code,
241: "smtp_msg" => substr($rply,4));
242: if($this->do_debug >= 1) {
243: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
244: }
245: return false;
246: }
247:
248:
249: fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
250:
251: $rply = $this->get_lines();
252: $code = substr($rply,0,3);
253:
254: if($code != 235) {
255: $this->error =
256: array("error" => "Password not accepted from server",
257: "smtp_code" => $code,
258: "smtp_msg" => substr($rply,4));
259: if($this->do_debug >= 1) {
260: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
261: }
262: return false;
263: }
264:
265: return true;
266: }
267:
268: 269: 270: 271: 272:
273: public function Connected() {
274: if(!empty($this->smtp_conn)) {
275: $sock_status = socket_get_status($this->smtp_conn);
276: if($sock_status["eof"]) {
277:
278: if($this->do_debug >= 1) {
279: echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
280: }
281: $this->Close();
282: return false;
283: }
284: return true;
285: }
286: return false;
287: }
288:
289: 290: 291: 292: 293: 294: 295:
296: public function Close() {
297: $this->error = null;
298: $this->helo_rply = null;
299: if(!empty($this->smtp_conn)) {
300:
301: fclose($this->smtp_conn);
302: $this->smtp_conn = 0;
303: }
304: }
305:
306:
307:
308:
309:
310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328:
329: public function Data($msg_data) {
330: $this->error = null;
331:
332: if(!$this->connected()) {
333: $this->error = array(
334: "error" => "Called Data() without being connected");
335: return false;
336: }
337:
338: fputs($this->smtp_conn,"DATA" . $this->CRLF);
339:
340: $rply = $this->get_lines();
341: $code = substr($rply,0,3);
342:
343: if($this->do_debug >= 2) {
344: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
345: }
346:
347: if($code != 354) {
348: $this->error =
349: array("error" => "DATA command not accepted from server",
350: "smtp_code" => $code,
351: "smtp_msg" => substr($rply,4));
352: if($this->do_debug >= 1) {
353: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
354: }
355: return false;
356: }
357:
358: 359: 360: 361: 362: 363: 364: 365: 366: 367:
368:
369:
370: $msg_data = str_replace("\r\n","\n",$msg_data);
371: $msg_data = str_replace("\r","\n",$msg_data);
372: $lines = explode("\n",$msg_data);
373:
374: 375: 376: 377: 378: 379: 380: 381:
382:
383: $field = substr($lines[0],0,strpos($lines[0],":"));
384: $in_headers = false;
385: if(!empty($field) && !strstr($field," ")) {
386: $in_headers = true;
387: }
388:
389: $max_line_length = 998;
390:
391: while(list(,$line) = @each($lines)) {
392: $lines_out = null;
393: if($line == "" && $in_headers) {
394: $in_headers = false;
395: }
396:
397: while(strlen($line) > $max_line_length) {
398: $pos = strrpos(substr($line,0,$max_line_length)," ");
399:
400:
401: if(!$pos) {
402: $pos = $max_line_length - 1;
403: $lines_out[] = substr($line,0,$pos);
404: $line = substr($line,$pos);
405: } else {
406: $lines_out[] = substr($line,0,$pos);
407: $line = substr($line,$pos + 1);
408: }
409:
410: 411: 412:
413: if($in_headers) {
414: $line = "\t" . $line;
415: }
416: }
417: $lines_out[] = $line;
418:
419:
420: while(list(,$line_out) = @each($lines_out)) {
421: if(strlen($line_out) > 0)
422: {
423: if(substr($line_out, 0, 1) == ".") {
424: $line_out = "." . $line_out;
425: }
426: }
427: fputs($this->smtp_conn,$line_out . $this->CRLF);
428: }
429: }
430:
431:
432: fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
433:
434: $rply = $this->get_lines();
435: $code = substr($rply,0,3);
436:
437: if($this->do_debug >= 2) {
438: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
439: }
440:
441: if($code != 250) {
442: $this->error =
443: array("error" => "DATA not accepted from server",
444: "smtp_code" => $code,
445: "smtp_msg" => substr($rply,4));
446: if($this->do_debug >= 1) {
447: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
448: }
449: return false;
450: }
451: return true;
452: }
453:
454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465:
466: public function Hello($host = '') {
467: $this->error = null;
468:
469: if(!$this->connected()) {
470: $this->error = array(
471: "error" => "Called Hello() without being connected");
472: return false;
473: }
474:
475:
476: if(empty($host)) {
477:
478: $host = "localhost";
479: }
480:
481:
482: if(!$this->SendHello("EHLO", $host)) {
483: if(!$this->SendHello("HELO", $host)) {
484: return false;
485: }
486: }
487:
488: return true;
489: }
490:
491: 492: 493: 494: 495:
496: private function SendHello($hello, $host) {
497: fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
498:
499: $rply = $this->get_lines();
500: $code = substr($rply,0,3);
501:
502: if($this->do_debug >= 2) {
503: echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
504: }
505:
506: if($code != 250) {
507: $this->error =
508: array("error" => $hello . " not accepted from server",
509: "smtp_code" => $code,
510: "smtp_msg" => substr($rply,4));
511: if($this->do_debug >= 1) {
512: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
513: }
514: return false;
515: }
516:
517: $this->helo_rply = $rply;
518:
519: return true;
520: }
521:
522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535:
536: public function Mail($from) {
537: $this->error = null;
538:
539: if(!$this->connected()) {
540: $this->error = array(
541: "error" => "Called Mail() without being connected");
542: return false;
543: }
544:
545: $useVerp = ($this->do_verp ? "XVERP" : "");
546: fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
547:
548: $rply = $this->get_lines();
549: $code = substr($rply,0,3);
550:
551: if($this->do_debug >= 2) {
552: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
553: }
554:
555: if($code != 250) {
556: $this->error =
557: array("error" => "MAIL not accepted from server",
558: "smtp_code" => $code,
559: "smtp_msg" => substr($rply,4));
560: if($this->do_debug >= 1) {
561: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
562: }
563: return false;
564: }
565: return true;
566: }
567:
568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578:
579: public function Quit($close_on_error = true) {
580: $this->error = null;
581:
582: if(!$this->connected()) {
583: $this->error = array(
584: "error" => "Called Quit() without being connected");
585: return false;
586: }
587:
588:
589: fputs($this->smtp_conn,"quit" . $this->CRLF);
590:
591:
592: $byemsg = $this->get_lines();
593:
594: if($this->do_debug >= 2) {
595: echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
596: }
597:
598: $rval = true;
599: $e = null;
600:
601: $code = substr($byemsg,0,3);
602: if($code != 221) {
603:
604: $e = array("error" => "SMTP server rejected quit command",
605: "smtp_code" => $code,
606: "smtp_rply" => substr($byemsg,4));
607: $rval = false;
608: if($this->do_debug >= 1) {
609: echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
610: }
611: }
612:
613: if(empty($e) || $close_on_error) {
614: $this->Close();
615: }
616:
617: return $rval;
618: }
619:
620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631:
632: public function Recipient($to) {
633: $this->error = null;
634:
635: if(!$this->connected()) {
636: $this->error = array(
637: "error" => "Called Recipient() without being connected");
638: return false;
639: }
640:
641: fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
642:
643: $rply = $this->get_lines();
644: $code = substr($rply,0,3);
645:
646: if($this->do_debug >= 2) {
647: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
648: }
649:
650: if($code != 250 && $code != 251) {
651: $this->error =
652: array("error" => "RCPT not accepted from server",
653: "smtp_code" => $code,
654: "smtp_msg" => substr($rply,4));
655: if($this->do_debug >= 1) {
656: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
657: }
658: return false;
659: }
660: return true;
661: }
662:
663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674:
675: public function Reset() {
676: $this->error = null;
677:
678: if(!$this->connected()) {
679: $this->error = array(
680: "error" => "Called Reset() without being connected");
681: return false;
682: }
683:
684: fputs($this->smtp_conn,"RSET" . $this->CRLF);
685:
686: $rply = $this->get_lines();
687: $code = substr($rply,0,3);
688:
689: if($this->do_debug >= 2) {
690: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
691: }
692:
693: if($code != 250) {
694: $this->error =
695: array("error" => "RSET failed",
696: "smtp_code" => $code,
697: "smtp_msg" => substr($rply,4));
698: if($this->do_debug >= 1) {
699: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
700: }
701: return false;
702: }
703:
704: return true;
705: }
706:
707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722:
723: public function SendAndMail($from) {
724: $this->error = null;
725:
726: if(!$this->connected()) {
727: $this->error = array(
728: "error" => "Called SendAndMail() without being connected");
729: return false;
730: }
731:
732: fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
733:
734: $rply = $this->get_lines();
735: $code = substr($rply,0,3);
736:
737: if($this->do_debug >= 2) {
738: echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
739: }
740:
741: if($code != 250) {
742: $this->error =
743: array("error" => "SAML not accepted from server",
744: "smtp_code" => $code,
745: "smtp_msg" => substr($rply,4));
746: if($this->do_debug >= 1) {
747: echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
748: }
749: return false;
750: }
751: return true;
752: }
753:
754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766:
767: public function Turn() {
768: $this->error = array("error" => "This method, TURN, of the SMTP ".
769: "is not implemented");
770: if($this->do_debug >= 1) {
771: echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
772: }
773: return false;
774: }
775:
776: 777: 778: 779: 780:
781: public function getError() {
782: return $this->error;
783: }
784:
785:
786:
787:
788:
789: 790: 791: 792: 793: 794: 795: 796: 797:
798: private function get_lines() {
799: $data = "";
800: while(!feof($this->smtp_conn)) {
801: $str = @fgets($this->smtp_conn,515);
802: if($this->do_debug >= 4) {
803: echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
804: echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
805: }
806: $data .= $str;
807: if($this->do_debug >= 4) {
808: echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
809: }
810:
811: if(substr($str,3,1) == " ") { break; }
812: }
813: return $data;
814: }
815:
816: }
817:
818: ?>
819: