最近paperen公司的那个搞了一年的东西也差不多可以拿出来了,至少在数据上可靠了点,界面上就……程序上就更……关于丢失密码的处理会有涉及到给会员的注册邮箱发送邮件功能,其实就是运用了SMTP这个服务。

正如对PHP函数有了解的人都应该知道PHP中有一个mail函数,直接调用它理论上就可以发送邮件了

bool mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )

你能从手册中获得更多例子,这个函数确实是太方便了,以至于paperen一开始也会对它感到神奇,因为实在是搞不清为什么一个函数就能发送一封邮件,直观上看来貌似这个函数能直接跟邮局联系。但实质上它要起作用需要服务器的支持,简单来说你的服务器需要有SMTP 服务。

很幸运公司的服务器有这个服务,但也很不幸运直接调用mail函数来发邮件的结果并不能让自己满意。当然paperen也找了不少网上提供的发送邮件代码,结果都不是很满意的,有些邮箱能收到有些邮箱收不到,而且绝大部分都是一些主流的邮箱,例如163,126等

所以paperen觉得还是有必要自己搞清楚一下这个原理,其实真的没那么神秘。

或者你开始你需要对smtp有一个基本的了解,paperen貌似以前大学的时候就学过这个,但书上学得确实没有实践中学的劲。

或者你可以看看以下链接的内容

然后动动手试试在"黑屏"下发一封邮件玩玩。下图为telent localhost 25后的界面,可以使用help参数查看命令。

20110113210420

如果有一台服务器而且有smtp服务的话不妨可以试试,paperen公司里面就有一台对外的服务器可以玩,oy~~不过如果没有服务器也不要紧,你可以使用第三方的smtp服务的,参见下面的例子(使用163的)

在cmd下输入 telnet smtp.163.com 25

20110113210644

就能登陆到163的smtp服务了,不过首先要使用helo命令打个招呼先

220 163.com Anti-spam GT for Coremail System (163com[20101010])
helo paperen
250 OK
auth login
334 dXNlcm5hbWU6
//你帐号的base64码
334 UGFzc3dvcmQ6
//你帐号密码的base64码
235 Authentication successful
mail from:
250 Mail OK
rcpt to:
250 Mail OK
data
354 End data with .
mime-version:1.0
from:paperen
to:paperen
subject:test
content-type:text/html; charset="utf-8"
//这里要空两行,1行
//2行
hello world!
.
250 Mail OK queued as smtp4,DtGowLCbrgVa+y5N1C9xAA--.11142S2 1294924769

20110113212115

其中334两行分别要填写您在163的帐号与密码,而且要用base64码,这个也很容易嘛,可以用php中的base64_encode函数帮你或者用在线工具 http://tool.114la.com/base64.html  复制后在黑屏里面右击粘贴就可以了,也不用自己照着输入。

后面其实也就没什么了,mail from你懂的,rcpt to也就是要发给谁。不过要注意一下在data后,也就是在写邮件内容前空两行。然后到gmail看看吧。

20110114091637

这就使用命令行模式下成功发送了一封邮件了,这就是发送邮件的原理。Of course~光来点英文的信件也没神马意思,我们就是喜欢玩花样的,或者你觉得"发中文内容还不容易嘛,也是拷贝的功夫",在黑屏下的确不支持中文输入法的,没错也得用拷贝的方法将中文弄到邮件内容里面去,但别高兴得太早,如果你以为就这么简单那么你就错了,结果发送过来的邮件就是一堆乱码"??????????????????",N个口……问你死未……

其实发中文的关键也在于要对内容进行一下base64加密,并在邮件头加上一个声明

Content-Transfer-Encoding: base64

那么发送的内容就ok了,不过至于邮件的标题嘛,详见下面,因为标题处有些少复杂,需要加上一些字符来标识。

所谓懒惰是动力是对的,想象一下如果我们都是在命令行下发送邮件的话……发一封邮件少则需要15分钟,多则半个小时……这真的让人崩溃了,就连paperen自己面对着这个黑屏状态敲着无数遍重复的命令也快要崩溃了(还不能输错,paperen不知道如何删除之前的输入……只能覆盖而且覆盖后的命令会乱码的,你试试看就明白),就写一个程序让它帮我们发送邮件好了。

下面开始来更爽的,就是搞一个发邮件的php程序。

或者在开始之前你需要了解关于socket的知识  http://baike.baidu.com/view/13870.htm

简单来说socket就是ip+端口号的意思,你需要跟其他机子交流你需要链接到正确的端口号上并且该端口号应该有进程在接收与处理数据,或者大概就是这个意思吧~~而正如在命令行下操作发送邮件,我们首先要做的就是要连上smtp服务器,然后再输送命令与数据,所以我们第一步是要连接到服务器smtp服务监听的端口上,163的就是25。

php内置关于socket操作的函数也够全面的了,自己可以在手册中输入socket看看。

对于连上163的smtp,首先使用的是fsockopen(Open Internet or Unix domain socket connection)打开一个socket连接,fsockopen返回的是一个资源类型的数据,换言之可以使用fgets来获取在socket上传输的数据。

$smtp_server = 'smtp.163.com';
$smtp_port = '25';
$fp = fsockopen( $smtp_server , $smtp_port );
echo fgets( $fp );
//220 163.com Anti-spam GT for Coremail System (163com[20101010])
fclose( $fp );

既然可以这样搞,故下面的代码就明了,注意的是可能需要判断一下服务端返回的状态,是否错误,是否可以继续。不过在这个例子中paperen就不写这么严谨了,毕竟最后会分享一个摘自uchome的利用socket发送邮件的函数。

$username = '***';//您邮箱的帐号,@前面的
$password = '***';//密码

$from = 'paperen@163.com';//寄信人邮箱
$to = 'paperen@gmail.com';//收件人邮箱
$smtp_server = 'smtp.163.com';//smtp服务器
$smtp_port = '25';//端口
$message = "Hello paperen,i use php send a mail to you,very cool yet?";//邮件内容
$subject = "Test Only";//邮件标题

set_time_limit(0);

$fp = fsockopen( $smtp_server , $smtp_port );
if( substr( fgets( $fp ), 0, 3 ) != '220' ) exit('connect error');

//hello
fputs($fp, "helo 163\r\n");
if( substr( fgets( $fp ), 0, 3 ) != '250' ) exit('helo error');

//auth login
fputs($fp, "auth login\r\n");
if( substr( fgets( $fp ), 0, 3 ) != '334' ) exit('user error');
fputs($fp, base64_encode( $username ) . "\r\n" );
if( substr( fgets( $fp ), 0, 3 ) != '334' ) exit('pwd error');
fputs($fp, base64_encode( $password ) . "\r\n" );

//auth success
if( substr( fgets( $fp ), 0, 3 ) != '235' ) exit('auth failed');

//mail from
fputs($fp, "mail from:<{$from}>\r\n" );
if( substr( fgets( $fp ), 0, 3 ) != '250' ) exit('mail from error');

//rcpt to
fputs($fp, "rcpt to:<{$to}>\r\n" );
if( substr( fgets( $fp ), 0, 3 ) != '250' ) exit('rcpt to error');

//data
fputs($fp, "data\r\n" );
if( substr( fgets( $fp ), 0, 3 ) != '354' ) exit('data error');

//header
$headers = "mime-version: 1.0\r\n";
$headers .= "from: paperen<{$from}>\r\n";
$headers .= "to: paperen<{$to}>\r\n";
$headers .= "subject: {$subject}\r\n";
$headers .= "content-type: text/html; charset=utf-8\r\n";

fputs($fp, "{$headers}\r\n\r\n" );
fputs($fp, "$message\r\n");
fputs($fp, ".\r\n");

if( substr( fgets( $fp ), 0, 3 ) != '250' ) exit('sendmail failed');
echo 'OK';

fclose( $fp );

20110114205835

就是这么简单就可以用php帮你搞掂,是不是很cool~

下面附带自己在uchome摘出来的一个sendmail函数,具体配置需要自己根据自己需求修改才可以发送,paperen测试过gmail,163,126,sina,hotmail,qq均可以收到邮件。

关于中文标题与内容乱码的问题自己参照sendmail这个函数中看吧,看完你就明白了,主要是43行到53行的代码要看看。

$email_subject = '=?' . $mail['charset'] . '?B?'.base64_encode(preg_replace("/[\r|\n]/", '', '['.$mail['sitename'].'] '.$subject)).'?=';
$email_message = chunk_split(base64_encode(str_replace("\n", "\r\n", str_replace("\r", "\n", str_replace("\r\n", "\n", str_replace("\n\r", "\r", $message))))));

$headers = "From: $email_from{$maildelimiter}X-Priority: 3{$maildelimiter}X-Mailer: ". $mail['sitename'] ."{$maildelimiter}MIME-Version: 1.0{$maildelimiter}Content-type: text/html; charset=" . $mail['charset'] . "{$maildelimiter}Content-Transfer-Encoding: base64{$maildelimiter}";

下载地址 这里

呼·~~好不容易才写完一篇,希望对使用php发送邮件或者想玩玩底层发邮件的你有点帮助吧