// // This file is part of IlohaMail. // IlohaMail is free software released under the GPL // license. See enclosed file COPYING for details, // or see http://www.fsf.org/copyleft/gpl.html // ///////////////////////////////////////////////////////// /******************************************************** AUTHOR: Ryo Chijiiwa FILE: include/smtp.php PURPOSE: Provide SMTP functionality using pure PHP. PRE-CONDITIONS: The functions here require a SMTP server configured to allow relaying. POST-CONDITIONS: The following global variables are returned: $smtp_errornum - error number, 0 if successful $smtp_error - error message(s) $SMTP_TYPE - Optional COMMENTS: The optional $smtp_message_file can be used for sending extremely large messages. Storing large messages in a variable will consume whatever amount of memory required, which may be more than is available if dealing with messages with large attachments. By storing them in a file, it becomes possible to read/send bits at a time, drastically reducing memory useage. This library only provides bare-bones SMTP functionality. It is up to the parent code to form valid RFC822 (MIME) messages. ********************************************************/ //set some global constants if (strcasecmp($SMTP_TYPE, "courier")==0){ $SMTP_REPLY_DELIM = "-"; $SMTP_DATA_REPLY = 250; }else{ $SMTP_REPLY_DELIM = " "; $SMTP_DATA_REPLY = 354; } /* fgets replacement that's multi-line aware */ function smtp_get_response($fp, $len){ $end = false; do{ $line = chop(fgets($fp, 5120)); // echo "SMTP:".$line."
\n"; flush(); if ((strlen($line)==3) || ($line[3]==' ')) $end = true; }while(!$end); return $line; } function smtp_check_reply($reply){ global $smtp_error; global $SMTP_REPLY_DELIM; $a = explode($SMTP_REPLY_DELIM, chop($reply)); if (count($a) >= 1){ if ($a[0]==250||$a[0]==354) return true; else{ $smtp_error .= $reply."\n"; } }else{ $smtp_error .= "Invalid SMTP response line: $reply\n"; } return false; } function smtp_split($str){ $result = array(); $pos = strpos($str, " "); if ($pos===false){ $result[0] = $str; }else{ $result[0] = substr($str, 0, $pos); $result[1] = substr($str, $pos+1); } return $result; } function smtp_ehlo(&$conn, $host){ $result = ""; fputs($conn, "EHLO $host\r\n"); //echo "Sent: EHLO $host\n"; flush(); do{ $line = fgets($conn, 2048); //echo "Got: $line"; flush(); $a = explode(" ", $line); if ($a[0]=="250-AUTH") $result .= substr($line, 9); }while(!is_numeric($a[0])); if ($a[0]==250) return $result; else return $a[0]; } function smtp_auth_login(&$conn, $user, $pass){ $auth["username"] = base64_encode($user); $auth["password"] = base64_encode($pass); fputs($conn, "AUTH LOGIN\r\n"); //echo "Sent: AUTH LOGIN\n"; flush(); //get first line $line = smtp_get_response($conn, 1024); //echo "AUTH_LOGIN << $line"; flush(); $parts = smtp_split($line); //valid reply? if (($parts[0]!=334) || (empty($parts[1]))) return false; //send data $prompt = eregi_replace("[^a-z]", "", strtolower(base64_decode($parts[1]))); fputs($conn, $auth[$prompt]."\r\n"); //echo "AUT_LOGIN >> ".$auth[$prompt]."\n"; flush(); //get second line $line = smtp_get_response($conn, 1024); //echo "AUTH_LOGIN << $line"; flush(); $parts = smtp_split($line); //valid reply? if (($parts[0]!=334) || (empty($parts[1]))) return false; $prompt = eregi_replace("[^a-z]", "", strtolower(base64_decode($parts[1]))); fputs($conn, $auth[$prompt]."\r\n"); //echo "AUT_LOGIN >> ".$auth[$prompt]."\n"; flush(); $line = smtp_get_response($conn, 1024); //echo "AUTH_LOGIN << $line"; flush(); $parts = smtp_split($line); return ($parts[0]==235); } function smtp_connect($host, $port, $user, $pass){ global $smtp_errornum; global $smtp_error; //auth user? global $SMTP_USER, $SMTP_PASSWORD; if ((!empty($SMTP_USER)) && (!empty($SMTP_PASSWORD))){ $user = $SMTP_USER; $pass = $SMTP_PASSWORD; } // echo "User: $user
\n"; //figure out auth mode global $AUTH_MODE; $auth_mode = $AUTH_MODE["smtp"]; if (empty($auth_mode)) $auth_mode = "none"; if (empty($user) || empty($pass)) $auth_mode = "none"; // echo "authmode: $auth_mode
\n"; flush(); //initialize defaults if (empty($host)) $host = "localhost"; if (empty($port)) $port = 25; // echo "Connecting to $host:$port
\n"; flush(); //connect to SMTP server $conn = fsockopen($host, $port); if (!$conn){ //echo "fsockopen failed\n"; $smtp_error = "Couldn't connect to $host:$port
\n"; return false; } //read greeting $greeting = smtp_get_response($conn, 1024); // echo "Connected: $greeting
\n"; flush(); if (($auth_mode=="check") || ($auth_mode=="auth")){ // echo "Trying EHLO
\n"; flush(); $auth_modes = smtp_ehlo($conn, $_SERVER["SERVER_NAME"]); // echo "smtp_ehlo returned: $auth_modes
\n"; flush(); if ($auth_modes===false){ $smtp_error = "EHLO failed\n"; $conn = false; }else if (stristr($auth_modes, "LOGIN")!==false){ echo "trying AUTH LOGIN\n"; flush(); if (!smtp_auth_login($conn, $user, $pass)){ //echo "CONN: AUTH_LOGIN failed\n"; flush(); $conn = false; } //echo "Conn after LOGIN: $conn
\n"; flush(); } }else{ fputs($conn, "HELO ".$_SERVER["SERVER_NAME"]."\r\n"); $line = smtp_get_response($conn, 1024); if (!smtp_check_reply($line)){ $conn = false; $smtp_error .= $line."\n"; } // echo "after HELO: $conn
\n"; flush(); } return $conn; } function smtp_close($conn){ fclose($conn); } function smtp_mail($conn, $from, $recipients, $message, $is_file){ global $smtp_errornum; global $smtp_error; global $SMTP_DATA_REPLY; //check recipients and sender addresses if ((count($recipients)==0) || (!is_array($recipients))){ $smtp_errornum = -1; $smtp_error .= "Recipients list is empty\n"; return false; } if (empty($from)){ $smtp_errornum = -2; $smtp_error .= "From address unspecified\n"; return false; } if (!$conn){ $smtp_errornum = -3; $smtp_error .= "Invalid connection\n"; } if (!ereg("^<", $from)) $from = "<".$from; if (!ereg(">$", $from)) $from = $from.">"; //send MAIL FROM command $command = "MAIL FROM: $from\r\n"; // echo nl2br(htmlspecialchars($command)); fputs($conn, $command); if (smtp_check_reply(smtp_get_response($conn, 1024))){ //send RCPT TO commands, count valid recipients $num_recipients = 0; while ( list($k, $recipient) = each($recipients) ){ $command = "RCPT TO: $recipient\r\n"; fputs($conn, $command); $reply = smtp_check_reply(smtp_get_response($conn, 1024)); if ($reply) $num_recipients++; else $smtp_error .= $reply."\n"; } //error out if no valid recipiets if ($num_recipients == 0){ $smtp_errornum = -1; $smtp_error .= "No valid recipients\n"; return false; } //send DATA command fputs($conn, "DATA\r\n"); $reply = chop(smtp_get_response($conn, 1024)); $a = explode(" ", $reply); //error out if DATA command ill received if ($a[0]!=$SMTP_DATA_REPLY){ $smtp_errornum = -4; $smtp_error .= $reply; return false; } //send data if ($is_file){ //if message file, open file $fp = false; if (file_exists(realpath($message))) $fp = fopen($message, "rb"); if (!$fp) { $smtp_errornum = -4; $smtp_error .= "Invlid message file\n"; return false; } //send file while(!feof($fp)){ $buffer = chop(fgets($fp, 4096), "\r\n"); fputs($conn, $buffer."\r\n"); } fclose($fp); fputs($conn, "\r\n.\r\n"); return smtp_check_reply(smtp_get_response($conn, 1024)); }else{ //else, send message $message = str_replace("\r\n", "\n", $message); $message = str_replace("\n", "\r\n", $message); $message = str_replace("\r\n.\r\n", "\r\n..\r\n", $message); fputs($conn, $message); fputs($conn, "\r\n.\r\n"); return smtp_check_reply(smtp_get_response($conn, 1024)); } } return false; } function smtp_ExplodeQuotedString($delimiter, $string){ $quotes=explode("\"", $string); while ( list($key, $val) = each($quotes)) if (($key % 2) == 1) $quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]); $string=implode("\"", $quotes); $result=explode($delimiter, $string); while ( list($key, $val) = each($result) ) $result[$key] = str_replace("_!@!_", $delimiter, $result[$key]); return $result; } function smtp_expand($str){ $addresses = array(); $recipients = smtp_ExplodeQuotedString(",", $str); reset($recipients); while ( list($k, $recipient) = each($recipients) ){ $a = explode(" ", $recipient); while ( list($k2, $word) = each($a) ){ if ((strpos($word, "@") > 0) && (strpos($word, "\"")===false)){ if (!ereg("^<", $word)) $word = "<".$word; if (!ereg(">$", $word)) $word = $word.">"; if (in_array($word, $addresses)===false) array_push($addresses, $word); } } } return $addresses; } ?>