実際の仕事でメールを送信する必要に遭遇しました。既存のコードは、JSP ページにアクセスし、Java メール クラスを呼び出すことによって実装されます。最初はPHPの授業も試したそうですが、しばらく使っていると問題が発生したようで、こうして「カーブで国を救う」ことを始めたそうです。自分のやり方で自分の作業を行った後、好奇心から、なぜ PHP を直接使用すると失敗するのかを知りたいと思いました。 PHP を直接使用して関数を完成できれば、より効率的になるはずです。
1. 既存の PHP メール クラスを見つけます。 2. PHP の mail() 関数を使用しますが、ログインできないため、イントラネット メールボックスのみを送信できます。 3. ソケットの学習 4. SMTP プロトコル コマンドの学習 5. cmd を使用して Telnet 経由でサーバーに接続し、SMTP コマンドを送信して電子メールを送信します。 6. ソケットを使用して SMTP コマンドを送信し、電子メールを送信します。 7. データ部分とエンコードの問題を要約します。電子メールの添付ファイル形式 (1) タイトル エンコーディング (2) テキストの分割 (3) 添付ファイル付きの特定のテキスト (4) 特定の実装 8. 概要 9. 添付ファイル
注: 以下では 3 つの電子メール サーバーが使用されます。会社の古いサーバー: mail.old .net2、会社の新しいサーバー: mail.new.net3、QQ メールボックス: smtp.qq.com
2. PHP の mail() 関数を使用しますが、ログインできないため、イントラネット メールボックスにのみ送信できます:
具体的な実装:
1. php.ini 設定を変更します:
SMTP = mail.old.net //设置具体的邮件服务器地址smtp_port = 25 //设置端口,一般为25sendmail_from = "gs@old.net" //设置发送者的邮箱(win环境);sendmail_path = "" //unix环境?未测试过
2. PHP コード: mail($to, $subject, $headers, $parameters ) メール (受信者、タイトル、内容、メールの元のテキストに表示されるいくつかのパラメーター。これまでに使用したことがないのでわかりません)
$to = "gs@old.net";$subject = "=?UTF-8?B?".base64_encode("邮件标题")."?=";$message = "<a href='http://www.xx.com'>点击可以直接跳转</a>";$headers = <<<HEADERSMIME-Version: 1.0 \r\nContent-type:text/html;charset=UTF-8 \r\nfrom:<random@random> \r\nto:<random@random>" \r\nHEADERS;$boolean = mail($to, $subject, $message, $headers); //返回是否发送成功
1. メールの送信者と受信者: ini 設定 -- > 電子メールの元のテキスト Return-Path$to パラメータ --> 実際の受信者 (イントラネット上にある必要があります) $header パラメータ --> 送信者を表示します (必要に応じて追加できます) > 受信者の表示 送信者 (任意に入力可能) 2. 送信範囲: 受信者はイントラネット上の人物である必要があります: テスト状況: 同じサーバー範囲内のメールのみ送信可能 (@ 以降は同じです) )。外部ネットワーク (会社メールから QQ メールなど) に送信する場合、エラー コードは 554 および 550 です。推測: 1. メールサーバーの設定に問題があります。 2. メール送信に特定のアカウントとパスワードでログインする必要がないため、外部ネットワークに送信できないのですか?注: インターフェイスに表示されるコンテンツは、to の設定により他のコンテンツとして表示される場合があります。つまり、$to はイントラネット メールボックスを設定し、メールボックスは実際にこの電子メールを受信します。ただし、電子メールに表示される受信者はイントラネット メールボックスではなく、$headers に基づいて設定される場合があります。 3. エンコード: コンテンツの場合: 最初に Base64 でエンコードし、次に UTF-8 でエンコードします。形式: =?UTF-8?B?".base64_encode("Email Title")."?=4. 本文に HTML コードを使用します: $headers に Content-type: text/html を設定するだけです
概要:
ソケットの一般的な意味:
具体的な実装:
set_time_limit(0); //网页执行防止超时,cmd中执行无需该行$socket = socket_create(AF_INET, SOCK_STREAM, 0); //创建socket资源socket_bind($socket, "127.0.0.1", 16161); //将socket资源绑定到具体端口socket_listen($socket, 3); //该端口开始监听,第二个参数是具体连接数(并发数?)?$receive_socket = socket_accept($socket); //接收到客户端的信息,一个新的socket资源$input = socket_read($receive_socket, 1024); //读取该socket资源的内容var_dump($input); //客户端发出的内容,一般都是字符串?$output = "服务器-->客户端 信息";socket_write($receive_socket, $output, strlen ($output)); //给客户端返回信息。注意:用的是接受到的socket资源,而不是原本自身的资源。socket_close($socket); //将两个资源关闭socket_close($receive_socket);
$socket = socket_create(AF_INET, SOCK_STREAM, 0); //创建socket资源socket_connect($socket, "127.0.0.1", 16161); //连接具体端口$message = "客户端-->服务器 信息";socket_write($socket, $message, strlen($message)); //发送信息给服务器$result = socket_read ($socket, 1024); //读取到具体的信息var_dump($resule);socket_close($socket); //关闭socket资源
要約:
各コマンドは、成功または失敗を通知するステータス コードと短い説明を返します。
//连接成功,220helo xxx //这一步是必须的!xxx貌似自定义,250ehlo xxx //xxx貌似自定义,查看服务器支持哪些命令,返回250-xxx 250-xxxstarttls //QQ邮箱需要auth login //账号密码登陆,账号密码需要的是base64加密过的,mail from:<x@y.z> //发件人,250rept to:<a@b.c> //收件人,可以重复执行发送给多个人,250data //具体邮件内容,显示的from-to、编码及附件都在这里传输,以单行.结束(\r\n.\r\n),354+250quit //退出连接,221
telnet host port //邮件通常端口为25 QQ邮箱需要使用587(SSL加密方式,官方465或587,但465我测试失败)
telnet mail.old.net 25 //220helo abc //250ehlo abc //返回250-xx 250-xxmail from:<random@random> //原文Return-Path,可外网邮箱,250rcpt to:<gs@old.net> //实际收件人(必须内网邮箱),250data //354 开始可以输入具体内容from: random@random //显示的发件人(可以随便填)to: random@random //显示的收件人(可以随便填)comment-comment //具体内容需要和上面的隔一个空行. //用单行.结束,250quit //221
不论是否登陆,都可以发送邮件。1、auth login不登陆
telnet mail.new.net 25 //220helo abc //250ehlo abc //返回250-xx 250-xxmail from:<random@random> //原文Return-Path,可外网邮箱,250rcpt to:<gs@30new.net> //实际收件人(必须内网邮箱),250data //354 开始可以输入具体内容from:random@random //显示的发件人(可以随便填)to: random@random //显示的收件人(可以随便填)comment-comment //具体内容需要和上面的隔一个空行. //用单行.结束,250quit //221
2、auth login登陆无论端口是25还是587,在starttls后都无法进行账号登陆。另发现,如果 mail from 及 rcpt to 都是填写QQ邮箱,QQ邮箱会无效。
telnet mail.new.net 25 //220helo abc //250ehlo abc //返回250-xx 250-xxauth login //334base64abcdefg //@前的 base64编码,334base64abcdefg //密码 base64编码,235mail from:<random@random> //原文Return-Path,可外网邮箱,250rcpt to:<random@random> //实际收件人,可外网邮箱,250data //354 开始可以输入具体内容from:random@random //显示的发件人(可以随便填)to: random@random //显示的收件人(可以随便填)comment-comment //具体内容需要和上面的隔一个空行. //用单行.结束,250quit //221
需要在QQ邮箱里设置,开启P0P3/SMTP。QQ邮箱必须开启starttls后再登陆,可以发送邮件到外网。
telnet smtp.qq.com 587 //220helo abc //250ehlo abc //返回250-xx 250-xxstarttls //220auth login //334base64abcdefg //@前的 base64编码,334base64abcdefg //授权码 base64编码,235mail from:<gs@qq.com> //原文Return-Path,必须为登陆账号,250rcpt to:<random@random> //实际收件人,可外网邮箱,250data //354 开始可以输入具体内容from:random@random //显示的发件人,可以随便填to: random@random //显示的收件人,可以随便填comment-comment //具体内容需要和上面的隔一个空行. //用单行.结束,250quit //221
1、发送范围:公司旧邮箱:只能内网。公司新邮箱:不登陆只能内网,登陆了可以外网。QQ邮箱:先starttls然后登陆,可以外网。2、具体发件人收件人:登陆的账号 --> 实际发送人mail from --> 原文Return-Path的内容(如果与data-from设置不同,QQ邮箱会显示:由xxx代发)rcpt to --> 实际收件人data-from --> 显示的发送人(可以随便填)data-to --> 显示的收件人(可以随便填,与实际不同)3、其它:编码及附件未测试
与mail()一样,不登陆的情况下,只能在内网发送。不过telnet可以用auth login登陆账号,然后可以发送邮件到外网。
$socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); //创建socket资源socket_connect($socket, $mail_server_name, $mail_server_port); //连接端口$command = "helo abc \r\n"; // \r\n表示回车socket_write($socket, $command, strlen($command)); //发送命令给服务器$num = socket_read($socket, 1024); //接受状态码及短句
1、通过多次socket_write()来传送SMTP命令,完成整个发邮件的流程2、\r\n等同于在命令行中按回车3、QQ邮箱无法使用:在auth login命令后:显示错误: unable to read from socket [0]: 远程主机强迫关闭了一个现有的连接。可能是处于安全性的考虑??
查资料想找编码还有正文的格式,但大部分比较凌乱,不然就是RFC文件没勇气。后来想到自己给自己发邮件,然后用查看邮件原文这个功能,去自己总结。目前需求只是发送文本、html的a标签、附件就足够了,因此自己总结的不用太全面。
$subject = "=?UTF-8?B?".base64_encode("标题")."?=";
需要声明:Content-Type: multipart/mixed;其中,mixed表明是混合类型。规定boundary分割,然后按照具体情况分别写具体声明+内容。
boundary是自定义的第一段开始:--boundary第n段开始: --boundary结束: --boundary--boundary是可以嵌套的:如果就文本和附件,一般无需嵌套。
标题发件人收件人声明编码-类型-boundary声明 --boundary 声明编码-类型 内容 --boundary 声明编码-类型 内容 --boundary 声明编码-类型 --boundary--
声明与内容,内容与后文 都需要有空行,即2次\r\n
$command = <<<COMMANDContent-Type: text/html; \r\ncharset="utf-8" \r\nContent-Transfer-Encoding: base64 \r\nCOMMAND;$command = "\r\n" . base64_encode("内容") . "\r\n\r\n"; //内容前后都有两次\r\n
先用fopen()及fread() 读取二进制,然后将二进制内容进行发送
$file_name = iconv('UTF-8', 'GB18030', "文件名.txt" ); //对文件名编码$fp = fopen($file_name, 'rb'); //以二进制形式打开文件$comment = fread($fp, filesize($file_name)); //读取文件内容fclose($fp); //关闭资源
然后声明编码-类型并传递数据
$file_name = "=?UTF-8?B?".base64_encode("文件名.txt")."?="; //对文件名编码$command = "Content-Type: application/octet-stream; \r\n"$command .= "name=\"" . $file_name . "\"\r\n"$command .= "Content-Disposition: attachment; filename=\"" . $file_name . "\"\r\n";$command .= "Content-Transfer-Encoding: base64 \r\n";$command .= "\r\n" . base64_encode($comment) . "\r\n\r\n"; //这里的$comment就是读出来的文件二进制数据
1、文件名编码:对文件名的编码有两次,一次是为了打开文件,一次是为了邮件的显示。编码方式不同,不知道能否统一?2、开始的声明中,boundary前必须有一个Tab键的缩进:原因未知
"Mime-Version: 1.0\r\nContent-Type: multipart/mixed;\r\n boundary=\"".$boundary."\"\r\nContent-Transfer-Encoding: 8Bit\r\n";
3、附件声明:看别人的代码,好像通过文件后缀来判断的类型。而自己只是笼统地用 application/octet-stream;
自己归纳的发邮件函数缺陷,未添加:1、没有抄送人、密送人。2、没有对命令发送是否成功进行判断(可以通过正则判断返回码)。3、没有选择是否text还是html,全部默认成为了html。4、没有选择是否starttls,如果需要使用到QQ邮箱,需自行添加。5、变量名及代码格式可能不太规范。
网上已经封装好的类,通过socket发送邮件。
上述内容大约花了三天时间学习及测试,然后整理就花了一天多...以前总以为socket深不可测,现在起码有了一定的了解,没有那么害怕了。QQ邮箱必须登陆,而且mail from的发件人设置必须是登陆人,可防止有人故意隐藏自己真实地址。所以说,公司新邮箱不用登陆的情况,估计是属于安全漏洞?等PHP代码知识再熟悉之后,得去研究研究那上千行的PHP类...不知道具体实现原理究竟是怎么样的...
超链接";$file_name[0] = "啊.png";$file_name[1] = "哦.xlsx";$file_name[2] = "额.docx";$file_name[3] = "咦.pdf";send_email($mail_server_name, $username, $passward, $mail_from, $mail_to, $html_comment, $file_name, $subject);/** * 通过socket发送邮件 * @param $mail_server_name 邮件服务器地址 * @param $username 登陆账号 * @param $passward 登陆密码 * @param $mail_from 发件人地址 * @param $mail_to 收件人地址,数组格式 * @param $html_comment 文本内容 * @param array $file_name 附件路径,数组格式 * @param string $subject 标题,默认空 * @param string $mail_server_port 邮件服务器端口 默认25 * @param string $boundary 分割符 */function send_email($mail_server_name, $username, $passward, $mail_from, $mail_to, $html_comment, $file_name=array(), $subject="", $mail_server_port="25", $boundary="ABCDEFG"){ //创建一个socket连接 $socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); //连接邮件服务器,需要返回状态码 220 socket_connect($socket, $mail_server_name, $mail_server_port); //helo localhost,需要返回状态码 250 $command = "helo localhost\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //登陆账号,分别返回状态码 334 334 235 $command = "auth login\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //需要返回状态码 334 $command = base64_encode($username)."\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //需要返回状态码 235 $command = base64_encode($passward)."\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //设置邮件发送者,需要返回状态码 250 $command = "MAIL FROM:<".$mail_from.">\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //设置邮件接受者,需要返回状态码 250 $mail_to_length = count($mail_to); for($i=0; $i<$mail_to_length; $i++){ $command = "RCPT TO:<".$mail_to[$i].">\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); } //开始发送具体内容,需要返回状态码 354 $command = "DATA\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //发送具体内容:需要返回状态码 250 $command = "from: ".$mail_from."\r\n"; for($i=0; $i<$mail_to_length; $i++){ $command .= "to: ".$mail_to[$i]."\r\n"; } $subject = "=?UTF-8?B?".base64_encode($subject)."?="; $command .= "Subject: ".$subject."\r\n"; $command .= "Mime-Version: 1.0\r\nContent-Type: multipart/mixed;\r\n boundary=\"".$boundary."\"\r\nContent-Transfer-Encoding: 8Bit\r\n"; $command .= "--".$boundary."\r\n"; $command .= "Content-Type: multipart/alternative;\r\n"; $command .= "Content-Type: text/html;\r\n"; $command .= "charset=\"utf-8\"\r\n"; $command .= "Content-Transfer-Encoding: base64\r\n"; $command .= "\r\n" .base64_encode($html_comment). "\r\n\r\n"; $file_length = count($file_name); for($i=0; $i<$file_length; $i++){ //读文件 $file_name_tmp = iconv( 'UTF-8', 'GB18030', $file_name[$i] ); $fp = fopen($file_name_tmp, 'rb'); // 以二进制形式打开文件 $comment = fread($fp, filesize($file_name_tmp)); // 读取文件内容 fclose($fp); $file_name_tmp = "=?UTF-8?B?".base64_encode($file_name[$i])."?="; $command .= "--".$boundary."\r\n"; $command .= "Content-Type: application/octet-stream;\r\n"; $command .= "name=\"".$file_name_tmp."\"\r\n"; $command .= "Content-Disposition: attachment; filename=\"".$file_name_tmp."\"\r\n"; $command .= "Content-Transfer-Encoding: base64\r\n"; $command .= "\r\n".base64_encode($comment)."\r\n\r\n"; } $command .= "--".$boundary."--\r\n"; $command .= ".\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024); //离开,需要返回状态码 221 $command = "quit\r\n"; socket_write($socket, $command, strlen($command)); socket_read($socket, 1024);}?>
<?php//define("SOL", "\n");define("EOL", "\r\n");define("SMTP_HOST", "mail.new.net"); //SMTP服务器define("SMTP_PORT", "25"); //SMTP服务器端口define("SMTP_USER", ""); //SMTP服务器的用户帐号define("SMTP_PASS", ""); //SMTP服务器的用户密码$from = "random@random"; //SMTP服务器的用户邮箱$to = "random@random"; //发送给谁 可用逗号隔开多个邮箱$cc = "";$bcc = "";$subject="标题"; $subject=iconv("utf-8","gb2312//IGNORE",$subject); //邮件主题 很多客户端会有乱码,所以转一下码$body = "测试"; //邮件内容$smtp = new smtp(SMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS, false); //这里面的一个true是表示使用身份验证,否则不使用身份验证.$smtp->addAttachment("123.doc","啊.doc");$smtp->sendmail($to, $from, $subject, $body, $cc, $bcc);class smtp { /* Public Variables */ public $attachments = array(); /* Private Variables */ private $smtp_host; private $smtp_port; private $time_out; private $host_name; private $auth; private $user; private $pass; private $sock; /* Constractor */ public function smtp($smtp_host = null, $smtp_port = null, $user = null, $pass = null, $auth = true) { $this->smtp_host = (!empty($smtp_host)) ? $smtp_host : SMTP_HOST; $this->smtp_port = (!empty($smtp_port)) ? $smtp_port : SMTP_PORT; $this->user = (!empty($user)) ? $user : SMTP_PORT; $this->pass = (!empty($pass)) ? $pass : SMTP_PORT; $this->auth = $auth; $this->time_out = 15; # $this->host_name = "localhost"; $this->sock = FALSE; } /* Main Function */ public function sendmail($to, $from, $subject = "", $body = "", $cc = "", $bcc = "") { $bndp = md5(uniqid("")) . rand(1000, 9999); $bnd = md5(uniqid("")) . rand(1000, 9999); list ($msec, $sec) = explode(" ", microtime()); $mail_from = $this->strip_line_breaks($from); $mail_to = explode(",", $to); $body = preg_replace("/(^|(\r\n))(\\.)/", "", $body); if ($cc != "") $mail_to = array_merge($mail_to, explode(",", $cc)); if ($bcc != "") $mail_to = array_merge($mail_to, explode(",", $bcc)); $headers = "MIME-Version:1.0" . EOL; $headers .= "To: " . $to . EOL; if ($cc != "") { $headers .= "Cc: " . $cc . EOL; } $headers .= "From: $from<" . $from . ">" . EOL; $headers .= "Subject: " . $subject . EOL; $headers .= "Date: " . date("r") . EOL; $headers .= "X-Mailer: Webmail ver 1.0 (PHP Version/" . phpversion() . ")" . EOL; $headers .= "Message-ID: <" . date("YmdHis", $sec) . "." . ($msec * 1000000) . "." . $from . ">" . EOL; if (count($this->attachments) > 0) { $headers .= "Content-Type: multipart/mixed;" . EOL . chr(9) . " boundary=\"" . $bndp . "\"" . EOL . EOL; $headers .= '--'.$bndp . EOL; $headers .= 'Content-Type : multipart/alternative; boundary="' . $bnd . '"' . EOL . EOL; $headers .= '--' . $bnd . EOL; $headers .= 'Content-Type: text/plain; charset=utf-8' . EOL; $headers .= "Content-Transfer-Encoding: 8bit" . EOL . EOL; $headers .= $body . EOL; $headers .= '--' . $bnd . EOL; $headers .= 'Content-type: text/html; charset=utf-8' . EOL; $headers .= "Content-Transfer-Encoding: 8bit" . EOL . EOL; $headers .= $body . EOL; $headers .= '--' . $bnd . '--' . EOL; foreach ($this->attachments as $att) { $headers .= "--" . $bndp . EOL . $att; print_R($headers); } $headers .= '--' . $bndp . '--' . EOL; $this->clear_attachments(); } else { $headers .= 'Content-Type : multipart/alternative;boundary="'.$bnd.'"' . EOL . EOL; $headers .= '--'.$bnd . EOL; $headers .= 'Content-Type: text/plain; charset=utf-8' . EOL; $headers .= "Content-Transfer-Encoding: 8bit" . EOL . EOL; $headers .= $body . EOL; $headers .= '--'.$bnd . EOL; $headers .= 'Content-type: text/html; charset=utf-8' . EOL; $headers .= "Content-Transfer-Encoding: 8bit" . EOL . EOL; $headers .= $body . EOL; $headers .= '--'.$bnd.'--' . EOL; } $sent = TRUE; foreach ($mail_to as $rcpt_to) { $rcpt_to = $this->strip_line_breaks($rcpt_to); if (!$this->smtp_sockopen($rcpt_to)) { $this->log_write("Error: Cannot send email to " . $rcpt_to); $sent = FALSE; continue; } if ($this->smtp_send($this->host_name, $mail_from, $rcpt_to, $headers, $body)) { $this->log_write("E-mail has been sent to <" . $rcpt_to . ">"); } else { $this->log_write("Error: Cannot send email to <" . $rcpt_to . ">"); $sent = FALSE; } fclose($this->sock); } $this->log_write("{$mail_to} send over;"); return $sent; } public function addAttachment($file,$file_name="", $dispo = "attachment") { $file_data = (file_exists($file)) ? file_get_contents($file) : ""; if ($file_data != "") { $filename = basename($file); if(!$file_name) $file_name=$filename; $file_name="=?UTF-8?B?".base64_encode($file_name)."?="; $ext = pathinfo($filename, PATHINFO_EXTENSION); $chunks = chunk_split(base64_encode($file_data)); $parts = "Content-Type: application/$ext; name=\"" . $file_name . "\"" . EOL; $parts .= "Content-Transfer-Encoding: base64" . EOL; $parts .= "Content-Disposition: " . $dispo . "; filename=\"" . $file_name . "\"" . EOL . EOL; $parts .= $chunks . EOL . EOL; $this->attachments[] = $parts; } } private function clear_attachments() { unset($this->attachments); $this->attachments = array(); } /* Private Functions */ private function smtp_send($helo, $from, $to, $header, $body = "") { if (!$this->smtp_putcmd("HELO", $helo)) { //$this->log_write("Error: Error occurred while sending HELO command."); return FALSE; } #auth if ($this->auth) { if (!$this->smtp_putcmd("AUTH LOGIN", base64_encode($this->user))) { //$this->log_write("Error: Error occurred while sending HELO command."); return FALSE; } if (!$this->smtp_putcmd("", base64_encode($this->pass))) { //$this->log_write("Error: Error occurred while sending HELO command."); return FALSE; } } if (!$this->smtp_putcmd("MAIL", "FROM:<" . $from . ">")) { //$this->log_write("Error: Error occurred while sending MAIL FROM command."); return FALSE; } if (!$this->smtp_putcmd("RCPT", "TO:<" . $to . ">")) { //$this->log_write("Error: Error occurred while sending RCPT TO command."); return FALSE; } if (!$this->smtp_putcmd("DATA")) { //$this->log_write("Error: Error occurred while sending DATA command."); return FALSE; } if (!$this->smtp_message($header, $body)) { //$this->log_write("Error: Error occurred while sending message."); return FALSE; } if (!$this->smtp_eom()) { //$this->log_write("Error: Error occurred while sending <CR><LF>.<CR><LF> [EOM]."); return FALSE; } if (!$this->smtp_putcmd("QUIT")) { //$this->log_write("Error: Error occurred while sending QUIT command."); return FALSE; } return TRUE; } private function smtp_sockopen($address) { if ($this->smtp_host == "") { return $this->smtp_sockopen_mx($address); } else { return $this->smtp_sockopen_relay(); } } private function smtp_sockopen_relay() { $this->log_write("Trying to Connect " . $this->smtp_host . ":" . $this->smtp_port . "..."); $this->sock = @fsockopen($this->smtp_host, $this->smtp_port, $errno, $errstr, $this->time_out); if (!($this->sock && $this->smtp_ok())) { $this->log_write("Error: connenct error" . $errstr . " (" . $errno . ")"); return FALSE; } $this->log_write("Connected Ok"); return TRUE; } private function smtp_sockopen_mx($address) { $domain = preg_replace("/^.+@([^@]+)$/", "\1", $address); if (!@getmxrr($domain, $MXHOSTS)) { $this->log_write("Error: Cannot resolve MX \"" . $domain . "\""); return FALSE; } foreach ($MXHOSTS as $host) { $this->log_write("Trying to " . $host . ":" . $this->smtp_port); $this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->time_out); if (!($this->sock && $this->smtp_ok())) { $this->log_write("Connect Error ," . $errstr . " (" . $errno . ")"); continue; } $this->log_write("Connected to mx host " . $host); return TRUE; } $this->log_write("Error: Cannot connect to any mx hosts (" . implode(", ", $MXHOSTS) . ")"); return FALSE; } private function smtp_message($header, $body) { fputs($this->sock, $header . "\r\n" . $body); return TRUE; } private function smtp_eom() { fputs($this->sock, "\r\n.\r\n"); return $this->smtp_ok(); } private function smtp_ok() { $response = str_replace("\r\n", "", fgets($this->sock, 512)); if (!preg_match("/^[23]/", $response)) { fputs($this->sock, "QUIT\r\n"); fgets($this->sock, 512); $this->log_write("Error: Remote host returned \"" . $response . "\""); return FALSE; } return TRUE; } private function smtp_putcmd($cmd, $arg = "") { if ($arg != "") $cmd = ($cmd == "") ? $arg : ($cmd . " " . $arg); fputs($this->sock, $cmd . "\r\n"); return $this->smtp_ok(); } private function strip_line_breaks($address) { $address = preg_replace("/([\t\r\n])+/", "", $address); $address = preg_replace("/^.*<(.+)>.*$/", "", $address); return $address; } public function log_write($message) { $message = date("M d H:i:s ") . get_current_user() . "[" . getmypid() . "]: " . $message; file_put_contents(dirname(__FILE__) . '/mail.log', $message . PHP_EOL, FILE_APPEND | LOCK_EX); }}