smtp原理
+ smtp邮件协议 : http://www.ietf.org/rfc/rfc2821.txt
+ internet邮件协议 : http://www.ietf.org/rfc/rfc2822.txt
+ 代码参考 : http://blog.csdn.net/kerry0071/article/details/28604267
+ 代码参考 : http://chenall.net/post/cs_smtp/
+ http1.1协议: http://www.ietf.org/rfc/rfc2616.txt
+ 在Internet邮件头非ASCII文本表示 : http://www.ietf.org/rfc/rfc1342.txt
简易smtp实现类
<?php
/*
简易的SMTP发送邮件类,代码比较少,有助于学习SMTP协议,
可以带附件,支持需要验证的SMTP服务器(目前的SMTP基本都需要验证)
编写: chenall
时间: 2012-12-04
网址: http://chenall.net/post/cs_smtp/
修订记录:
2012-12-08
添加AddURL函数,可以直接从某个网址上下载文件并作为附件发送。
修正由于发送人和接收人邮件地址没有使用"<>"126邮箱SMTP无法使用的问题。
2012-12-06
添加reset函数,重置连接,这样可以发送多个邮件。
2012-12-05
发送附件的代码整合到send函数中,减少变量的使用,快速输出,节省内存占用;
2012-12-04
第一个版本
使用方法:
1. 初始化:连接到服务器(默认是QQ邮箱)
$mail = new cs_smtp('smtp.qq.com',25)
if ($mail->errstr) //如果连接出错
die($mail->errstr;
2. 登录到服务器验证,如果失败返回FALSE;
if (!$mail->login('USERNAME','PASSWORD'))
die($mail->errstr;
3. 添加附件如果不指定name自动从指定的文件中取文件名
$mail->AddFile($file,$name) //服务器上的文件,可以指定文件名;
4. 发送邮件
$mail->send($to,$subject,$body)
$to 收件人,多个使用','分隔
$subject 邮件主题,可选。
$body 邮件主体内容,可选
*/
class cs_smtp
{
private $CRLF = "\r\n";
private $from;
private $smtp = null;
private $attach = array();
public $debug = true;//调试开关
public $errstr = '';
function __construct($host='smtp.qq.com',$port = 25) {
if (empty($host))
die('SMTP服务器未指定!');
$this->smtp = fsockopen($host,$port,$errno,$errstr,5);
if (empty($this->smtp))
{
$this->errstr = '错误'.$errno.':'.$errstr;
return;
}
$this->smtp_log(fread($this->smtp, 515));
if (intval($this->smtp_cmd('EHLO '.$host)) != 250 && intval($this->smtp_cmd('HELO '.$host)))
return $this->errstr = '服务器不支持!';
$this->errstr = '';
}
private function AttachURL($url,$name)
{
$info = parse_url($url);
isset($info['port']) || $info['port'] = 80;
isset($info['path']) || $info['path'] = '/';
isset($info['query']) || $info['query'] = '';
$down = fsockopen($info['host'],$info['port'],$errno,$errstr,5);
if (!$down)
return false;
$out = "GET ".$info['path'].'?'.$info['query']." HTTP/1.1\r\n";
$out .="Host: ".$info['host']."\r\n";
$out .= "Connection: Close\r\n\r\n";// 头结束
fwrite($down, $out);
$filesize = 0;
while (!feof($down)) {
$a = fgets($down,515);
if ($a == "\r\n") /* fgets 读取一行遇到换行符"\n"结束, "\r"是回车 */
break;
$a = explode(':',$a);
if (strcasecmp($a[0],'Content-Length') == 0)
$filesize = intval($a[1]);
}
$sendsize = 0;
echo "TotalSize: ".$filesize."\r\n";
$i = 0;
// 读取body
while (!feof($down)) {
$data = fread($down,0x2000);
$sendsize += strlen($data);
if ($filesize)
{
echo "$i Send:".$sendsize."\r";
ob_flush();
flush();
}
++$i;
// 使用 RFC 2045 语义格式化 $data
fwrite($this->smtp,chunk_split(base64_encode($data)));
}
echo "\r\n";
fclose($down);
return ($filesize>0)?$filesize==$sendsize:true; // content-length 的大小 是否等于 读取body的大小判断是否成功
}
function __destruct()
{
if ($this->smtp)
$this->smtp_cmd('QUIT');//发送退出命令
}
private function smtp_log($msg)//即时输出调试使用
{
if ($this->debug == false)
return;
echo $msg."\r\n";
ob_flush();
flush();
}
function reset()
{
$this->attach = null;
$this->smtp_cmd('RSET');
}
function smtp_cmd($msg)//SMTP命令发送和收收
{
fputs($this->smtp,$msg.$this->CRLF);// \r\n 结束输入
$this->smtp_log('SEND:'. substr($msg,0,80));
$res = fread($this->smtp, 515);
$this->smtp_log($res);
$this->errstr = $res;
return $res;
}
function AddURL($url,$name)
{
$this->attach[$name] = $url;
}
function AddFile($file,$name = '')//添加文件附件
{
if (file_exists($file))
{
if (!empty($name))
return $this->attach[$name] = $file;
$fn = pathinfo($file);
return $this->attach[$fn['basename']] = $file;
}
return false;
}
function send($to,$subject='',$body = '')
{
$this->smtp_cmd("MAIL FROM: <".$this->from.'>');
$mailto = explode(',',$to);
foreach($mailto as $email_to)
$this->smtp_cmd("RCPT TO: <".$email_to.">");
if (intval($this->smtp_cmd("DATA")) != 354)//正确的返回必须是354
return false;
fwrite($this->smtp,"To:$to\nFrom: ".$this->from."\nSubject: $subject\n");
$boundary = uniqid("--BY_CHENALL_",true);
$headers = "MIME-Version: 1.0".$this->CRLF;
$headers .= "From: <".$this->from.">".$this->CRLF;
$headers .= "Content-type: multipart/mixed; boundary= $boundary\n\n".$this->CRLF;//headers结束要至少两个换行
fwrite($this->smtp,$headers);
$msg = "--$boundary\nContent-Type: text/html;charset=\"ISO-8859-1\"\nContent-Transfer-Encoding: base64\n\n";
$msg .= chunk_split(base64_encode($body));
// base64_encode设计此种编码是为了使二进制数据可以通过非纯 8-bit 的传输层传输,例如电子邮件的主体
fwrite($this->smtp,$msg);
$files = '';
$errinfo = '';
foreach($this->attach as $name=>$file)
{
$files .= $name;
$msg = "--$boundary\n--$boundary\n";
$msg .= "Content-Type: application/octet-stream; name=\"".$name."\"\n";
$msg .= "Content-Disposition: attachment; filename=\"".$name."\"\n";
$msg .= "Content-transfer-encoding: base64\n\n";
fwrite($this->smtp,$msg);
if (substr($file,4,1) == ':')//URL like http:///file://
{
if (!$this->AttachURL($file,$name))
$errinfo .= '文件下载错误:'.$name.",文件可能是错误的\r\n$file";
}
else
fwrite($this->smtp,chunk_split(base64_encode(file_get_contents($file))));//使用BASE64编码,再用chunk_split大卸八块(每行76个字符)
}
if (!empty($errinfo))
{
$msg = "--$boundary\n--$boundary\n";
$msg .= "Content-Type: application/octet-stream; name=Error.log\n";
$msg .= "Content-Disposition: attachment; filename=Error.log\n";
$msg .= "Content-transfer-encoding: base64\n\n";
fwrite($this->smtp,$msg);
fwrite($this->smtp,chunk_split(base64_encode($errinfo)));
}
return intval($this->smtp_cmd("--$boundary--\n\r\n.")) == 250;//结束DATA发送,服务器会返回执行结果,如果代码不是250则出错。
// \r\n.\r\n 表示发送内容结束
}
function login($su,$sp)
{
if (empty($this->smtp))
return false;
$res = $this->smtp_cmd("AUTH LOGIN");
if (intval($res)>400)
return !$this->errstr = $res;
$res = $this->smtp_cmd(base64_encode($su));
if (intval($res)>400)
return !$this->errstr = $res;
$res = $this->smtp_cmd(base64_encode($sp));
if (intval($res)>400)
return !$this->errstr = $res;
$this->from = $su;
return true;
}
}
mail+stmp函数
<?
!defined('M_COM') && exit('No Permisson');
function sys_mail(&$to,&$subject,&$msg,&$from){
global $mail_smtp,$mail_mode,$mail_port,$mail_auth,$mail_from,$mail_user,$mail_pwd,$mail_delimiter,$mail_silent,$adminemail,$mcharset,$cmsname;
if($mail_silent)
error_reporting(0);
$delimiter = $mail_delimiter == 1 ? "\r\n" : ($mail_delimiter == 2 ? "\r" : "\n");
$user = isset($mail_user) ? $mail_user : 1;
$subject = '=?'.$mcharset.'?B?'.base64_encode(str_replace(array("\r","\n"),'','['.$cmsname.'] '.$subject)).'?=';
$msg = chunk_split(base64_encode(str_replace(array("\n\r","\r\n","\r","\n","\r\n.",),array("\r","\n","\n","\r\n"," \r\n..",),$msg)));
/*
1. 在Internet邮件头非ASCII文本表示 : http://www.ietf.org/rfc/rfc1342.txt
2. encoded-word := "=?" charset "?" encoding "?" encoded-text "?="
3. 具体解析:
encoded-word = "=" "?" charset "?" encoding "?" encoded-text "?" "="
charset = token ; legal charsets defined by RFC 1341
encoding = token ; Either "B" or "Q"
token = 1*<Any CHAR except SPACE, CTLs, and tspecials>
tspecials = "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" / <"> / "/" / "[" / "]" / "?" / "." / "="
encoded-text = 1*<Any printable ASCII character other than "?" or
; SPACE> (but see "Use of encoded-words in message
; headers", below)
*/
/*
Examples
From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>
To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>
CC: =?ISO-8859-1?Q?Andr=E9_?= Pirard <PIRARD@vm1.ulg.ac.be>
Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=
=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=
From: =?ISO-8859-1?Q?Olle_J=E4rnefors?= <ojarnef@admin.kth.se>
To: ietf-822@dimacs.rutgers.edu, ojarnef@admin.kth.se
Subject: Time for ISO 10646?
To: Dave Crocker <dcrocker@mordor.stanford.edu>
Cc: ietf-822@dimacs.rutgers.edu, paf@comsol.se
From: =?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se>
Subject: Re: RFC-HDR care and feeding
*/
$from = $from == '' ? '=?'.$mcharset.'?B?'.base64_encode($cmsname)."?= <$adminemail>" : (preg_match('/^(.+?)\<(.+?)\>$/',$from, $v) ? '=?'.$mcharset.'?B?'.base64_encode($v[1])."?= <$v[2]>" : $from);
$toarr = array();
foreach(explode(',',$to) as $k)
$toarr[] = preg_match('/^(.+?)\<(.+?)\>$/',$k,$v) ? ($user ? '=?'.$mcharset.'?B?'.base64_encode($v[1])."?= <$v[2]>" : $v[2]) : $k;
$to = implode(',',$toarr);
$headers = "From: $from{$delimiter}X-Priority: 3{$delimiter}X-Mailer: 08CMS{$delimiter}MIME-Version: 1.0{$delimiter}Content-type: text/html; charset=$mcharset{$delimiter}Content-Transfer-Encoding: base64{$delimiter}";
$mail_port = $mail_port ? $mail_port : 25;
if($mail_mode == 1 && function_exists('mail')){
// 使用mail函数发送
@mail($to,$subject,$msg,$headers);
}elseif($mail_mode == 2){
// 使用smtp协议+fsockopen发送
if(!$fp = fsockopen($mail_smtp, $mail_port,$errno,$errstr,30))
return "($mail_smtp:$mail_port) CONNECT - Unable to connect to the SMTP server";
stream_set_blocking($fp,true);
$nmsg = fgets($fp,512);
if(substr($nmsg,0,3) != '220') // 220 <domain> Service ready
return "$mail_smtp:$mail_port CONNECT - $nmsg";
fputs($fp, ($mail_auth ? 'EHLO' : 'HELO')." 08CMS\r\n");
$nmsg = fgets($fp,512);
if(substr($nmsg,0,3) != 220 && substr($nmsg,0,3) != 250) // 250 Requested mail action okay, completed
return "($mail_smtp:$mail_port) HELO/EHLO - $nmsg";
while(1){
if(substr($nmsg,3,1) != '-' || empty($nmsg))
break;
$nmsg = fgets($fp,512);
}
if($mail_auth) {
fputs($fp,"AUTH LOGIN\r\n");
$nmsg = fgets($fp,512);
if(substr($nmsg, 0, 3) != 334)
return "($mail_smtp:$mail_port) AUTH LOGIN - $nmsg";
fputs($fp,base64_encode($mail_user)."\r\n");
$nmsg = fgets($fp,512);
if(substr($nmsg,0,3) != 334)
return "($mail_smtp:$mail_port) USERNAME - $nmsg";
fputs($fp,base64_encode($mail_pwd)."\r\n");
$nmsg = fgets($fp,512);
if(substr($nmsg,0,3) != 235)
return "($mail_smtp:$mail_port) PASSWORD - $nmsg";
$from = $mail_from;
}
fputs($fp,"MAIL FROM: <".preg_replace("/.*\<(.+?)\>.*/","\\1",$from).">\r\n");
$nmsg = fgets($fp,512);
if(substr($nmsg,0,3) != 250) {
// 重试了一下?
fputs($fp,"MAIL FROM: <".preg_replace("/.*\<(.+?)\>.*/","\\1",$from).">\r\n");
$nmsg = fgets($fp,512);
if(substr($nmsg,0,3) != 250)
return "($mail_smtp:$mail_port) MAIL FROM - $nmsg";
}
foreach(explode(',',$to) as $v){
$v = trim($v);
if($v){
fputs($fp,"RCPT TO: <".preg_replace("/.*\<(.+?)\>.*/", "\\1", $v).">\r\n");
$nmsg = fgets($fp,512);
// 重试了一下?
if(substr($nmsg,0,3) != 250){
fputs($fp, "RCPT TO: <".preg_replace("/.*\<(.+?)\>.*/","\\1",$v).">\r\n");
$nmsg = fgets($fp,512);
return "($mail_smtp:$mail_port) RCPT TO - $nmsg";
}
}
}
// 邮件内容
fputs($fp,"DATA\r\n");
$nmsg = fgets($fp,512);
// 354 Start mail input; end with <CRLF>.<CRLF>
if(substr($nmsg,0,3) != 354)
return "($mail_smtp:$mail_port) DATA - $nmsg";
$headers .= 'Message-ID: <'.gmdate('YmdHs').'.'.substr(md5($msg.microtime()),0,6).rand(100000, 999999).'@'.$_SERVER['HTTP_HOST'].">{$delimiter}";
fputs($fp,"Date: ".gmdate('r')."\r\n");
fputs($fp,"To: ".$to."\r\n");
fputs($fp,"Subject: ".$subject."\r\n");
fputs($fp,$headers."\r\n");
fputs($fp,"\r\n\r\n");
// header之后\r\n\r\n?
fputs($fp,"$msg\r\n.\r\n"); // TODO 增加附件下载功能
$nmsg = fgets($fp, 512);
if(substr($nmsg, 0, 3) != 250)
return "($mail_smtp:$mail_port) END - $nmsg";
fputs($fp, "QUIT\r\n");
}elseif($mail_mode == 3){
ini_set('SMTP',$mail_smtp);
ini_set('smtp_port',$mail_port);
ini_set('sendmail_from',$from);
@mail($to,$subject,$msg,$headers);
}
return '';
}
ecshop mail + smtp 发送邮件
/**
* 邮件发送
*
* @param: $name[string] 接收人姓名
* @param: $email[string] 接收人邮件地址
* @param: $subject[string] 邮件标题
* @param: $content[string] 邮件内容
* @param: $type[int] 0 普通邮件, 1 HTML邮件
* @param: $notification[bool] true 要求回执, false 不用回执
*
* @return boolean
*/
function send_mail($name, $email, $subject, $content, $type = 0, $notification=false)
{
/* 如果邮件编码不是EC_CHARSET,创建字符集转换对象,转换编码 */
if ($GLOBALS['_CFG']['mail_charset'] != EC_CHARSET)
{
$name = ecs_iconv(EC_CHARSET, $GLOBALS['_CFG']['mail_charset'], $name);
$subject = ecs_iconv(EC_CHARSET, $GLOBALS['_CFG']['mail_charset'], $subject);
$content = ecs_iconv(EC_CHARSET, $GLOBALS['_CFG']['mail_charset'], $content);
$shop_name = ecs_iconv(EC_CHARSET, $GLOBALS['_CFG']['mail_charset'], $GLOBALS['_CFG']['shop_name']);
}
$charset = $GLOBALS['_CFG']['mail_charset'];
/**
* 使用mail函数发送邮件
*/
if ($GLOBALS['_CFG']['mail_service'] == 0 && function_exists('mail'))
{
/* 邮件的头部信息 */
$content_type = ($type == 0) ? 'Content-Type: text/plain; charset=' . $charset : 'Content-Type: text/html; charset=' . $charset;
$headers = array();
$headers[] = 'From: "' . '=?' . $charset . '?B?' . base64_encode($shop_name) . '?='.'" <' . $GLOBALS['_CFG']['smtp_mail'] . '>';
$headers[] = $content_type . '; format=flowed';
if ($notification)
{
$headers[] = 'Disposition-Notification-To: ' . '=?' . $charset . '?B?' . base64_encode($shop_name) . '?='.'" <' . $GLOBALS['_CFG']['smtp_mail'] . '>';
// 回执可以确认对方是否收到该邮件
}
$res = @mail($email, '=?' . $charset . '?B?' . base64_encode($subject) . '?=', $content, implode("\r\n", $headers));
if (!$res)
{
$GLOBALS['err'] ->add($GLOBALS['_LANG']['sendemail_false']);
return false;
}
else
{
return true;
}
}
/**
* 使用smtp服务发送邮件
*/
else
{
/* 邮件的头部信息 */
$content_type = ($type == 0) ?
'Content-Type: text/plain; charset=' . $charset : 'Content-Type: text/html; charset=' . $charset;
$content = base64_encode($content);
$headers = array();
$headers[] = 'Date: ' . gmdate('D, j M Y H:i:s') . ' +0000';
$headers[] = 'To: "' . '=?' . $charset . '?B?' . base64_encode($name) . '?=' . '" <' . $email. '>';
$headers[] = 'From: "' . '=?' . $charset . '?B?' . base64_encode($shop_name) . '?='.'" <' . $GLOBALS['_CFG']['smtp_mail'] . '>';
$headers[] = 'Subject: ' . '=?' . $charset . '?B?' . base64_encode($subject) . '?=';
$headers[] = $content_type . '; format=flowed';
$headers[] = 'Content-Transfer-Encoding: base64';
$headers[] = 'Content-Disposition: inline';
if ($notification)
{
$headers[] = 'Disposition-Notification-To: ' . '=?' . $charset . '?B?' . base64_encode($shop_name) . '?='.'" <' . $GLOBALS['_CFG']['smtp_mail'] . '>';
}
/* 获得邮件服务器的参数设置 */
$params['host'] = $GLOBALS['_CFG']['smtp_host'];
$params['port'] = $GLOBALS['_CFG']['smtp_port'];
$params['user'] = $GLOBALS['_CFG']['smtp_user'];
$params['pass'] = $GLOBALS['_CFG']['smtp_pass'];
if (empty($params['host']) || empty($params['port']))
{
// 如果没有设置主机和端口直接返回 false
$GLOBALS['err'] ->add($GLOBALS['_LANG']['smtp_setting_error']);
return false;
}
else
{
// 发送邮件
if (!function_exists('fsockopen'))
{
//如果fsockopen被禁用,直接返回
$GLOBALS['err']->add($GLOBALS['_LANG']['disabled_fsockopen']);
return false;
}
include_once(ROOT_PATH . 'includes/cls_smtp.php');
static $smtp;
$send_params['recipients'] = $email;
$send_params['headers'] = $headers;
$send_params['from'] = $GLOBALS['_CFG']['smtp_mail'];
$send_params['body'] = $content;
if (!isset($smtp))
{
$smtp = new smtp($params);
}
if ($smtp->connect() && $smtp->send($send_params))
{
return true;
}
else
{
$err_msg = $smtp->error_msg();
if (empty($err_msg))
{
$GLOBALS['err']->add('Unknown Error');
}
else
{
if (strpos($err_msg, 'Failed to connect to server') !== false)
{
$GLOBALS['err']->add(sprintf($GLOBALS['_LANG']['smtp_connect_failure'], $params['host'] . ':' . $params['port']));
}
else if (strpos($err_msg, 'AUTH command failed') !== false)
{
$GLOBALS['err']->add($GLOBALS['_LANG']['smtp_login_failure']);
}
elseif (strpos($err_msg, 'bad sequence of commands') !== false)
{
$GLOBALS['err']->add($GLOBALS['_LANG']['smtp_refuse']);
}
else
{
$GLOBALS['err']->add($err_msg);
}
}
return false;
}
}
}
}
<?php
/**
* ECSHOP SMTP 邮件类
* ============================================================================
* * 版权所有 2005-2012 上海商派网络科技有限公司,并保留所有权利。
* 网站地址: http://www.ecshop.com;
* ----------------------------------------------------------------------------
* 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和
* 使用;不允许对程序代码以任何形式任何目的的再发布。
* ============================================================================
* $Author: liubo $
* $Id: cls_smtp.php 17217 2011-01-19 06:29:08Z liubo $
*/
if (!defined('IN_ECS'))
{
die('Hacking attempt');
}
define('SMTP_STATUS_NOT_CONNECTED', 1, true);
define('SMTP_STATUS_CONNECTED', 2, true);
class smtp
{
var $connection;
var $recipients;
var $headers;
var $timeout;
var $errors;
var $status;
var $body;
var $from;
var $host;
var $port;
var $helo;
var $auth;
var $user;
var $pass;
/**
* 参数为一个数组
* host SMTP 服务器的主机 默认:localhost
* port SMTP 服务器的端口 默认:25
* helo 发送HELO命令的名称 默认:localhost
* user SMTP 服务器的用户名 默认:空值
* pass SMTP 服务器的登陆密码 默认:空值
* timeout 连接超时的时间 默认:5
* @return bool
*/
function smtp($params = array())
{
if (!defined('CRLF'))
{
define('CRLF', "\r\n", true);
}
$this->timeout = 10;
$this->status = SMTP_STATUS_NOT_CONNECTED;
$this->host = 'localhost';
$this->port = 25;
$this->auth = false;
$this->user = '';
$this->pass = '';
$this->errors = array();
foreach ($params AS $key => $value)
{
$this->$key = $value;
}
$this->helo = $this->host;
// 如果没有设置用户名则不验证
$this->auth = ('' == $this->user) ? false : true;
}
function connect($params = array())
{
if (!isset($this->status))
{
$obj = new smtp($params);
if ($obj->connect())
{
$obj->status = SMTP_STATUS_CONNECTED;
}
return $obj;
}
else
{
if (!empty($GLOBALS['_CFG']['smtp_ssl']))
{
// ssl协议链接
$this->host = "ssl://" . $this->host;
}
$this->connection = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
if ($this->connection === false)
{
$this->errors[] = 'Access is denied.';
return false;
}
@socket_set_timeout($this->connection, 0, 250000);
$greeting = $this->get_data();
if (is_resource($this->connection))
{
$this->status = 2;
return $this->auth ? $this->ehlo() : $this->helo();
}
else
{
log_write($errstr, __FILE__, __LINE__);
$this->errors[] = 'Failed to connect to server: ' . $errstr;
return false;
}
}
}
/**
* 参数为数组
* recipients 接收人的数组
* from 发件人的地址,也将作为回复地址
* headers 头部信息的数组
* body 邮件的主体
*/
function send($params = array())
{
foreach ($params AS $key => $value)
{
$this->$key = $value;
}
if ($this->is_connected())
{
// 服务器是否需要验证
if ($this->auth)
{
if (!$this->auth())
{
return false;
}
}
$this->mail($this->from);
if (is_array($this->recipients))
{
foreach ($this->recipients AS $value)
{
$this->rcpt($value);
}
}
else
{
$this->rcpt($this->recipients);
}
if (!$this->data())
{
return false;
}
$headers = str_replace(CRLF . '.', CRLF . '..', trim(implode(CRLF, $this->headers)));
$body = str_replace(CRLF . '.', CRLF . '..', $this->body);
$body = substr($body, 0, 1) == '.' ? '.' . $body : $body;
$this->send_data($headers);
$this->send_data('');
$this->send_data($body);
$this->send_data('.');
return (substr($this->get_data(), 0, 3) === '250');
}
else
{
$this->errors[] = 'Not connected!';
return false;
}
}
function helo()
{
if (is_resource($this->connection)
AND $this->send_data('HELO ' . $this->helo)
AND substr($error = $this->get_data(), 0, 3) === '250' )
{
return true;
}
else
{
$this->errors[] = 'HELO command failed, output: ' . trim(substr($error, 3));
return false;
}
}
function ehlo()
{
if (is_resource($this->connection)
AND $this->send_data('EHLO ' . $this->helo)
AND substr($error = $this->get_data(), 0, 3) === '250' )
{
return true;
}
else
{
$this->errors[] = 'EHLO command failed, output: ' . trim(substr($error, 3));
return false;
}
}
function auth()
{
if (is_resource($this->connection)
AND $this->send_data('AUTH LOGIN')
AND substr($error = $this->get_data(), 0, 3) === '334'
AND $this->send_data(base64_encode($this->user)) // Send username
AND substr($error = $this->get_data(),0,3) === '334'
AND $this->send_data(base64_encode($this->pass)) // Send password
AND substr($error = $this->get_data(),0,3) === '235' )
{
return true;
}
else
{
$this->errors[] = 'AUTH command failed: ' . trim(substr($error, 3));
return false;
}
}
function mail($from)
{
if ($this->is_connected()
AND $this->send_data('MAIL FROM:<' . $from . '>')
AND substr($this->get_data(), 0, 2) === '250' )
{
return true;
}
else
{
return false;
}
}
function rcpt($to)
{
if ($this->is_connected()
AND $this->send_data('RCPT TO:<' . $to . '>')
AND substr($error = $this->get_data(), 0, 2) === '25')
{
return true;
}
else
{
$this->errors[] = trim(substr($error, 3));
return false;
}
}
function data()
{
if ($this->is_connected()
AND $this->send_data('DATA')
AND substr($error = $this->get_data(), 0, 3) === '354' )
{
return true;
}
else
{
$this->errors[] = trim(substr($error, 3));
return false;
}
}
function is_connected()
{
return (is_resource($this->connection) AND ($this->status === SMTP_STATUS_CONNECTED));
}
function send_data($data)
{
if (is_resource($this->connection))
{
return fwrite($this->connection, $data . CRLF, strlen($data) + 2);
}
else
{
return false;
}
}
function get_data()
{
$return = '';
$line = '';
if (is_resource($this->connection))
{
// 返回以\r\n结束 或 250 OK
while (strpos($return, CRLF) === false OR $line{3} !== ' ')
{
$line = fgets($this->connection, 512);
$return .= $line;
}
return trim($return);
}
else
{
return '';
}
}
/**
* 获得最后一个错误信息
*
* @access public
* @return string
*/
function error_msg()
{
if (!empty($this->errors))
{
$len = count($this->errors) - 1;
return $this->errors[$len];
}
else
{
return '';
}
}
}