PHP邮件技术流程,自己用PHP写的POP3电子邮件收取流程

【小蜗牛嗷嗷之作

etc_20.gif

这里面主要是一个 recvmail() 函数,从POP3服务器检测并收取新的邮件,最后用 update_mail_table() 函数将新邮件信息(发信者, 主题, 发送时间, 邮件文件名, 邮件大小, 附件标志)插入到数据库。

我在 update_mail_table()  函数里写的解释一封电子邮件内容的方法不规范,可能无法正确解释一些不严格遵守MIME规范的邮件。还有一些其它的实用函数,参考了互联网上的别人的一些方法,Thanks the Original Author. ;)

/* 系统默认参数,注意:这里是全局变量 */

$connection=0;   // 保存与主机的连接

$timeout = 5;    // 连接主机的最大超时时间

$err_str='';     // 如果出错,这里保存错误信息

$err_no;         // 如果出错,这里保存错误号码

$resp;           // 临时保存服务器的响应信息

$new_mail_count = 0; //新邮件数目

/*

* 函数功能:接收POP3服务器上的(新)邮件

* 输入参数:$host,$user,$pass

* 返    回:如果顺利执行,返回true,否则返回false,

*           错误信息保存在$err_str

*

*/

function recvmail($host, $user, $pass) {

/* 使用全局的数据库连接 */

global $link;

/* 使用全局的pop3连接参数 */

global $connection;

global $timeout;

global $err_str;

global $err_no;

global $resp;

/* 这次所取回的新邮件数目 */

global $new_mail_count;

global $new_mail_dir;

$mail_uidl_stored = array();    // 数据库里的邮件UIDL列表

$mail_uidl_fresh  = array();    // 邮件服务器上的UIDL列表

/*===================== 从数据库读取UIDL列表 ========================*/

$query = "select * from mail_uid_list";

if ($result = mysqli_query($link, $query)) {

$i = 0;

while ($row = mysqli_fetch_row($result)) {

$mail_uidl_stored[$i++] = $row[0];

}

mysqli_free_result($result);

} else {

printf("Can't query to MySQL Server. Errorcode: %s ", mysqli_error($link));

exit();

}

/*========================= 连接POP3服务器 =========================*/

if (!$connection=fsockopen($host, 110 , &$err_no, &$err_str, $timeout)) {

$err_str="连接到POP服务器失败,错误信息:".$err_str."错误号:".$err_no;

return false;

} else {

getresp();

if (substr($resp,0,3)!="+OK") {

$err_str="服务器返回无效的信息:".$resp."请检查POP服务器是否正确!";

return false;

}

}

/*========================= 登陆POP3服务器 =========================*/

if (!login($user, $pass)) {

$err_str = "帐号或者密码错误!";

return false;

}

/*====================== 获取邮件列表,用UIDL命令 ====================*/

command("UIDL", 3, "+OK");

getresp();

$i = 0;

while ($resp != ".") {

$mail_uidl_key[$i] = strtok($resp," ");

$mail_uidl_fresh[$i] = strtok(" "); // 这是邮件的UID

getresp();

$i++;

}

/*====== 对邮件列表进行分析处理,对比数据库中的信息,收取新邮件 =======*/

$new_mail_uidl = array_diff($mail_uidl_fresh, $mail_uidl_stored);

if (empty($new_mail_uidl)) {

$new_mail_count = 0;

/* 注意:如果没有新邮件,这里就返回了 */

return true;

} else {

$new_mail_count = count($new_mail_uidl);

}

/* 这里巧妙的运用了array_keys函数 */

$new_mail_num = array_keys($new_mail_uidl);

$i = 0;

while (($num = $new_mail_num[$i]) || ($new_mail_num[$i] === 0)) { // 循环收取新邮件

$num += 1;

if (!command("RETR $num", 3, "+OK")) {

return false;

}

$mail_file_str = "";

$mail_str = fgets($connection, 100);

while ($mail_str != ".\r\n") {  // .\r\n 是邮件结束的标志

$mail_file_str .= $mail_str;

$mail_str = fgets($connection, 100);

}

/* 输出邮件文件 */

$mail_file_name_array[$i] = date("YmdHis")."_hoho_".get_radom_str(10);

file_put_contents($new_mail_dir.$mail_file_name_array[$i], $mail_file_str);

$i ++;

}

/*====================== 关闭与服务器连接 =========================*/

if (!command("QUIT",3,"+OK")) {

return false;

}

fclose($connection);

/*====================== 更新数据库UID列表 ========================*/

$i = 0;

while (($num = $new_mail_num[$i]) || ($new_mail_num[$i] === 0)) { // 即使有一封新邮件,也要更新数据库

//如果是大批量数据,最好采用数组合并,但目前没有掌握将数据存放msyql的方法

//$mail_uidl_stored = array_unique(array_merge($mail_uidl_stored, $mail_uidl_fresh));

//只好笨笨的这样做了

$query = "insert into mail_uid_list values('".$new_mail_uidl[$new_mail_num[$i]]."', '".$mail_file_name_array[$i]."')";

$result = mysqli_query($link, $query);

if (!$result) {

printf("Can't query to MySQL Server. Errorcode: %s ", mysqli_error($link));

exit();

}

$i ++;

}

/*================ 更新mail列表 =======================*/

$i = 0;

while ($mail_file_name_array[$i]) {

update_mail_table($mail_file_name_array[$i]);

$i ++;

}

/*=============== 注意:这里不能关闭与数据库的连接 ==================*/

//mysqli_close($link);

return true;

}

function getresp() {

/* 采用全局变量,再三思考,还是认为这样效率高 */

global $connection;

global $resp;

for($resp = "";;) {

if(feof($connection))

return false;

$resp .= fgets($connection,100);

$length = strlen($resp);

if($length >= 2 && substr($resp, $length - 2, 2) == "\r\n") {

$resp = strtok($resp,"\r\n");

return true;

}

}

}

function command($command, $return_lenth=1, $return_code='+') {

/* 采用全局变量,再三思考,还是认为这样效率高 */

global $connection;

global $resp;

global $err_str;

if (!fputs($connection, "$command\r\n")) {

$err_str = "无法发送命令".$command;

return false;

} else {

getresp();

if (substr($resp, 0, $return_lenth) != $return_code) {

$err_str = $command." 命令服务器返回无效:".$resp;

return false;

} else {

return true;

}

}

}

function login($user, $password) {

if (!command("USER $user",3,"+OK")) return false;

if (!command("PASS $password",3,"+OK")) return false;

return true;

}

function get_radom_str($len){

$str = 'abcdefghijklmnopqrstuvwxyz0123456789';

//从以上字串中产生随机串,你如果想要其它字符,可以自行加入,如大写字母

return substr(str_shuffle($str),0,$len);

}

function update_mail_table($mail_file_name) {

global $new_mail_dir;

$mail_file_content = file_get_contents($new_mail_dir.$mail_file_name);

$mail_file_size = filesize($new_mail_dir.$mail_file_name);

/* 记录附件个数和对应名字、大小 */

if ($mail_file_size > 1048576) {

$mail_file_size = round($mail_file_size/1048576, "2")." MB ";

} else if ($mail_file_size > 1024) {

$mail_file_size = round($mail_file_size/1024, "2")." KB ";

} else {

$mail_file_size = $mail_file_size." Bytes ";

}

/*

* 注意!这里好像没有先后,所以不能拿一个作为另一个的参考位置出发点

*/

/*======== 发件人 ========*/

$from_start = strpos($mail_file_content, "\r\nFrom:");

$from_end   = strpos($mail_file_content, "\r", $from_start + 7);

$from_str   = substr($mail_file_content, $from_start, $from_end - $from_start);

if ($sender_start = strpos($from_str, "?B?")) {

$sender_start += 3;

$sender_end = strpos($from_str, "?=", $sender_start);

$sender_str = substr($from_str, $sender_start, $sender_end - $sender_start);

$sender = base64_decode($sender_str);

/* 检测字符集类型,在recvmail_func.php中没有这一项 */

$charset_start = strpos($from_str, "=?") + 2;

$charset_end = strpos($from_str, "?", $charset_start);

$charset = substr($from_str, $charset_start, $charset_end - $charset_start);

} else if ($sender_start = stripos($from_str, "?Q?")) {

$sender_start += 3;

$sender_end = strpos($from_str, "?=", $sender_start);

$sender_str = substr($from_str, $sender_start, $sender_end - $sender_start);

/* 有些变态的名字,还分开几段来写,真郁闷! */

while ($sender_start = stripos($from_str, "?Q?", $sender_end)) {

$sender_start += 3;

$sender_end = strpos($from_str, "?=", $subject_start);

$sender_str .= substr($from_str, $sender_start, $sender_end - $sender_start);

}

$sender = quoted_printable_decode($sender_str);

/* 检测字符集类型,在recvmail_func.php中没有这一项 */

$charset_start = strpos($from_str, "=?") + 2;

$charset_end = strpos($from_str, "?", $charset_start);

$charset = substr($from_str, $charset_start, $charset_end - $charset_start);

} else if ($sender_start = strpos($from_str, "\"")) {

/* “预防”有的邮件没有 "发件人",虽然自己还没见到例外 2008-10-21 */

$sender_start += 1;

$sender_end = strpos($from_str, "\"", $sender_start);

/* 这里是ascii组成 */

$sender = substr($from_str, $sender_start, $sender_end - $sender_start);

} else {

$sender_start = 8;

/* 先看看是否有空格,有空格就以空格为边界 */

if (!$sender_end = strpos($from_str, " ", $sender_start)) {

$sender_end = $from_end;

}

$sender = substr($from_str, $sender_start, $sender_end - $sender_start);

if (substr($sender, 0, 1) == "

$sender = "";

}

}

/* 发件人email地址 */

if ($sender_email_start = strpos($from_str, "

$sender_email_end   = strpos($from_str, ">");

$sender_email = substr($from_str, $sender_email_start + 1, $sender_email_end - $sender_email_start - 1);

if (strlen($sender) > 30 || strlen($sender) == 0){

$sender = $sender_email;

}

}

/*======== 收件人 ========*/

/*

*         暂略

*/

/*========= 主题 =========*/

$subject_start = strpos($mail_file_content, "\r\nSubject:");

$subject_end   = strpos($mail_file_content, "\r", $subject_start+10);

$subject_line  = substr($mail_file_content, $subject_start, $subject_end - $subject_start);

if ($subject_start = strpos($subject_line, "?B?")) {

$subject_start += 3;

$subject_end = strpos($subject_line, "?=", $subject_start);

$subject_str = substr($subject_line, $subject_start, $subject_end - $subject_start);

$subject = base64_decode($subject_str);

/* 检测字符集类型,在recvmail_func.php中没有这一项 */

$charset_start = strpos($subject_line, "=?") + 2;

$charset_end = strpos($subject_line, "?", $charset_start);

$charset = substr($subject_line, $charset_start, $charset_end - $charset_start);

} else if ($subject_start = stripos($subject_line, "?Q?")) {

$subject_start += 3;

$subject_end = strpos($subject_line, "?=", $subject_start);

$subject_str = substr($subject_line, $subject_start, $subject_end - $subject_start);

/* 有些变态的名字,还分开几段来写,真郁闷! */

while ($subject_start = stripos($subject_line, "?Q?", $subject_end)) {

$subject_start += 3;

$subject_end = strpos($subject_line, "?=", $subject_start);

$subject_str .= substr($subject_line, $subject_start, $subject_end - $subject_start);

}

$subject = htmlspecialchars(quoted_printable_decode($subject_str));

/* 检测字符集类型,在recvmail_func.php中没有这一项 */

$charset_start = strpos($subject_line, "=?") + 2;

$charset_end = strpos($subject_line, "?", $charset_start);

$charset = substr($subject_line, $charset_start, $charset_end - $charset_start);

} else {

$subject = substr($subject_line, 11, $subject_end - $subject_start - 11);

}

/*======== 发送日期 =======*/

if ($date_start = strpos($mail_file_content, "\r\nDate:")) {

$date_start += 8;

$date_end   = strpos($mail_file_content, "\r", $date_start);

$date_str   = substr($mail_file_content, $date_start, $date_end - $date_start);

$date = date('Y年m月d日 H:i:s', strtotime($date_str));

} else {

$date = date('Y年m月d日 H:i:s');

}

/* 检查是否有附件 */

if (strpos($mail_file_content, "\r\nContent-Disposition: p_w_upload")) {

$has_p_w_upload = 1;

} else {

$has_p_w_upload = 0;

}

global $link;

if ($charset == "UTF-8" || $charset == "utf-8") {

$sender = iconv("UTF-8", "GB2312", $sender);

$subject = iconv("UTF-8", "GB2312", $subject);

}

/* 插入数据库 */

$query = "insert into mail(Sender, Subject, Sendtime, Filename, Filesize, Attachment) \n

values('$sender', '$subject', '$date', '$mail_file_name', '$mail_file_size', '$has_p_w_upload')";

$result = mysqli_query($link, $query);

if (!$result) {

printf("Can't query to MySQL Server. Errorcode: %s ", mysqli_error($link));

exit();

}

}

?>

------------------------------------------------------------------------------------------

赵小蜗牛

QQ: 755721501

在不断奉献中谋求生存发展、打造自己的优秀品质,用人性最本质最动人的一面“营销”自己!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POP3(Post Office Protocol version 3)是一种用于接收电子邮件的协议。以下是 POP3 接收邮件的基本流程: 1. 建立连接:使用 TCP/IP 协议建立与邮件服务器的连接。 2. 发送身份验证:发送用户名和密码以进行身份验证。 3. 发送命令:发送命令以执行邮件接收操作。常用的命令包括: * USER:指定用户名。 * PASS:指定密码。 * STAT:获取邮箱中的邮件总数和总大小。 * LIST:获取邮件的编号和大小。 * RETR:获取指定邮件的详细内容。 * DELE:标记指定邮件为删除状态。 * QUIT:关闭与服务器的连接。 4. 获取邮件:使用 RETR 命令获取指定邮件的详细内容,然后将其保存到本地计算机上。 5. 删除邮件:使用 DELE 命令将邮件标记为删除状态。 6. 关闭连接:使用 QUIT 命令关闭与服务器的连接。 以下是使用 C++ 实现 POP3 接收邮件的基本代码框架: ```c++ #include <iostream> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") using namespace std; int main() { // 初始化 Winsock 库 WSADATA wsaData; int err = WSAStartup(MAKEWORD(2, 2), &wsaData); if (err != 0) { cout << "WSAStartup failed: " << err << endl; return -1; } // 创建套接字 SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { cout << "socket failed: " << WSAGetLastError() << endl; WSACleanup(); return -1; } // 设置服务器地址和端口号 sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr("邮件服务器地址"); serverAddr.sin_port = htons(110); // 连接服务器 err = connect(sock, (sockaddr*)&serverAddr, sizeof(serverAddr)); if (err == SOCKET_ERROR) { cout << "connect failed: " << WSAGetLastError() << endl; closesocket(sock); WSACleanup(); return -1; } // 发送身份验证信息和命令,接收服务器响应 // ... // 关闭连接 closesocket(sock); WSACleanup(); return 0; } ``` 注意:上述代码仅为参考,具体实现过程需要根据 POP3 协议规范进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值