php下使用SMTP发邮件的代码

5年以前  |  阅读数:320 次  |  编程语言:PHP 

最近一个项目需要用到SMTP发送邮件,之前的库类不存在了,又不喜欢安装pear或者使用pear的net/smtp类,感觉太复杂了。就直接从discuz中抽取出核心稍微修改了下。
从协议分析网上,查找到SMTP协议的命令和应答,SMTP协议在发送SMTP和接收SMTP之间的会话是靠发送SMTP的SMTP命令和接收SMTP反馈的应答来完成的。常用的命令如下:
HELLO<domain><CRLF>识别发送方到接收SMTP的一个HELLO命令
MAIL FROM:<reverse-path><CRLF><reverse-path>为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件数据传送到一个或多个邮箱中。
RCPT TO:<forward-path><CRLF><forward-path>标识各个邮件接收者的地址
DATA<CRLF>
接收SMTP将把其后的行为看作邮件数据去处理,以<CRLF>.<CRLF>标识数据的结尾。
REST<CRLF>退出/复位当前的邮件传输
NOOP<CRLF>要求接收SMTP仅做OK应答。(用于测试)
QUIT<CRLF>要求接收SMTP返回一个OK应答并关闭传输。
VRFY<string><CRLF>验证指定的邮箱是否存在,由于安全因素,服务器多禁止此命令。
EXPN<string><CRLF>验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。
HELP<CRLF>查询服务器支持什么命令

注:<CRLF>为回车、换行,ASCII码分别为13、10(十进制)。

另外,可以在command下,使用telnet来进行简单的手工使用SMTP。
比如:

telnet smtp.263.net 25
Trying 211.150.96.25...
Connected to smtp.263.net.
Escape character is '^]'.
220 Welcome to coremail System(With Anti-Spam) 2.1 for 263(040326)
HELO weiqiong@cctk.net
250 smtp.263.net
mail from:weiqiong@cctk.net
250 Ok
rcpt to:g2_t1@263.net
250 Ok
data
354 End data with .
haha
.
250 Ok: queued as B9E452FF3E
quit
221 Bye
Connection closed by foreign host.

在此基础上就可以写出一个简单的SMTP类了。

<?
class stmp{

private $mailcfg=array();    
private $error_msg='';    

function __construct($mailcfg){    

    $this->mailcfg=$mailcfg;    

}    

public function send($mail){    
    $mailcfg=$this->mailcfg;    
    if(!$fp = fsockopen($mailcfg['server'], $mailcfg['port'], $errno, $errstr, 30)) {    
        return $this->error("($mailcfg[server]:$mailcfg[port]) CONNECT - Unable to connect to the SMTP server, please check your \"mail_config.php\".");    
    }    
     stream_set_blocking($fp, true);    
     $lastmessage = fgets($fp, 512);    
    if(substr($lastmessage, 0, 3) != '220') {    
        return $this->error("$mailcfg[server]:$mailcfg[port] CONNECT - $lastmessage");    
    }    
    fputs($fp, ($mailcfg['auth'] ? 'EHLO' : 'HELO')." ".$mailcfg['auth_username']."\r\n");    
    $lastmessage = fgets($fp, 512);    
    if(substr($lastmessage, 0, 3) != 220 && substr($lastmessage, 0, 3) != 250) {    
        return $this->error("($mailcfg[server]:$mailcfg[port]) HELO/EHLO - $lastmessage");    
    }    
    while(1) {    
        if(substr($lastmessage, 3, 1) != '-' || empty($lastmessage)) {    
             break;    
         }    
         $lastmessage = fgets($fp, 512);    
    }    
    if($mailcfg['auth']) {    
        fputs($fp, "AUTH LOGIN\r\n");    
        $lastmessage = fgets($fp, 512);    
        if(substr($lastmessage, 0, 3) != 334) {    
            return $this->error("($mailcfg[server]:$mailcfg[port]) AUTH LOGIN - $lastmessage");    
        }    
        fputs($fp, base64_encode($mailcfg['auth_username'])."\r\n");    
        $lastmessage = fgets($fp, 512);    
        if(substr($lastmessage, 0, 3) != 334) {    
            return $this->error("($mailcfg[server]:$mailcfg[port]) USERNAME - $lastmessage");    
        }    

        fputs($fp, base64_encode($mailcfg['auth_password'])."\r\n");    
        $lastmessage = fgets($fp, 512);    
        if(substr($lastmessage, 0, 3) != 235) {    
            return $this->error("($mailcfg[server]:$mailcfg[port]) PASSWORD - $lastmessage");    
        }    

        $email_from = $mailcfg['from'];    
    }    
    fputs($fp, "MAIL FROM: <".preg_replace("/.*\<(.+?)\>.*/", "\\\1", $email_from).">\r\n");    
    $lastmessage = fgets($fp, 512);    
    if(substr($lastmessage, 0, 3) != 250) {    
        fputs($fp, "MAIL FROM: <".preg_replace("/.*\<(.+?)\>.*/", "\\\1", $email_from).">\r\n");    
        $lastmessage = fgets($fp, 512);    
        if(substr($lastmessage, 0, 3) != 250) {    
            return $this->error("($mailcfg[server]:$mailcfg[port]) MAIL FROM - $lastmessage");    
        }    
    }    

    $email_to=$mail['to'];    
    foreach(explode(',', $email_to) as $touser) {    
        $touser = trim($touser);    
        if($touser) {    
            fputs($fp, "RCPT TO: <$touser>\r\n");    
            $lastmessage = fgets($fp, 512);    
            if(substr($lastmessage, 0, 3) != 250) {    
                fputs($fp, "RCPT TO: <$touser>\r\n");    
                $lastmessage = fgets($fp, 512);    
                return $this->error("($mailcfg[server]:$mailcfg[port]) RCPT TO - $lastmessage");    
            }    
        }    
    }    
    fputs($fp, "DATA\r\n");    
    $lastmessage = fgets($fp, 512);    
    if(substr($lastmessage, 0, 3) != 354) {    
        return $this->error("($mailcfg[server]:$mailcfg[port]) DATA - $lastmessage");    
    }    
    $str="To: $email_to\r\nFrom: $email_from\r\nSubject: ".$mail['subject']."\r\n\r\n".$mail['content']."\r\n.\r\n";    
    fputs($fp, $str);    
    fputs($fp, "QUIT\r\n");    
    return true;    
}    

public function get_error(){    
    return $this->error_msg;    
}    

private function error($msg){    
    $this->error_msg.=$msg;    
    return false;    
}    

}
?>

简单的调用例子:   

<?
$mailcfg['server'] = 'smtp.163.com';

    $mailcfg['port'] = '25';    

    $mailcfg['auth'] = 1;    
    $mailcfg['from'] = 'test <test@163.com>';    

    $mailcfg['auth_username'] = 'test';    

    $mailcfg['auth_password'] = 'password';        
    $stmp=new stmp($mailcfg);    
    $mail=array('to'=>'test@gmail.com','subject'=>'测试标题','content'=>'邮件内容<a href="http://www.phpobject.net">PHP面向对象</a>');    
    if(!$stmp->send($mail)){    
        echo $stmp->get_error();    
    }else{    
        echo 'mail succ!';    
    }    

?>

如果发送成功,你就可以去邮箱查看邮件了。^_^

 相关文章:
PHP分页显示制作详细讲解
SSH 登录失败:Host key verification failed
获取IMSI
将二进制数据转为16进制以便显示
获取IMEI
文件下载
贪吃蛇
双位运算符
PHP自定义函数获取搜索引擎来源关键字的方法
Java生成UUID
发送邮件
年的日历图
提取后缀名
在Zeus Web Server中安装PHP语言支持
让你成为最历害的git提交人
Yii2汉字转拼音类的实例代码
再谈PHP中单双引号的区别详解
指定应用ID以获取对应的应用名称
Python 2与Python 3版本和编码的对比
php封装的page分页类完整实例