Loading... > 此方法初始目的来源于公司邮箱数据库里面有损坏的邮件,导致MAC版本客户端无法使用POP3协议拉取邮件。</span> 原理为使用POP3协议的命令操作删除数据库内损坏的邮件列表,从而解决通过POP3协议拉取邮件时卡住不拉取邮件的问题。 方法采取脚本方式,使用PHP编写,下面是代码,贴出来共享。 > 使用方法: - `php fixmail.php username password` ```PHP <?php /* * Fix mail by deleting corrupted mails. * Use USER and PASS * POP3 protocol refer RFC1939 (http://tools.ietf.org/rfc/rfc1939.txt) */ $host = "邮箱服务器域名或IP"; $port = "110"; // secure port is 995 if ($argc != 3) { print "Usage: \n"; print "\t" . $argv[0] . " user pass\n"; print "\n"; exit; } $username = $argv[1]; $password = $argv[2]; function sendQuery($socket, $CMD, $data = '') { $data = trim($data); if (empty($data)) { $send = "$CMD\r\n"; } else { $send = "$CMD $data\r\n"; } socket_send($socket, $send, strlen($send), 0); return; } function getResult($socket, $CMD = '') { $retBuffer = ''; while(($len = @socket_recv($socket, $buffer, 1024, 0)) >0) { //print $buffer; //print "\n"; $retBuffer .= $buffer; $n = strlen($retBuffer); if (($CMD == 'LIST' || $CMD == 'TOP' || $CMD == 'RETR' || $CMD == 'UIDL') && ($retBuffer[0] == '+' && $retBuffer[1] == 'O' && $retBuffer[2] == 'K') && ! ($retBuffer[$n-1] == "\n" && $retBuffer[$n-2] == "\r" && $retBuffer[$n-3] == '.')) { // POP3协议返回数据 // 第一行为状态码 +OK 或者 -ERR // 若有数据,数据以 ".\r\n" 结束 $buffer = ''; continue; } break; } return $retBuffer; } function getConnection($host, $port) { $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("Unable to create socket\n"); socket_connect($socket, $host, $port); $r = getResult($socket); // Get greeting info print $r; return $socket; } function getLoginSession($host, $port, $user, $pass) { $socket = getConnection($host, $port); sendQuery($socket, 'USER', $user); $r = getResult($socket, 'USER'); print $r; sendQuery($socket, 'PASS', $pass); $r = getResult($socket, 'PASS'); print $r; return $socket; } function getMailIdList($socket) { sendQuery($socket, 'LIST'); $r = getResult($socket, 'LIST'); $lines = explode("\r\n", $r); $lines = array_filter($lines); $arrMailId = array(); foreach($lines as $v) { if ($v[0] == '+' && $v[1] == 'O' && $v[2] == 'K') continue; if ($v[0] == '.') continue; $v = trim($v); if (empty($v)) continue; $mid = explode(' ', $v); //print "$v\n"; $arrMailId[] = $mid[0]; } return $arrMailId; } function checkMailCorrupt($socket, $mailId) { sendQuery($socket, 'TOP', "$mailId 0"); $r = getResult($socket, 'TOP'); $r = trim($r); if ($r == '-ERR Message corrupted') { print "$mailId $r\n"; return 1; } else if ($r[0] == '-' && $r[1] == 'E' && $r[2] == 'R' && $r[3] == 'R') { print "$mailId $r\n"; return 2; } return 0; } function deleteMail($socket, $mailId) { sendQuery($socket, 'DELE', "$mailId"); $r = getResult($socket, 'DELE'); print "DELE $mailId " . $r; return; } function quitAndClose(& $socket) { sendQuery($socket, 'QUIT'); $r = getResult($socket, 'QUIT'); socket_close($socket); $socket = null; print $r; return; } // START // get mail id list $socket = getLoginSession($host, $port, $username, $password); $arrMailId = getMailIdList($socket); quitAndClose($socket); $totalMail = count($arrMailId); print "\nTotal mail count $totalMail\n\n"; // delete corrupt mail // 删除之后id会重新补齐,所以从最大id开始 // 同一封邮件id在不同会话之间不一定相同, 但可以通过UIDL来获得邮件唯一ID标识 // 所以邮件客户端会先获取UIDL, 然后再获取LIST, 最后RETR获取邮件 $totalCorrupt = 0; $cur = $totalMail - 1; while ($cur >= 0) { $n = 6; $socket = getLoginSession($host, $port, $username, $password); while(($n > 0) && ($cur >= 0)) { $id = $arrMailId[$cur]; $r = checkMailCorrupt($socket, $id); if ($r == 1) { $totalCorrupt ++; deleteMail($socket, $id); $n --; } else if ($r != 0) { $n --; } $cur --; } quitAndClose($socket); } print "\nTotal mail corrupt count $totalCorrupt\n\n"; ``` > [脚本下载](https://pan.wsczx.com/d/f/621936942736478211) Last modification:January 12, 2022 © Allow specification reprint Support Appreciate the author AliPayWeChat Like 0 如果觉得我的文章对你有用,请随意赞赏