Path: blob/master/externals/phpmailer/class.smtp.php
12241 views
<?php1/*~ class.smtp.php2.---------------------------------------------------------------------------.3| Software: PHPMailer - PHP email class |4| Version: 5.1 |5| Contact: via sourceforge.net support pages (also www.codeworxtech.com) |6| Info: http://phpmailer.sourceforge.net |7| Support: http://sourceforge.net/projects/phpmailer/ |8| ------------------------------------------------------------------------- |9| Admin: Andy Prevost (project admininistrator) |10| Authors: Andy Prevost (codeworxtech) [email protected] |11| : Marcus Bointon (coolbru) [email protected] |12| Founder: Brent R. Matzelle (original founder) |13| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |14| Copyright (c) 2001-2003, Brent R. Matzelle |15| ------------------------------------------------------------------------- |16| License: Distributed under the Lesser General Public License (LGPL) |17| http://www.gnu.org/copyleft/lesser.html |18| This program is distributed in the hope that it will be useful - WITHOUT |19| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |20| FITNESS FOR A PARTICULAR PURPOSE. |21| ------------------------------------------------------------------------- |22| We offer a number of paid services (www.codeworxtech.com): |23| - Web Hosting on highly optimized fast and secure servers |24| - Technology Consulting |25| - Oursourcing (highly qualified programmers and graphic designers) |26'---------------------------------------------------------------------------'27*/2829/**30* PHPMailer - PHP SMTP email transport class31* NOTE: Designed for use with PHP version 5 and up32* @package PHPMailer33* @author Andy Prevost34* @author Marcus Bointon35* @copyright 2004 - 2008 Andy Prevost36* @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)37* @version $Id: class.smtp.php 444 2009-05-05 11:22:26Z coolbru $38*/3940/**41* SMTP is rfc 821 compliant and implements all the rfc 821 SMTP42* commands except TURN which will always return a not implemented43* error. SMTP also provides some utility methods for sending mail44* to an SMTP server.45* original author: Chris Ryan46*/4748class SMTP {49/**50* SMTP server port51* @var int52*/53public $SMTP_PORT = 25;5455/**56* SMTP reply line ending57* @var string58*/59public $CRLF = "\r\n";6061/**62* Sets whether debugging is turned on63* @var bool64*/65public $do_debug; // the level of debug to perform6667/**68* Sets VERP use on/off (default is off)69* @var bool70*/71public $do_verp = false;7273/////////////////////////////////////////////////74// PROPERTIES, PRIVATE AND PROTECTED75/////////////////////////////////////////////////7677private $smtp_conn; // the socket to the server78private $error; // error if any on the last call79private $helo_rply; // the reply the server sent to us for HELO8081/**82* Initialize the class so that the data is in a known state.83* @access public84* @return void85*/86public function __construct() {87$this->smtp_conn = 0;88$this->error = null;89$this->helo_rply = null;9091$this->do_debug = 0;92}9394/////////////////////////////////////////////////95// CONNECTION FUNCTIONS96/////////////////////////////////////////////////9798/**99* Connect to the server specified on the port specified.100* If the port is not specified use the default SMTP_PORT.101* If tval is specified then a connection will try and be102* established with the server for that number of seconds.103* If tval is not specified the default is 30 seconds to104* try on the connection.105*106* SMTP CODE SUCCESS: 220107* SMTP CODE FAILURE: 421108* @access public109* @return bool110*/111public function Connect($host, $port = 0, $tval = 30) {112// set the error val to null so there is no confusion113$this->error = null;114115// make sure we are __not__ connected116if($this->connected()) {117// already connected, generate error118$this->error = array("error" => "Already connected to a server");119return false;120}121122if(empty($port)) {123$port = $this->SMTP_PORT;124}125126// connect to the smtp server127$this->smtp_conn = @fsockopen($host, // the host of the server128$port, // the port to use129$errno, // error number if any130$errstr, // error message if any131$tval); // give up after ? secs132// verify we connected properly133if(empty($this->smtp_conn)) {134$this->error = array("error" => "Failed to connect to server",135"errno" => $errno,136"errstr" => $errstr);137if($this->do_debug >= 1) {138echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';139}140return false;141}142143// SMTP server can take longer to respond, give longer timeout for first read144// Windows does not have support for this timeout function145if(substr(PHP_OS, 0, 3) != "WIN")146socket_set_timeout($this->smtp_conn, $tval, 0);147148// get any announcement149$announce = $this->get_lines();150151if($this->do_debug >= 2) {152echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';153}154155return true;156}157158/**159* Initiate a TLS communication with the server.160*161* SMTP CODE 220 Ready to start TLS162* SMTP CODE 501 Syntax error (no parameters allowed)163* SMTP CODE 454 TLS not available due to temporary reason164* @access public165* @return bool success166*/167public function StartTLS() {168$this->error = null; # to avoid confusion169170if(!$this->connected()) {171$this->error = array("error" => "Called StartTLS() without being connected");172return false;173}174175fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);176177$rply = $this->get_lines();178$code = substr($rply,0,3);179180if($this->do_debug >= 2) {181echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';182}183184if($code != 220) {185$this->error =186array("error" => "STARTTLS not accepted from server",187"smtp_code" => $code,188"smtp_msg" => substr($rply,4));189if($this->do_debug >= 1) {190echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';191}192return false;193}194195// Begin encrypted connection196if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {197return false;198}199200return true;201}202203/**204* Performs SMTP authentication. Must be run after running the205* Hello() method. Returns true if successfully authenticated.206* @access public207* @return bool208*/209public function Authenticate($username, $password) {210// Start authentication211fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);212213$rply = $this->get_lines();214$code = substr($rply,0,3);215216if($code != 334) {217$this->error =218array("error" => "AUTH not accepted from server",219"smtp_code" => $code,220"smtp_msg" => substr($rply,4));221if($this->do_debug >= 1) {222echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';223}224return false;225}226227// Send encoded username228fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);229230$rply = $this->get_lines();231$code = substr($rply,0,3);232233if($code != 334) {234$this->error =235array("error" => "Username not accepted from server",236"smtp_code" => $code,237"smtp_msg" => substr($rply,4));238if($this->do_debug >= 1) {239echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';240}241return false;242}243244// Send encoded password245fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);246247$rply = $this->get_lines();248$code = substr($rply,0,3);249250if($code != 235) {251$this->error =252array("error" => "Password not accepted from server",253"smtp_code" => $code,254"smtp_msg" => substr($rply,4));255if($this->do_debug >= 1) {256echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';257}258return false;259}260261return true;262}263264/**265* Returns true if connected to a server otherwise false266* @access public267* @return bool268*/269public function Connected() {270if(!empty($this->smtp_conn)) {271$sock_status = socket_get_status($this->smtp_conn);272if($sock_status["eof"]) {273// the socket is valid but we are not connected274if($this->do_debug >= 1) {275echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";276}277$this->Close();278return false;279}280return true; // everything looks good281}282return false;283}284285/**286* Closes the socket and cleans up the state of the class.287* It is not considered good to use this function without288* first trying to use QUIT.289* @access public290* @return void291*/292public function Close() {293$this->error = null; // so there is no confusion294$this->helo_rply = null;295if(!empty($this->smtp_conn)) {296// close the connection and cleanup297fclose($this->smtp_conn);298$this->smtp_conn = 0;299}300}301302/////////////////////////////////////////////////303// SMTP COMMANDS304/////////////////////////////////////////////////305306/**307* Issues a data command and sends the msg_data to the server308* finializing the mail transaction. $msg_data is the message309* that is to be send with the headers. Each header needs to be310* on a single line followed by a <CRLF> with the message headers311* and the message body being seperated by and additional <CRLF>.312*313* Implements rfc 821: DATA <CRLF>314*315* SMTP CODE INTERMEDIATE: 354316* [data]317* <CRLF>.<CRLF>318* SMTP CODE SUCCESS: 250319* SMTP CODE FAILURE: 552,554,451,452320* SMTP CODE FAILURE: 451,554321* SMTP CODE ERROR : 500,501,503,421322* @access public323* @return bool324*/325public function Data($msg_data) {326$this->error = null; // so no confusion is caused327328if(!$this->connected()) {329$this->error = array(330"error" => "Called Data() without being connected");331return false;332}333334fputs($this->smtp_conn,"DATA" . $this->CRLF);335336$rply = $this->get_lines();337$code = substr($rply,0,3);338339if($this->do_debug >= 2) {340echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';341}342343if($code != 354) {344$this->error =345array("error" => "DATA command not accepted from server",346"smtp_code" => $code,347"smtp_msg" => substr($rply,4));348if($this->do_debug >= 1) {349echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';350}351return false;352}353354/* the server is ready to accept data!355* according to rfc 821 we should not send more than 1000356* including the CRLF357* characters on a single line so we will break the data up358* into lines by \r and/or \n then if needed we will break359* each of those into smaller lines to fit within the limit.360* in addition we will be looking for lines that start with361* a period '.' and append and additional period '.' to that362* line. NOTE: this does not count towards limit.363*/364365// normalize the line breaks so we know the explode works366$msg_data = str_replace("\r\n","\n",$msg_data);367$msg_data = str_replace("\r","\n",$msg_data);368$lines = explode("\n",$msg_data);369370/* we need to find a good way to determine is headers are371* in the msg_data or if it is a straight msg body372* currently I am assuming rfc 822 definitions of msg headers373* and if the first field of the first line (':' sperated)374* does not contain a space then it _should_ be a header375* and we can process all lines before a blank "" line as376* headers.377*/378379$field = substr($lines[0],0,strpos($lines[0],":"));380$in_headers = false;381if(!empty($field) && !strstr($field," ")) {382$in_headers = true;383}384385$max_line_length = 998; // used below; set here for ease in change386387while(list(,$line) = @each($lines)) {388$lines_out = null;389if($line == "" && $in_headers) {390$in_headers = false;391}392// ok we need to break this line up into several smaller lines393while(strlen($line) > $max_line_length) {394$pos = strrpos(substr($line,0,$max_line_length)," ");395396// Patch to fix DOS attack397if(!$pos) {398$pos = $max_line_length - 1;399$lines_out[] = substr($line,0,$pos);400$line = substr($line,$pos);401} else {402$lines_out[] = substr($line,0,$pos);403$line = substr($line,$pos + 1);404}405406/* if processing headers add a LWSP-char to the front of new line407* rfc 822 on long msg headers408*/409if($in_headers) {410$line = "\t" . $line;411}412}413$lines_out[] = $line;414415// send the lines to the server416while(list(,$line_out) = @each($lines_out)) {417if(strlen($line_out) > 0)418{419if(substr($line_out, 0, 1) == ".") {420$line_out = "." . $line_out;421}422}423fputs($this->smtp_conn,$line_out . $this->CRLF);424}425}426427// message data has been sent428fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);429430$rply = $this->get_lines();431$code = substr($rply,0,3);432433if($this->do_debug >= 2) {434echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';435}436437if($code != 250) {438$this->error =439array("error" => "DATA not accepted from server",440"smtp_code" => $code,441"smtp_msg" => substr($rply,4));442if($this->do_debug >= 1) {443echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';444}445return false;446}447return true;448}449450/**451* Sends the HELO command to the smtp server.452* This makes sure that we and the server are in453* the same known state.454*455* Implements from rfc 821: HELO <SP> <domain> <CRLF>456*457* SMTP CODE SUCCESS: 250458* SMTP CODE ERROR : 500, 501, 504, 421459* @access public460* @return bool461*/462public function Hello($host = '') {463$this->error = null; // so no confusion is caused464465if(!$this->connected()) {466$this->error = array(467"error" => "Called Hello() without being connected");468return false;469}470471// if hostname for HELO was not specified send default472if(empty($host)) {473// determine appropriate default to send to server474$host = "localhost";475}476477// Send extended hello first (RFC 2821)478if(!$this->SendHello("EHLO", $host)) {479if(!$this->SendHello("HELO", $host)) {480return false;481}482}483484return true;485}486487/**488* Sends a HELO/EHLO command.489* @access private490* @return bool491*/492private function SendHello($hello, $host) {493fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);494495$rply = $this->get_lines();496$code = substr($rply,0,3);497498if($this->do_debug >= 2) {499echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';500}501502if($code != 250) {503$this->error =504array("error" => $hello . " not accepted from server",505"smtp_code" => $code,506"smtp_msg" => substr($rply,4));507if($this->do_debug >= 1) {508echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';509}510return false;511}512513$this->helo_rply = $rply;514515return true;516}517518/**519* Starts a mail transaction from the email address specified in520* $from. Returns true if successful or false otherwise. If True521* the mail transaction is started and then one or more Recipient522* commands may be called followed by a Data command.523*524* Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>525*526* SMTP CODE SUCCESS: 250527* SMTP CODE SUCCESS: 552,451,452528* SMTP CODE SUCCESS: 500,501,421529* @access public530* @return bool531*/532public function Mail($from) {533$this->error = null; // so no confusion is caused534535if(!$this->connected()) {536$this->error = array(537"error" => "Called Mail() without being connected");538return false;539}540541$useVerp = ($this->do_verp ? "XVERP" : "");542fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);543544$rply = $this->get_lines();545$code = substr($rply,0,3);546547if($this->do_debug >= 2) {548echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';549}550551if($code != 250) {552$this->error =553array("error" => "MAIL not accepted from server",554"smtp_code" => $code,555"smtp_msg" => substr($rply,4));556if($this->do_debug >= 1) {557echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';558}559return false;560}561return true;562}563564/**565* Sends the quit command to the server and then closes the socket566* if there is no error or the $close_on_error argument is true.567*568* Implements from rfc 821: QUIT <CRLF>569*570* SMTP CODE SUCCESS: 221571* SMTP CODE ERROR : 500572* @access public573* @return bool574*/575public function Quit($close_on_error = true) {576$this->error = null; // so there is no confusion577578if(!$this->connected()) {579$this->error = array(580"error" => "Called Quit() without being connected");581return false;582}583584// send the quit command to the server585fputs($this->smtp_conn,"quit" . $this->CRLF);586587// get any good-bye messages588$byemsg = $this->get_lines();589590if($this->do_debug >= 2) {591echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';592}593594$rval = true;595$e = null;596597$code = substr($byemsg,0,3);598if($code != 221) {599// use e as a tmp var cause Close will overwrite $this->error600$e = array("error" => "SMTP server rejected quit command",601"smtp_code" => $code,602"smtp_rply" => substr($byemsg,4));603$rval = false;604if($this->do_debug >= 1) {605echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';606}607}608609if(empty($e) || $close_on_error) {610$this->Close();611}612613return $rval;614}615616/**617* Sends the command RCPT to the SMTP server with the TO: argument of $to.618* Returns true if the recipient was accepted false if it was rejected.619*620* Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>621*622* SMTP CODE SUCCESS: 250,251623* SMTP CODE FAILURE: 550,551,552,553,450,451,452624* SMTP CODE ERROR : 500,501,503,421625* @access public626* @return bool627*/628public function Recipient($to) {629$this->error = null; // so no confusion is caused630631if(!$this->connected()) {632$this->error = array(633"error" => "Called Recipient() without being connected");634return false;635}636637fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);638639$rply = $this->get_lines();640$code = substr($rply,0,3);641642if($this->do_debug >= 2) {643echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';644}645646if($code != 250 && $code != 251) {647$this->error =648array("error" => "RCPT not accepted from server",649"smtp_code" => $code,650"smtp_msg" => substr($rply,4));651if($this->do_debug >= 1) {652echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';653}654return false;655}656return true;657}658659/**660* Sends the RSET command to abort and transaction that is661* currently in progress. Returns true if successful false662* otherwise.663*664* Implements rfc 821: RSET <CRLF>665*666* SMTP CODE SUCCESS: 250667* SMTP CODE ERROR : 500,501,504,421668* @access public669* @return bool670*/671public function Reset() {672$this->error = null; // so no confusion is caused673674if(!$this->connected()) {675$this->error = array(676"error" => "Called Reset() without being connected");677return false;678}679680fputs($this->smtp_conn,"RSET" . $this->CRLF);681682$rply = $this->get_lines();683$code = substr($rply,0,3);684685if($this->do_debug >= 2) {686echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';687}688689if($code != 250) {690$this->error =691array("error" => "RSET failed",692"smtp_code" => $code,693"smtp_msg" => substr($rply,4));694if($this->do_debug >= 1) {695echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';696}697return false;698}699700return true;701}702703/**704* Starts a mail transaction from the email address specified in705* $from. Returns true if successful or false otherwise. If True706* the mail transaction is started and then one or more Recipient707* commands may be called followed by a Data command. This command708* will send the message to the users terminal if they are logged709* in and send them an email.710*711* Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>712*713* SMTP CODE SUCCESS: 250714* SMTP CODE SUCCESS: 552,451,452715* SMTP CODE SUCCESS: 500,501,502,421716* @access public717* @return bool718*/719public function SendAndMail($from) {720$this->error = null; // so no confusion is caused721722if(!$this->connected()) {723$this->error = array(724"error" => "Called SendAndMail() without being connected");725return false;726}727728fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);729730$rply = $this->get_lines();731$code = substr($rply,0,3);732733if($this->do_debug >= 2) {734echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';735}736737if($code != 250) {738$this->error =739array("error" => "SAML not accepted from server",740"smtp_code" => $code,741"smtp_msg" => substr($rply,4));742if($this->do_debug >= 1) {743echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';744}745return false;746}747return true;748}749750/**751* This is an optional command for SMTP that this class does not752* support. This method is here to make the RFC821 Definition753* complete for this class and __may__ be implimented in the future754*755* Implements from rfc 821: TURN <CRLF>756*757* SMTP CODE SUCCESS: 250758* SMTP CODE FAILURE: 502759* SMTP CODE ERROR : 500, 503760* @access public761* @return bool762*/763public function Turn() {764$this->error = array("error" => "This method, TURN, of the SMTP ".765"is not implemented");766if($this->do_debug >= 1) {767echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';768}769return false;770}771772/**773* Get the current error774* @access public775* @return array776*/777public function getError() {778return $this->error;779}780781/////////////////////////////////////////////////782// INTERNAL FUNCTIONS783/////////////////////////////////////////////////784785/**786* Read in as many lines as possible787* either before eof or socket timeout occurs on the operation.788* With SMTP we can tell if we have more lines to read if the789* 4th character is '-' symbol. If it is a space then we don't790* need to read anything else.791* @access private792* @return string793*/794private function get_lines() {795$data = "";796while($str = @fgets($this->smtp_conn,515)) {797if($this->do_debug >= 4) {798echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';799echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';800}801$data .= $str;802if($this->do_debug >= 4) {803echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';804}805// if 4th character is a space, we are done reading, break the loop806if(substr($str,3,1) == " ") { break; }807}808return $data;809}810811}812813?>814815