根据官方文档以及一些网友的分享,整理编写了IMAP方式访问Gmail邮箱的代码。经过反复测试和调整,中文目录名称显示的问题也终于得到了解决。
<?php
/*
* PHP访问gmail IMAP邮箱的完成代码。
* 示例1:列出邮箱的子目录名称
* 示例2:取出收件箱(INBOX)下所有邮件。可以正确显示中文字符。
*
* 整理/编写:www.tudaxia.com, 2014年1月
* 感谢互联网分享给我们的一切知识!
*/
// gmail邮箱地址
//(注:也可以是托管在Google APP上的账号,实际也是gmail服务器负责提供邮件功能)
$gmail_account = 'your_name@gmail.com';
// gmail邮箱密码
$gmail_password = 'your_gmail_password';
// gmail imap邮件服务器地址
$gmail_imap_host = 'imap.googlemail.com';
// imap服务器端口
$gmail_imap_post = 993;
// 根据以上参数,拼凑出imap服务器的完整地址
$gmail_imap_server = '{'.$gmail_imap_host.':'.$gmail_imap_post.'/novalidate-cert/imap/ssl}';
/*
===========================
示例1:gmail的中文目录编码与解码
===========================
(Gmail内部使用UTF7-IMAP编码,所以如果直接显示会乱码,需要进行转码才能正确显示)
*
*/
$imap_code = "&V4NXPpCuTvY-";
echo "imap_code: $imap_code\n";
$hanzi = mb_convert_encoding($imap_code, "UTF-8", "UTF7-IMAP");
echo "中文名称 : $hanzi\n";
$encode= mb_convert_encoding($hanzi, "UTF7-IMAP","UTF-8");
echo "encode : $encode\n";
/*
===========================
// 示例2: 列出所有的邮件Label(相当于邮箱的子目录)
===========================
*
*/
if (($mbox = @imap_open($gmail_imap_server, $gmail_account, $gmail_password)) == true) {
$folders = imap_list($mbox, $gmail_imap_server, "*");
foreach ($folders as $folder) {
// Gmail邮箱目录采用的编码为"UTF7-IMAP",因此如果要正确显示中文目录名称,需要针对中文目录名称进行UTF-8转码
// (反之,如果给出中文名字,需要访问gmail的目录,需要先执行UTF-8到UTF7-IMAP的逆向转码)
$folder = mb_convert_encoding($folder, "UTF-8", "UTF7-IMAP");
echo $folder . "\n";
}
// 关闭imap连接
imap_close($mbox);
}
/*
===========================
// 示例3:查看收件夹(INBOX)的所有邮件
*
*/
if (($mailbox_inbox = @imap_open($gmail_imap_server."INBOX", $gmail_account, $gmail_password)) == true) {
echo "处理INBOX \n";
scan_mailbox($mailbox_inbox);
imap_close($mailbox_inbox);
}
function scan_mailbox($mbox) {
// 获取邮箱信息
$mboxes=imap_mailboxmsginfo($mbox);
// 查看是否有新邮件
if( $mboxes->Nmsgs != 0 ) {
for( $mailno=1; $mailno<=$mboxes->Nmsgs; $mailno++ ) {
// 获取邮件内容
$email = fetchEmail($mbox, $mailno);
var_dump($email);
// 删除邮件(打上删除标记)
//imap_delete($mbox, $mailno);
}
// 删除所有打上删除标记的邮件
//imap_expunge($mbox);
}
}
/**
* 获取一封邮件的信息
* @param resource $imap_stream
* @param int $msg_number
*/
function fetchEmail($mbox , $mailno) {
// 获取邮件内容
$email = array();
// 获取Header信息
$head=imap_header($mbox, $mailno);
// 获取邮件的发件人地址
$email['from_address']=$head->from[0]->mailbox.'@'.$head->from[0]->host;
// 初始化邮件主题变量
$subject = null;
if( !empty($head->subject) ) {
// 编码转换
$mhead=imap_mime_header_decode($head->subject);
foreach( $mhead as $key=>$value) {
if( $value->charset != 'default' ) {
$subject.=mb_convert_encoding($value->text,'UTF-8',$value->charset);
}else{
$subject.=$value->text;
}
}
}
$email['subject'] = $subject;
global $charset,$htmlmsg,$plainmsg,$attachments;
$htmlmsg = $plainmsg = $charset = '';
$attachments = array();
// BODY
$s = imap_fetchstructure($mbox,$mailno);
if (!$s->parts) // simple
getpart($mbox,$mailno,$s,0); // pass 0 as part-number
else { // multipart: cycle through each part
foreach ($s->parts as $partno0=>$p)
getpart($mbox,$mailno,$p,$partno0+1);
}
$email['plainmsg'] = $plainmsg;
$email['htmlmsg'] = $htmlmsg;
$email['attachments'] = $attachments;
return $email;
}
function getpart($mbox,$mid,$p,$partno) {
// $partno = '1', '2', '2.1', '2.1.3', etc for multipart, 0 if simple
global $htmlmsg,$plainmsg,$charset,$attachments;
// DECODE DATA
$data = ($partno)? imap_fetchbody($mbox,$mid,$partno): imap_body($mbox,$mid); // simple
// PARAMETERS
// get all parameters, like charset, filenames of attachments, etc.
$params = array();
if ($p->parameters)
foreach ($p->parameters as $x)
$params[strtolower($x->attribute)] = $x->value;
if (isset($p->dparameters))
foreach ($p->dparameters as $x)
$params[strtolower($x->attribute)] = $x->value;
// ATTACHMENT
// Any part with a filename is an attachment,
// so an attached text file (type 0) is not mistaken as the message.
if (isset($params['filename']) || isset($params['name'])) {
// filename may be given as 'Filename' or 'Name' or both
$filename = ($params['filename'])? $params['filename'] : $params['name'];
// filename may be encoded, so see imap_mime_header_decode()
$attachments[$filename] = $data; // this is a problem if two files have same name
}
// TEXT
if( $p->type==0 && !empty($data) ) {
$charset = $params['charset'];
$encoding=$p->encoding;
// 根据encoding参数,进行转码
switch( $encoding ) {
case 0 :
$data=mb_convert_encoding($data, "UTF-8", $charset);
break;
case 1 :
$encode_data=imap_8bit($data);
$encode_data=imap_qprint($encode_data);
$data=mb_convert_encoding($encode_data, "UTF-8", $charset);
break;
case 3 :
$encode_data=imap_base64($data);
$data=mb_convert_encoding($encode_data, "UTF-8", $charset);
break;
case 4 :
$encode_data=imap_qprint($data);
$data=mb_convert_encoding($encode_data, 'UTF-8', $charset);
break;
case 2 :
case 5 :
default:
// 转码失败
break;
}
if (strtolower($p->subtype)=='plain') {
$plainmsg .= trim($data);
} else {
$htmlmsg .= $data;
}
}
// EMBEDDED MESSAGE
// Many bounce notifications embed the original message as type 2,
// but AOL uses type 1 (multipart), which is not handled here.
// There are no PHP functions to parse embedded messages,
// so this just appends the raw source to the main message.
if ($p->type==2 && $data) {
$plainmsg .= $data;
}
// SUBPART RECURSION
if (isset($p->parts)) {
foreach ($p->parts as $partno0=>$p2)
getpart($mbox,$mid,$p2,$partno.'.'.($partno0+1)); // 1.2, 1.2.1, etc.
}
}
?>