PHP 发送Email的几种方法

在php中发送Email可以直接调用系统的mail()函数来完成,但是前提是你在php.ini文件中对mail都已经配置好了,以下为相关的配置信息:

[mail function]
; For Win32 only.
SMTP = localhost
smtp_port = 25
 
; For Win32 only.
;sendmail_from = me@example.com
 
; For Unix only.  You may supply arguments as well (default: "sendmail -t -i").
;sendmail_path =
 
; Force the addition of the specified parameters to be passed as extra parameters
; to the sendmail binary. These parameters will always replace the value of
; the 5th parameter to mail(), even in safe mode.
;mail.force_extra_parameters =

Mail 配置选项

名称 默认 描述 可更改

SMTP “localhost” Windows 专用:SMTP 服务器的 DNS 名称或 IP 地址。 PHP_INI_ALL

smtp_port “25” Windows 专用:SMTP 段口号。自 PHP 4.3 起可用。 PHP_INI_ALL

sendmail_fromNULL

Windows 专用:规定从 PHP 发送的邮件中使用的 “from”

地址。

PHP_INI_ALL

sendmail_path NULL Unix 系统专用:规定sendmail 程序的路径(通常 /usr/sbin/sendmail 或 /usr/lib/sendmail) PHP_INI_SYSTEM

上面写的很清楚,要是windows的服务器,必须装好开启本地的smtp服务器,在linux和unix下,要用到sendmail,所以得配置好sendmail,根据自己的实际情况选择适当的配置信息。

mail()函数如果邮件的投递被成功地接收,则返回 true,否则返回 false,语法:

mail($to,$subject,$message,$headers,$parameters)

参数 描述

$to 必需。规定邮件的接收者。

$subject 必需。规定邮件的主题。该参数不能包含任何换行字符。

$message 必需。规定要发送的消息。

$headers 必需。规定额外的报头,比如 From, Cc 以及 Bcc。

$parameters 必需。规定 sendmail 程序的额外参数。

简单的发封邮件,代码如下:

<?php
 
$txt = "First line of text\nSecond line of text";
 
// 如果一行大于 70 个字符,请使用 wordwrap()。
$txt = wordwrap($txt,70);
 
// 发送邮件
mail("somebody@example.com","My subject",$txt);
?>

如果是一封带HTML格式的Email则代码如下:

<?php
 
$to = "somebody@example.com, somebodyelse@example.com";
$subject = "HTML email";
 
$message = "
<html>
<head>
<title>HTML email</title>
</head>
<body>
<p>This email contains HTML Tags!</p>
<table>
<tr>
<th>Firstname</th>
<th>Lastname</th>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
</tr>
</table>
</body>
</html>
";
 
// 当发送 HTML 电子邮件时,请始终设置 content-type
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=iso-8859-1" . "\r\n";
 
// 更多报头
$headers .= 'From: <webmaster@example.com>' . "\r\n";
$headers .= 'Cc: myboss@example.com' . "\r\n";
 
mail($to,$subject,$message,$headers);
?>

函数很简单,看似很好用,但是实际上局限性很明显,必须是在本地的开启smtp的情况下,而且经过测试成功率不是很高,所以程序中很少有人用到mail()函数来发邮件。

如果要扩展功能的话,还得重新构造,网上也有好多现成的类可以直接调用来实现,其实就是靠fsockopen来进行连接smtp,下面的代码是个思路:

<?php
/**
	名称:smtpsend . class . php功能:
	邮件发送类, 实现邮件发送功能, 可以发送html邮件;可验证用户是否具有发送权限;可实现从任意服务器邮箱发送邮件,并非局限于本机。 $smtpserver;
	SMTP服务器 $smtpserverport;
	SMTP服务器端口 $smtpuser;
	SMTP服务器的用户帐号 $smtppass;
	SMTP服务器的用户密码 $fromMail;
	SMTP服务器的用户邮箱 $toMail;
	发送给谁 $subject;
	邮件主题 $content;
	邮件内容 $mailtype;
	邮件格式(HTML / TXT), TXT为文本邮件 
*/
 
class smtpclass {
	function smtp($relay_host = "", $smtp_port = 25, $auth = false, $user, $pass) {
		$this->debug = FALSE;
		$this->smtp_port = $smtp_port;
		$this->relay_host = $relay_host;
		$this->time_out = 60; //is used in fsockopen()
		$this->auth = $auth; //auth
		$this->user = $user;
		$this->pass = $pass;
		$this->host_name = "localhost"; //is used in HELO command
		$this->log_file = "";
		$this->sock = FALSE;
	}
	/* Main Function */
	function sendmail($to, $from, $subject = "", $body = "", $mailtype, $returnpath = "", $cc = "", $bcc = "", $additional_headers = "") {
		$mail_from = $this->get_address($this->strip_comment($from));
		$body = ereg_replace("(^|(\r\n))(\.)", "\1.\3", $body);
		$header = "";
		if (isset($returnpath) && $returnpath != "") {
			$header.= "Reply-To:" . $returnpath . "\r\n";
		}
		$header.= "MIME-Version:1.0\r\n";
		if ($mailtype == "HTML") {
			$header.= 'Content-Type:text/html; charset=gb2312' . "\r\n";
		}
		$header.= "To: " . $to . "\r\n";
		if ($cc != "") {
			$header.= "Cc: " . $cc . "\r\n";
		}
		$header.= "From: $from<" . $from . ">\r\n";
		$header.= "Subject: " . $subject . "\r\n";
		$header.= $additional_headers;
		$header.= "Date: " . date("r") . "\r\n";
		$header.= "X-Mailer:By Redhat (PHP/" . phpversion() . ")\r\n";
		list($msec, $sec) = explode(" ", microtime());
		$header.= "Message-ID: <" . date("YmdHis", $sec) . "." . ($msec * 1000000) . "." . $mail_from . ">\r\n";
		$TO = explode(",", $this->strip_comment($to));
		if ($cc != "") {
			$TO = array_merge($TO, explode(",", $this->strip_comment($cc)));
		}
		if ($bcc != "") {
			$TO = array_merge($TO, explode(",", $this->strip_comment($bcc)));
		}
		$sent = TRUE;
		foreach ($TO as $rcpt_to) {
			$rcpt_to = $this->get_address($rcpt_to);
			if (!$this->smtp_sockopen($rcpt_to)) {
				$this->log_write("Error: Cannot send email to " . $rcpt_to . "\n");
				$sent = FALSE;
				continue;
			}
			if ($this->smtp_send($this->host_name, $mail_from, $rcpt_to, $header, $body)) {
				$this->log_write("E-mail has been sent to <" . $rcpt_to . ">\n");
			} else {
				$this->log_write("Error: Cannot send email to <" . $rcpt_to . ">\n");
				$sent = FALSE;
			}
			fclose($this->sock);
			$this->log_write("Disconnected from remote host\n");
		}
		return $sent;
	}
	/* Private Functions */
	function smtp_send($helo, $from, $to, $header, $body = "") {
		if (!$this->smtp_putcmd("HELO", $helo)) {
			return $this->smtp_error("sending HELO command");
		}
		//auth
		if ($this->auth) {
			if (!$this->smtp_putcmd("AUTH LOGIN", base64_encode($this->user))) {
				return $this->smtp_error("sending HELO command");
			}
			if (!$this->smtp_putcmd("", base64_encode($this->pass))) {
				return $this->smtp_error("sending HELO command");
			}
		}
		//
		if (!$this->smtp_putcmd("MAIL", "FROM:<" . $from . ">")) {
			return $this->smtp_error("sending MAIL FROM command");
		}
		if (!$this->smtp_putcmd("RCPT", "TO:<" . $to . ">")) {
			return $this->smtp_error("sending RCPT TO command");
		}
		if (!$this->smtp_putcmd("DATA")) {
			return $this->smtp_error("sending DATA command");
		}
		if (!$this->smtp_message($header, $body)) {
			return $this->smtp_error("sending message");
		}
		if (!$this->smtp_eom()) {
			return $this->smtp_error("sending <CR><LF>.<CR><LF> [EOM]");
		}
		if (!$this->smtp_putcmd("QUIT")) {
			return $this->smtp_error("sending QUIT command");
		}
		return TRUE;
	}
	function smtp_sockopen($address) {
		if ($this->relay_host == "") {
			return $this->smtp_sockopen_mx($address);
		} else {
			return $this->smtp_sockopen_relay();
		}
	}
	function smtp_sockopen_relay() {
		$this->log_write("Trying to " . $this->relay_host . ":" . $this->smtp_port . "\n");
		$this->sock = @fsockopen($this->relay_host, $this->smtp_port, $errno, $errstr, $this->time_out);
		if (!($this->sock && $this->smtp_ok())) {
			$this->log_write("Error: Cannot connenct to relay host " . $this->relay_host . "\n");
			$this->log_write("Error: " . $errstr . " (" . $errno . ")\n");
			return FALSE;
		}
		$this->log_write("Connected to relay host " . $this->relay_host . "\n");
		return TRUE;
	}
	function smtp_sockopen_mx($address) {
		$domain = ereg_replace("^.+@([^@]+)$", "\1", $address);
		if (!@getmxrr($domain, $MXHOSTS)) {
			$this->log_write("Error: Cannot resolve MX \"" . $domain . "\"\n");
			return FALSE;
		}
		foreach ($MXHOSTS as $host) {
			$this->log_write("Trying to " . $host . ":" . $this->smtp_port . "\n");
			$this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->time_out);
			if (!($this->sock && $this->smtp_ok())) {
				$this->log_write("Warning: Cannot connect to mx host " . $host . "\n");
				$this->log_write("Error: " . $errstr . " (" . $errno . ")\n");
				continue;
			}
			$this->log_write("Connected to mx host " . $host . "\n");
			return TRUE;
		}
		$this->log_write("Error: Cannot connect to any mx hosts (" . implode(", ", $MXHOSTS) . ")\n");
		return FALSE;
	}
	function smtp_message($header, $body) {
		fputs($this->sock, $header . "\r\n" . $body);
		$this->smtp_debug("> " . str_replace("\r\n", "\n" . "> ", $header . "\n> " . $body . "\n> "));
		return TRUE;
	}
	function smtp_eom() {
		fputs($this->sock, "\r\n.\r\n");
		$this->smtp_debug(". [EOM]\n");
		return $this->smtp_ok();
	}
	function smtp_ok() {
		$response = str_replace("\r\n", "", fgets($this->sock, 512));
		$this->smtp_debug($response . "\n");
		if (!ereg("^[23]", $response)) {
			fputs($this->sock, "QUIT\r\n");
			fgets($this->sock, 512);
			$this->log_write("Error: Remote host returned \"" . $response . "\"\n");
			return FALSE;
		}
		return TRUE;
	}
	function smtp_putcmd($cmd, $arg = "") {
		if ($arg != "") {
			if ($cmd == "") $cmd = $arg;
			else $cmd = $cmd . " " . $arg;
		}
		fputs($this->sock, $cmd . "\r\n");
		$this->smtp_debug("> " . $cmd . "\n");
		return $this->smtp_ok();
	}
	function smtp_error($string) {
		$this->log_write("Error: Error occurred while " . $string . ".\n");
		return FALSE;
	}
	function log_write($message) {
		$this->smtp_debug($message);
		if ($this->log_file == "") {
			return TRUE;
		}
		$message = date("M d H:i:s ") . get_current_user() . "[" . getmypid() . "]: " . $message;
		if (!@file_exists($this->log_file) || !($fp = @fopen($this->log_file, "a"))) {
			$this->smtp_debug("Warning: Cannot open log file \"" . $this->log_file . "\"\n");
			return FALSE;;
		}
		flock($fp, LOCK_EX);
		fputs($fp, $message);
		fclose($fp);
		return TRUE;
	}
	function strip_comment($address) {
		$comment = "\([^()]*\)";
		while (ereg($comment, $address)) {
			$address = ereg_replace($comment, "", $address);
		}
		return $address;
	}
	function get_address($address) {
		$address = ereg_replace("([ \t\r\n])+", "", $address);
		$address = ereg_replace("^.*<(.+)>.*$", "\1", $address);
		return $address;
	}
	function smtp_debug($message) {
		if ($this->debug) {
			echo $message;
		}
	}
	function senduserMail($smtpserver, $smtpserverport = 25, $smtpuser, $smtppass, $fromMail, $toMail, $subject, $content, $mailtype = 'HTML') {
		if ($fromMail == "") {
			die("发件人不能为空!");
		}
		if ($smtpuser == "") {
			die("用户名不能为空!");
		}
		if ($smtppass == "") {
			die("用户密码不能为空!");
		}
		if ($subject == "") {
			die("标题不能为空!");
		}
		if ($toMail == "") {
			die("收件人不能为空!");
		}
		if ($content == "") {
			die("内容不能为空!");
		}
		$smtpserver = $smtpserver; //SMTP服务器
		$smtpserverport = $smtpserverport; //SMTP服务器端口
		$smtpuser = $smtpuser; //SMTP服务器的用户帐号
		$smtppass = $smtppass; //SMTP服务器的用户密码
		$smtpusermail = $fromMail; //SMTP服务器的用户邮箱
		$smtpemailto = $toMail; //发送给谁
		$mailsubject = $subject; //邮件主题
		$mailbody = $content; //邮件内容
		$mailtype = $mailtype; //邮件格式(HTML/TXT),TXT为文本邮件
		$this->smtp($smtpserver, $smtpserverport, true, $smtpuser, $smtppass); //这里面的一个true是表示使用身份验证,否则不使用身份验证.
		//$smtp->debug = TRUE;//是否显示发送的调试信息
		$this->sendmail($smtpemailto, $smtpusermail, $mailsubject, $mailbody, $mailtype);
	}
}
//$smtp = new smtpclass();
//$smtp->senduserMail("mail.163.com",25,"用户名","密码","xxx@xxx.com.cn","xx@xx.com","测试","测试一下","TXT");
    
?>

以上在网上看到的,其实具体的方法都是大同小异,用的很多的是一个开源的叫phpmailer,很方便的。用搜索引擎搜下然后下载就行。

这里贴出phpmailer的测试代码:

<?php
require ("class.phpmailer.php");
require ("class.smtp.php");
//以下是实例:
$mail = new phpmailer(); //建立邮件发送类
$address = xxx@xxx . com;
$mail->IsSMTP(); // 使用SMTP方式发送
$mail->Host = "mail.xxx.com"; // 您的企业邮局域名
$mail->SMTPAuth = false; // 启用SMTP验证功能
$mail->Username = "xxx"; // 邮局用户名(请填写完整的email地址)
$mail->Password = "xxx"; // 邮局密码
$mail->From = "xxxx@xxxx.cn"; //邮件发送者email地址
$mail->FromName = "您的名称";
$mail->AddAddress("$address", ""); //收件人地址,可以替换成任何想要接收邮件的email信箱,格式是AddAddress("收件人email","收件人姓名")
//$mail->AddReplyTo("", "");
//$mail->AddAttachment("/var/tmp/file.tar.gz"); // 添加附件
//$mail->IsHTML(true); // set email format to HTML //是否使用HTML格式
$mail->Subject = "PHPMailer测试邮件"; //邮件标题
$mail->Body = "Hello,这是测试邮件"; //邮件内容
$mail->AltBody = "This is the body in plain text for non-HTML mail clients"; //附加信息,可以省略
if (!$mail->Send()) {
    echo "邮件发送失败. <p>";
    echo "错误原因: " . $mail->ErrorInfo;
    exit;
}
echo "邮件发送成功";
?>