119 switch ($this->Debugoutput) {
125 echo htmlentities(preg_replace(
'/[\r\n]+/',
'', $str), ENT_QUOTES,
'UTF-8').
"<br>\n";
140 $this->smtp_conn = 0;
142 $this->helo_rply = null;
163 public function Connect($host, $port = 0, $timeout = 30, $options = array()) {
168 if($this->connected()) {
170 $this->error = array(
'error' =>
'Already connected to a server');
181 $socket_context = stream_context_create($options);
183 $this->smtp_conn = @stream_socket_client($host.
":".$port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $socket_context);
186 if(empty($this->smtp_conn)) {
187 $this->error = array(
'error' =>
'Failed to connect to server',
189 'errstr' => $errstr);
190 if($this->do_debug >= 1) {
191 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
": $errstr ($errno)");
198 if(substr(PHP_OS, 0, 3) !=
'WIN') {
199 $max = ini_get(
'max_execution_time');
200 if ($max != 0 && $timeout > $max) {
201 @set_time_limit($timeout);
203 stream_set_timeout($this->smtp_conn, $timeout, 0);
209 if($this->do_debug >= 2) {
210 $this->
edebug(
'SMTP -> FROM SERVER:' . $announce);
226 $this->error = null; # to avoid confusion
228 if(!$this->connected()) {
229 $this->error = array(
'error' =>
'Called StartTLS() without being connected');
236 $code = substr($rply, 0, 3);
238 if($this->do_debug >= 2) {
239 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
244 array(
'error' =>
'STARTTLS not accepted from server',
245 'smtp_code' => $code,
246 'smtp_msg' => substr($rply, 4));
247 if($this->do_debug >= 1) {
248 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
254 if(!stream_socket_enable_crypto($this->smtp_conn,
true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
272 public function Authenticate($username, $password, $authtype=
'LOGIN', $realm=
'', $workstation=
'') {
273 if (empty($authtype)) {
283 $code = substr($rply, 0, 3);
287 array(
'error' =>
'AUTH not accepted from server',
288 'smtp_code' => $code,
289 'smtp_msg' => substr($rply, 4));
290 if($this->do_debug >= 1) {
291 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
296 $this->
client_send(base64_encode(
"\0".$username.
"\0".$password) . $this->CRLF);
299 $code = substr($rply, 0, 3);
303 array(
'error' =>
'Authentication not accepted from server',
304 'smtp_code' => $code,
305 'smtp_msg' => substr($rply, 4));
306 if($this->do_debug >= 1) {
307 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
317 $code = substr($rply, 0, 3);
321 array(
'error' =>
'AUTH not accepted from server',
322 'smtp_code' => $code,
323 'smtp_msg' => substr($rply, 4));
324 if($this->do_debug >= 1) {
325 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
331 $this->
client_send(base64_encode($username) . $this->CRLF);
334 $code = substr($rply, 0, 3);
338 array(
'error' =>
'Username not accepted from server',
339 'smtp_code' => $code,
340 'smtp_msg' => substr($rply, 4));
341 if($this->do_debug >= 1) {
342 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
348 $this->
client_send(base64_encode($password) . $this->CRLF);
351 $code = substr($rply, 0, 3);
355 array(
'error' =>
'Password not accepted from server',
356 'smtp_code' => $code,
357 'smtp_msg' => substr($rply, 4));
358 if($this->do_debug >= 1) {
359 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
372 if (file_exists(
'extras/ntlm_sasl_client.php')) {
373 require_once
'extras/ntlm_sasl_client.php';
375 $temp =
new stdClass();
376 $ntlm_client =
new ntlm_sasl_client_class;
377 if(! $ntlm_client->Initialize($temp)){
378 $this->error = array(
'error' => $temp->error);
379 if($this->do_debug >= 1) {
380 $this->
edebug(
'You need to enable some modules in your php.ini file: ' . $this->error[
'error']);
384 $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);
386 $this->
client_send(
'AUTH NTLM ' . base64_encode($msg1) . $this->CRLF);
389 $code = substr($rply, 0, 3);
393 array(
'error' =>
'AUTH not accepted from server',
394 'smtp_code' => $code,
395 'smtp_msg' => substr($rply, 4));
396 if($this->do_debug >= 1) {
397 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
402 $challenge = substr($rply, 3);
403 $challenge = base64_decode($challenge);
404 $ntlm_res = $ntlm_client->NTLMResponse(substr($challenge, 24, 8), $password);
405 $msg3 = $ntlm_client->TypeMsg3($ntlm_res, $username, $realm, $workstation);
407 $this->
client_send(base64_encode($msg3) . $this->CRLF);
410 $code = substr($rply, 0, 3);
414 array(
'error' =>
'Could not authenticate',
415 'smtp_code' => $code,
416 'smtp_msg' => substr($rply, 4));
417 if($this->do_debug >= 1) {
418 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
428 $code = substr($rply, 0, 3);
432 array(
'error' =>
'AUTH not accepted from server',
433 'smtp_code' => $code,
434 'smtp_msg' => substr($rply, 4));
435 if($this->do_debug >= 1) {
436 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
442 $challenge = base64_decode(substr($rply, 4));
445 $response = $username .
' ' . $this->
hmac($challenge, $password);
448 $this->
client_send(base64_encode($response) . $this->CRLF);
451 $code = substr($rply, 0, 3);
455 array(
'error' =>
'Credentials not accepted from server',
456 'smtp_code' => $code,
457 'smtp_msg' => substr($rply, 4));
458 if($this->do_debug >= 1) {
459 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
475 protected function hmac($data, $key) {
476 if (function_exists(
'hash_hmac')) {
477 return hash_hmac(
'md5', $data, $key);
488 if (strlen($key) > $b) {
489 $key = pack(
'H*', md5($key));
491 $key = str_pad($key, $b, chr(0x00));
492 $ipad = str_pad(
'', $b, chr(0x36));
493 $opad = str_pad(
'', $b, chr(0x5c));
494 $k_ipad = $key ^ $ipad ;
495 $k_opad = $key ^ $opad;
497 return md5($k_opad . pack(
'H*', md5($k_ipad . $data)));
506 if(!empty($this->smtp_conn)) {
507 $sock_status = stream_get_meta_data($this->smtp_conn);
508 if($sock_status[
'eof']) {
510 if($this->do_debug >= 1) {
511 $this->
edebug(
'SMTP -> NOTICE: EOF caught while checking if connected');
530 $this->helo_rply = null;
531 if(!empty($this->smtp_conn)) {
533 fclose($this->smtp_conn);
534 $this->smtp_conn = 0;
562 public function Data($msg_data) {
565 if(!$this->connected()) {
566 $this->error = array(
567 'error' =>
'Called Data() without being connected');
574 $code = substr($rply, 0, 3);
576 if($this->do_debug >= 2) {
577 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
582 array(
'error' =>
'DATA command not accepted from server',
583 'smtp_code' => $code,
584 'smtp_msg' => substr($rply, 4));
585 if($this->do_debug >= 1) {
586 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
603 $msg_data = str_replace(
"\r\n",
"\n", $msg_data);
604 $msg_data = str_replace(
"\r",
"\n", $msg_data);
605 $lines = explode(
"\n", $msg_data);
616 $field = substr($lines[0], 0, strpos($lines[0],
':'));
618 if(!empty($field) && !strstr($field,
' ')) {
622 $max_line_length = 998;
624 while(list(, $line) = @each($lines)) {
626 if($line ==
'' && $in_headers) {
630 while(strlen($line) > $max_line_length) {
631 $pos = strrpos(substr($line, 0, $max_line_length),
' ');
635 $pos = $max_line_length - 1;
636 $lines_out[] = substr($line, 0, $pos);
637 $line = substr($line, $pos);
639 $lines_out[] = substr($line, 0, $pos);
640 $line = substr($line, $pos + 1);
647 $line =
"\t" . $line;
650 $lines_out[] = $line;
653 while(list(, $line_out) = @each($lines_out)) {
654 if(strlen($line_out) > 0)
656 if(substr($line_out, 0, 1) ==
'.') {
657 $line_out =
'.' . $line_out;
665 $this->
client_send($this->CRLF .
'.' . $this->CRLF);
668 $code = substr($rply, 0, 3);
670 if($this->do_debug >= 2) {
671 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
676 array(
'error' =>
'DATA not accepted from server',
677 'smtp_code' => $code,
678 'smtp_msg' => substr($rply, 4));
679 if($this->do_debug >= 1) {
680 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
703 if(!$this->connected()) {
704 $this->error = array(
705 'error' =>
'Called Hello() without being connected');
733 $this->
client_send($hello .
' ' . $host . $this->CRLF);
736 $code = substr($rply, 0, 3);
738 if($this->do_debug >= 2) {
739 $this->
edebug(
'SMTP -> FROM SERVER: ' . $rply);
744 array(
'error' => $hello .
' not accepted from server',
745 'smtp_code' => $code,
746 'smtp_msg' => substr($rply, 4));
747 if($this->do_debug >= 1) {
748 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
753 $this->helo_rply = $rply;
776 if(!$this->connected()) {
777 $this->error = array(
778 'error' =>
'Called Mail() without being connected');
782 $useVerp = ($this->do_verp ?
' XVERP' :
'');
783 $this->
client_send(
'MAIL FROM:<' . $from .
'>' . $useVerp . $this->CRLF);
786 $code = substr($rply, 0, 3);
788 if($this->do_debug >= 2) {
789 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
794 array(
'error' =>
'MAIL not accepted from server',
795 'smtp_code' => $code,
796 'smtp_msg' => substr($rply, 4));
797 if($this->do_debug >= 1) {
798 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
817 public function Quit($close_on_error =
true) {
820 if(!$this->connected()) {
821 $this->error = array(
822 'error' =>
'Called Quit() without being connected');
832 if($this->do_debug >= 2) {
833 $this->
edebug(
'SMTP -> FROM SERVER:' . $byemsg);
839 $code = substr($byemsg, 0, 3);
842 $e = array(
'error' =>
'SMTP server rejected quit command',
843 'smtp_code' => $code,
844 'smtp_rply' => substr($byemsg, 4));
846 if($this->do_debug >= 1) {
847 $this->
edebug(
'SMTP -> ERROR: ' . $e[
'error'] .
': ' . $byemsg);
851 if(empty($e) || $close_on_error) {
874 if(!$this->connected()) {
875 $this->error = array(
876 'error' =>
'Called Recipient() without being connected');
880 $this->
client_send(
'RCPT TO:<' . $to .
'>' . $this->CRLF);
883 $code = substr($rply, 0, 3);
885 if($this->do_debug >= 2) {
886 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
889 if($code != 250 && $code != 251) {
891 array(
'error' =>
'RCPT not accepted from server',
892 'smtp_code' => $code,
893 'smtp_msg' => substr($rply, 4));
894 if($this->do_debug >= 1) {
895 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
917 if(!$this->connected()) {
918 $this->error = array(
'error' =>
'Called Reset() without being connected');
925 $code = substr($rply, 0, 3);
927 if($this->do_debug >= 2) {
928 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
933 array(
'error' =>
'RSET failed',
934 'smtp_code' => $code,
935 'smtp_msg' => substr($rply, 4));
936 if($this->do_debug >= 1) {
937 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
965 if(!$this->connected()) {
966 $this->error = array(
967 'error' =>
'Called SendAndMail() without being connected');
971 $this->
client_send(
'SAML FROM:' . $from . $this->CRLF);
974 $code = substr($rply, 0, 3);
976 if($this->do_debug >= 2) {
977 $this->
edebug(
'SMTP -> FROM SERVER:' . $rply);
982 array(
'error' =>
'SAML not accepted from server',
983 'smtp_code' => $code,
984 'smtp_msg' => substr($rply, 4));
985 if($this->do_debug >= 1) {
986 $this->
edebug(
'SMTP -> ERROR: ' . $this->error[
'error'] .
': ' . $rply);
1007 $this->error = array(
'error' =>
'This method, TURN, of the SMTP '.
1008 'is not implemented');
1009 if($this->do_debug >= 1) {
1010 $this->
edebug(
'SMTP -> NOTICE: ' . $this->error[
'error']);
1022 if ($this->do_debug >= 1) {
1023 $this->
edebug(
"CLIENT -> SMTP: $data");
1025 return fwrite($this->smtp_conn, $data);
1054 if (!is_resource($this->smtp_conn)) {
1057 stream_set_timeout($this->smtp_conn, $this->Timeout);
1058 if ($this->Timelimit > 0) {
1061 while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
1062 $str = @fgets($this->smtp_conn, 515);
1063 if($this->do_debug >= 4) {
1064 $this->
edebug(
"SMTP -> get_lines(): \$data was \"$data\"");
1065 $this->
edebug(
"SMTP -> get_lines(): \$str is \"$str\"");
1068 if($this->do_debug >= 4) {
1069 $this->
edebug(
"SMTP -> get_lines(): \$data is \"$data\"");
1072 if(substr($str, 3, 1) ==
' ') {
break; }
1074 $info = stream_get_meta_data($this->smtp_conn);
1075 if ($info[
'timed_out']) {
1076 if($this->do_debug >= 4) {
1077 $this->
edebug(
'SMTP -> get_lines(): timed-out (' . $this->Timeout .
' seconds)');
1083 if (time() > $endtime) {
1084 if($this->do_debug >= 4) {
1085 $this->
edebug(
'SMTP -> get_lines(): timelimit reached (' . $this->Timelimit .
' seconds)');