### 使用 PHP 开发 qmail 邮件服务器管理系统

电子邮件在网络中占有很重要的地位。目前，在企业中运行的邮件服务器均用各自独立的管理系统来实现账号创建、口令修改、邮箱扩容、删除邮箱等功能。当邮箱用户达到一定数量时，邮件管理员的日常维护工作显得极为繁重，这就需要将一部分管理任务（如账号申请）实现自动化处理；同时将一部分任务（如口令修改）由多个分组管理员来负责，从而使邮件管理员从繁琐的维护工作中解脱出来，真正对邮件服务器起到监管作用。
邮件服务器及开发环境的选择
目前很多邮件服务器不提供开发接口，因此在企业内部实现开发邮件管理系统的首要问题是，寻找一种能够与开发语言相结合的开放式邮件系统。
由于对稳定性要求很高，因此大型电子邮件系统一般都使用Unix作为服务器的操作系统。例如，Hotmail使用的是FreeBSD和Solaris系统。
Linux自带的邮件由于在系统结构上存在一定缺陷，难以承受大用户量的访问。qmail是GNU下一款著名的自由软件，是新一代Unix邮件系统，支持Maildir存储方式。它把每个邮件作为一个单独的文件保存在用户个人的邮件目录下。qmail支持虚拟域（Virtual Domain）和虚拟用户（Virtual User）。当前国内流行的免费电子邮件系统大都采用qmail作为基本服务器软件，提供多级目录以支持较大的用户数。
从开发的角度看，PHP+Linux的开发模式已被许多开发人员采用。利用PHP来调用qmail提供的控制程序，实现对邮件系统的各种管理工作。为实现对大量用户的有效控制，还可引入数据库管理。本文将介绍一个PHP +Oracle+qmail+Linux的开发实例。
总体设计
整个系统分为邮箱管理和邮件收发两部分。申请邮箱时，先填写一些必要的信息，然后系统会自动地创建邮箱并允许用户立即使用。当用户忘记密码后，可采用目前互联网的通用做法，通过回答用户自定义的问题来修改邮箱密码。出于安全考虑，在用户三次回答错问题后，系统将该账号的“修复邮箱密码”功能锁定30分钟。
邮件管理依据不同的需求，将用户权限分为以下3种级别：
◆ 普通用户 能够在浏览器中收发电子邮件、修改邮箱密码、修改自定义问题和答案，并进行邮箱的查询。
◆ 分组管理员 除拥有普通用户的功能外，可以修改本组内所有账号的密码，解除本科室账号的“修复邮箱密码”功能锁定。
◆ 邮箱管理员 可以修改全部邮箱口令、删除邮箱、修改邮箱容量、查看邮箱的申请情况，解除全部账号的“修复邮箱密码”功能锁定。
邮件的收发采用PHP提供的标准POP3函数，可获得邮件清单、查看邮件的详细内容、发送带多个附件的邮件，并提供邮件删除、回复等功能。
数据库主要由以下几个表组成：
◆ email_info 存放所有电子邮箱的相关信息，如账号、人员姓名、科室、联系电话、自定义问题、自定义问题的答案、锁定标记等。
◆ email_register_info 存放用户申请电子邮件时填写的信息，如账号、密码、申请时间、科室、申请的当前步骤（主要是为了防止用户恶意跳过某些步骤而设定的）。
◆ email_change_log 记录用户电子邮箱的变化情况，以备日后需要时检查。主要记录有邮件的申请时间、删除时间、邮箱账号、对邮箱操作的人员姓名、IP地址等信息。
技术难点分析
PHP调用qmail的控制程序
在Linux环境中，每一个程序都有相应的用户和组的概念。PHP程序在服务器中执行时，默认的用户是nobody，没有权利执行qmail的控制程序。在Linux里面有个sudo命令，允许其它用户以root身份执行一些命令。修改/etc/sudoers文件，增加以下部分：

nobody ALL=/var/vpopmail/bin/vadduser (增加用户) nobody ALL=/var/vpopmail/bin/vdeluser (删除用户) nobody ALL=/var/vpopmail/bin/vpasswd (修改口令) nobody ALL=/var/vpopmail/bin/vchkpw (检查用户口令是否正确) nobody ALL=/var/vpopmail/bin/vsetuserquota (修改邮箱最大容量)

nobody ALL=/var/vpopmail/bin/vmoduser (修改用户信息)

root ALL=(ALL) ALL

在调用qmail控制程序时，需要用户手工输入一部分信息。如果要实现自动化，还需要使用Linux中的重定向技术，将用户预先输入的信息存放到文件中，使用重定向技术传递为Shell脚本。
PHP提供执行外部命令的函数为system()、exec()。system()函数执行给定的命令、输出和返回结果。exec()函数与system()类似，但不输出结果。使用程序控制必须选用exec()函数，并根据执行后的状态来确定控制程序是否正确执行，如果出现错误需要向邮件管理员通告。下面代码以“增加用户”功能为例进行说明：

require("/home/httpd/phplib/qmail.inc"); $qmail_date = "v1"; $qmail_email = new register_email ; $sql = "select pw_name from ".$qmail_date; $qmail_email->query($sql);

while ($qmail_email->next_record())

{

$qmail_user = $qmail_email->f("pw_name");

$passwd = "12345";

$str_command = "sudo /var/vpopmail/bin/vadduser " .$qmail_user.;

$str_command = $str_command."@mail.com".$passwd." -q 10000000 < /home/n";

@exec($str_command,$str,&$result);

if ($result != 0 )

{

echo "command string is :".$str_command." , command is failed!!!<br>";

$error_info = "在执行vadduser命令时失败";

$address = "From: computer@mail.com\nReply-To: computer@mail.com\n" ;

mail("webmaster@mail.com", $error_info , $message,$address );

}

}

$qmail_email->free();

其它功能如修改口令、修改邮箱容量、删除邮箱等，在程序实现上非常类似，不做过多阐述。
E-mail中附件的上传及下载
PHP本身提供上载功能，但根据实际情况，可以相应做一些配置和错误处理。用户可以通过修改php.ini文件来扩大上载文件的最大容量。同时，可以通过在网页的Form中增加的方法，将单个附件的大小限制在5MB以内。如果网络速度比较慢，则需要设置网页的timeout变量，否则上载时会因为时间太长而超时。在服务器端的处理程序部分代码如下：

if (!file_exists($mail_att)) //判断文件是否上载成功 { //错误处理及显示 break ; } copy ($mail_att, $mail_att.".att") ; //将附件重新改名并拷贝到指定位置。

for ($i = 1; $i <= $num_attach; $i++)

{

$file_name = "send_att".$i; //得到上传文件的原始名称

$file_tmp = "send_att_tmp".$i; //得到上传文件在服务器中的临时文件名称

$file_size = "send_att_size".$i; //得到上传文件的大小

$file_mime = "send_att_mime".$i; //得到上传文件的类型

}

在提供附件下载时，这里没有采用常用做法，即给用户提供文件的URL。因为这种做法理论上并不安全，用户有可能通过链接直接下载到该文件。相反，从浏览器无法访问到的目录下读出文件提供给用户下载，就不会遇到类似安全问题。程序核心代码如下：

if (file_exists($attach_filepos)) //判断文件是否存在 { $size = filesize($attach_filepos); //得到文件的大小 //将用户原始文件名提供给用户下载。 header("Content-Disposition: attachment; filename=".$attach_filename);

header("Content-length: ".$size);

header("Content-type: application/x-zip-compressed");

readfile($attach_filepos); //将下载文件读出，提供给用户下载。

}

结束语
该系统在技术上很完美地将PHP与Oracle数据库结合起来，实现对qmail用户的管理及日常邮箱服务器的维护。目前该系统已在我公司内部使用了一年多，效果很好。它一方面减轻了邮件管理员的日常维护工作；另一方面为不太熟悉邮件配置的用户提供网上收发邮件。此系统还有认证、分组管理及邮件收发、汉字编码等方面的功能，由于篇幅有限就不一一阐述。