模块

Mail

邮件发送。

用法举例:

$mail = new Mail(array( 'debug' => 1, 'method' => 'mail', 'html' => 1, 'debug_path' => '/tmp/_mail', 'charset' => 'utf-8', ) ); $mail->setFrom('support@kilofox.net', "这是\r\n一封邮件"); $mail->setTo('me@mydomain.com'); $mail->addBCC('myfriend@mydomain.com'); $mail->addBCC('myotherfriend@mydomain.com'); $mail->setSubject('这是一个测试!'); $mail->setBody('我们拥有 HTML 能力!

但这只是一个测试……'); $mail->send();

package
BootPHP/邮件
author
Tinsh
copyright
© 2005-2016 Kilofox Studio

该类在 MODPATH/mail/classes/mail.php 第 30 行声明。

常量

header_eol

string(1) "
"

属性

public boolean $error

错误标志

public string $error_help

错误描述

public string $error_msg

错误信息

public string $smtp_code

SMTP: 返回代码

public string $smtp_helo

SMTP: HELO 或 EHLO

public string $smtp_msg

SMTP 内容

protected static $_instance

Mail 实例

NULL

private array $bcc

BCC 邮件地址

private string $boundry

附件:边界

private string $char_set

Email 字符集

private string $extra_opts

PHP mail() 额外参数

private string $from

发件人邮件地址

private string $from_display

发件人邮件地址(用于显示)

private integer $html_email

HTML 邮件标记

private array $mail_headers

邮件头

private string $mail_method

默认邮递方式(mail 或 smtp)

private string $message

邮件内容

private string $multipart

附件:多部分

private array $parts

附件:部分

private string $pt_message

普通文本内容

private resource $smtp_fp

SMTP 源

private string $smtp_host

SMTP 主机

private string $smtp_pass

SMTP 密码

private integer $smtp_port

SMTP 端口

private string $smtp_user

SMTP 用户名

private string $subject

邮件标题

private integer $temp_dump

将邮件转储到 Flat File,用于测试

private string $temp_dump_path

邮件转储路径

private string $to

收件人邮件地址

private boolean $wrap_brackets

SMTP: 将邮件地址包在括号内的标记

方法

public __construct( [ array $opts = array(0) ] ) (在 Mail 中定义)

构造方法

参数

  • array $opts = array(0) - 要初始化的类的参数

返回值

  • void

源代码

public function __construct($opts = array())
{
	$this->mail_method = $opts['method'] && in_array(strtolower($opts['method']), array('smtp', 'mail')) ? strtolower($opts['method']) : 'mail';
	$this->temp_dump = isset($opts['debug']) && $opts['debug'] ? 1 : 0;
	$this->temp_dump_path = isset($opts['debug_path']) && $opts['debug_path'] ? $opts['debug_path'] : '';
	$this->html_email = isset($opts['html']) && $opts['html'] ? 1 : 0;
	$this->char_set = isset($opts['charset']) && $opts['charset'] ? $opts['charset'] : 'utf-8';
	$this->smtp_host = isset($opts['smtp_host']) && $opts['smtp_host'] ? $opts['smtp_host'] : '';
	$this->smtp_port = isset($opts['smtp_port']) && $opts['smtp_port'] ? intval($opts['smtp_port']) : 25;
	$this->smtp_user = isset($opts['smtp_user']) && $opts['smtp_user'] ? $opts['smtp_user'] : '';
	$this->smtp_pass = isset($opts['smtp_pass']) && $opts['smtp_pass'] ? $opts['smtp_pass'] : '';
	$this->smtp_helo = isset($opts['smtp_helo']) && $opts['smtp_helo'] ? $opts['smtp_helo'] : 'HELO';
	$this->wrap_brackets = isset($opts['wrap_brackets']) && $opts['wrap_brackets'] ? true : false;
	$this->extra_opts = isset($opts['extra_opts']) && $opts['extra_opts'] ? $opts['extra_opts'] : '';
	if ($this->mail_method == 'smtp')
	{
		$this->_smtpConnect();
	}
}

public __destruct( ) (在 Mail 中定义)

析构方法

返回值

  • void

源代码

public function __destruct()
{
	if ($this->mail_method == 'smtp')
	{
		$this->_smtpDisconnect();
	}
}

public addAttachment( [ string $data = string(0) "" , string $name = string(0) "" , string $ctype = string(24) "application/octet-stream" ] ) (在 Mail 中定义)

添加附件到当前邮件

参数

  • string $data = string(0) "" - 文件数据
  • string $name = string(0) "" - 文件名
  • string $ctype = string(24) "application/octet-stream" - 文件类型(MIME)

返回值

  • void

源代码

public function addAttachment($data = '', $name = '', $ctype = 'application/octet-stream')
{
	$this->parts[] = array(
		'ctype' => $ctype,
		'data' => $data,
		'encode' => 'base64',
		'name' => $name
	);
}

public addBCC( string $email ) (在 Mail 中定义)

添加密送

参数

  • string $email required - 收件人邮件地址

返回值

  • boolean

源代码

public function addBCC($email)
{
	$this->bcc[] = $this->_cleanEmail($email);
	return true;
}

public clearEmail( ) (在 Mail 中定义)

清除存储的数据,为新邮件做准备。

用于防止反复关闭/重新打开 SMTP 连接。

返回值

  • void

源代码

public function clearEmail()
{
	$this->from = '';
	$this->from_display = '';
	$this->to = '';
	$this->bcc = array();
	$this->subject = '';
	$this->message = '';
	$this->pt_message = '';
	$this->parts = array();
	$this->mail_headers = array();
	$this->multipart = '';
	$this->smtp_msg = '';
	$this->smtp_code = '';
}

public clearError( ) (在 Mail 中定义)

清除存储的错误,为新邮件作准备。

返回值

  • void

源代码

public function clearError()
{
	$this->error_msg = '';
	$this->error_help = '';
	$this->error = false;
}

public static instance( ) (在 Mail 中定义)

单例模式

返回值

  • Mail

源代码

public static function instance($opts = array())
{
	if (!isset(self::$_instance))
	{
		self::$_instance = new Mail($opts);
	}
	return self::$_instance;
}

public send( ) (在 Mail 中定义)

Send the mail (All appropriate params must be set by this point)

返回值

  • boolean - Mail sent successfully

源代码

public function send()
{
	// 创建头部
	$this->_buildHeaders();
	// 验证参数都已设置
	if (!$this->to || !$this->from || !$this->subject)
	{
		$this->_fatalError("From, to, or subject empty");
		return false;
	}
	// 调试
	if ($this->temp_dump == 1)
	{
		$debug = $this->subject . "\n------------\n" . $this->rfc_headers . "\n\n" . $this->message;
		if (!is_dir($this->temp_dump_path))
		{
			@mkdir($this->temp_dump_path);
			@chmod($this->temp_dump_path, 0777);
		}
		if (!is_dir($this->temp_dump_path))
		{
			$this->_fatalError('Debugging enabled, but debug path does not exist and cannot be created');
			return false;
		}
		$pathy = $this->temp_dump_path . '/' . date('M-j-Y') . '-' . time() . str_replace('@', '+', $this->to) . uniqid('_') . '.php';
		$fh = @fopen($pathy, 'w');
		@fputs($fh, $debug, strlen($debug));
		@fclose($fh);
	}
	else
	{
		// PHP mail()
		if ($this->mail_method != 'smtp')
		{
			if (!@mail($this->to, $this->subject, $this->message, $this->rfc_headers, $this->extra_opts))
			{
				if (!@mail($this->to, $this->subject, $this->message, $this->rfc_headers))
				{
					$this->_fatalError("Could not send the email", "Failed at 'mail' command");
				}
			}
		}
		// SMTP
		else
		{
			$this->_smtpSendMail();
		}
	}
	$this->clearEmail();
	return $this->error ? false : true;
}

public setBody( string $body ) (在 Mail 中定义)

设置邮件正文

参数

  • string $body required - 邮件正文

返回值

  • boolean

源代码

public function setBody($body)
{
	$this->message = $body;
	return true;
}

public setFrom( string $email [, string $display = string(0) "" ] ) (在 Mail 中定义)

设置发件人邮件地址

参数

  • string $email required - 发件人邮件地址
  • string $display = string(0) "" - [Optional] 要显示的发件人

返回值

  • boolean

源代码

public function setFrom($email, $display = '')
{
	$this->from = $this->_cleanEmail($email);
	$this->from_display = $display;
	return true;
}

public setHeader( string $key , string $value ) (在 Mail 中定义)

手动设置头部

参数

  • string $key required - 头部键
  • string $value required - 头部值

返回值

  • boolean

源代码

public function setHeader($key, $value)
{
	$this->mail_headers[$key] = $value;
	return true;
}

public setSubject( string $subject ) (在 Mail 中定义)

设置邮件标题

参数

  • string $subject required - 邮件标题

返回值

  • boolean

源代码

public function setSubject($subject)
{
	// 修复编码后的引号等
	$subject = str_replace('"', '"', $subject);
	$subject = str_replace(''', "'", $subject);
	$subject = str_replace(''', "'", $subject);
	$subject = str_replace('!', '!', $subject);
	$subject = str_replace('$', '$', $subject);
	if ($this->mail_method != 'smtp')
	{
		$sheader = $this->_encodeHeaders(array('Subject' => $subject));
		$subject = $sheader['Subject'];
	}
	$this->subject = $subject;
	return true;
}

public setTo( string $email ) (在 Mail 中定义)

设置收件人邮件地址

参数

  • string $email required - 收件人邮件地址

返回值

  • boolean

源代码

public function setTo($email)
{
	$this->to = $this->_cleanEmail($email);
	return true;
}

private _buildHeaders( ) (在 Mail 中定义)

构建邮件头(MIME、字符集、发件人、BCC、收件人、标题等)

返回值

  • void

源代码

private function _buildHeaders()
{
	$extra_headers = array();
	$extra_header_rfc = '';
	// 如果要发送HTML信息,那么我们将它和纯文本添加到一起。
	$this->pt_message = $this->message;
	$this->pt_message = str_replace('<br />', "\n", $this->pt_message);
	$this->pt_message = str_replace('<br>', "\n", $this->pt_message);
	$this->pt_message = strip_tags($this->pt_message);
	$this->pt_message = html_entity_decode($this->pt_message, ENT_QUOTES);
	$this->pt_message = str_replace('&#092;', '\\', $this->pt_message);
	$this->pt_message = str_replace('&#036;', '$', $this->pt_message);
	// 开启邮件头
	$this->mail_headers['MIME-Version'] = '1.0';
	$this->mail_headers['Date'] = date('r');
	$this->mail_headers['Return-Path'] = $this->from;
	$this->mail_headers['X-Priority'] = '3';
	$this->mail_headers['X-MSMail-Priority'] = 'Normal';
	$this->mail_headers['X-Mailer'] = 'BootPHP Mailer';
	if ($this->from_display && !preg_match('/(\w*[\x80-\xFF]+\w*)/', $this->from_display))
	{
		$this->mail_headers['From'] = '"' . $this->from_display . '" <' . $this->from . '>';
	}
	else
	{
		$this->mail_headers['From'] = '<' . $this->from . '>';
	}
	if ($this->mail_method != 'smtp')
	{
		if (count($this->bcc) > 0)
		{
			$this->mail_headers['Bcc'] = implode(',', $this->bcc);
		}
	}
	else
	{
		if ($this->to)
		{
			$this->mail_headers['To'] = $this->to;
		}
		$this->mail_headers['Subject'] = $this->subject;
	}
	// 有附件吗?
	if (count($this->parts) > 0)
	{
		if (!$this->html_email)
		{
			$extra_headers[0]['Content-Type'] = "multipart/mixed;\n\tboundary=\"" . $this->boundry . "\"";
			$extra_headers[0]['notencode'] = "\n\nThis is a MIME encoded message.\n\n--" . $this->boundry . "\n";
			$extra_headers[1]['Content-Type'] = "text/plain;\n\tcharset=\"" . $this->char_set . "\"";
			$extra_headers[1]['notencode'] = "\n\n" . $this->message . "\n\n--" . $this->boundry;
		}
		else
		{
			$extra_headers[0]['Content-Type'] = "multipart/mixed;\n\tboundary=\"" . $this->boundry . "\"";
			$extra_headers[0]['notencode'] = "\n\nThis is a MIME encoded message.\n\n--" . $this->boundry . "\n";
			$extra_headers[1]['Content-Type'] = "text/html;\n\tcharset=\"" . $this->char_set . "\"";
			$extra_headers[1]['notencode'] = "\n\n" . $this->message . "\n\n--" . $this->boundry;
		}
		$extra_headers[2]['notencode'] = $this->_buildMultipart();
		reset($extra_headers);
		foreach ($extra_headers as $subset => $the_header)
		{
			foreach ($the_header as $k => $v)
			{
				if ($k == 'notencode')
				{
					$extra_headers_rfc .= $v;
				}
				else
				{
					$v = $this->_encodeHeaders(array('v' => $v));
					$extra_headers_rfc .= $k . ': ' . $v['v'] . self::header_eol;
				}
			}
		}
		$this->message = '';
	}
	else
	{
		if ($this->html_email)
		{
			$extra_headers[0]['Content-Type'] = "multipart/alternative;\n\tboundary=\"" . $this->boundry . "\"";
			$extra_headers[0]['notencode'] = "\n\nThis is a MIME encoded message.\n\n--" . $this->boundry . "\n";
			$extra_headers[1]['Content-Type'] = "text/plain;\n\tcharset=\"" . $this->char_set . "\"";
			$extra_headers[1]['notencode'] = "\n\n" . $this->pt_message . "\n\n--" . $this->boundry . "\n";
			$extra_headers[2]['Content-Type'] = "text/html;\n\tcharset=\"" . $this->char_set . "\"";
			$extra_headers[2]['notencode'] = "\n\n" . $this->message . "\n\n--" . $this->boundry . "--";
			reset($extra_headers);
			foreach ($extra_headers as $subset => $the_header)
			{
				foreach ($the_header as $k => $v)
				{
					if ($k == 'notencode')
					{
						$extra_headers_rfc .= $v;
					}
					else
					{
						$v = $this->_encodeHeaders(array('v' => $v));
						$extra_headers_rfc .= $k . ': ' . $v['v'] . self::header_eol;
					}
				}
			}
			$this->message = '';
		}
		else
		{
			$this->mail_headers['Content-type'] = 'text/plain; charset="' . $this->char_set . '"';
		}
	}
	$this->_encodeHeaders();
	foreach ($this->mail_headers as $k => $v)
	{
		$this->rfc_headers .= $k . ": " . $v . self::header_eol;
	}
	// 有额外附件吗?
	if ($extra_headers_rfc)
	{
		$this->rfc_headers .= $extra_headers_rfc;
	}
}

private _buildMultipart( ) (在 Mail 中定义)

Build the multipart headers for the email

返回值

  • string - Multipart headers

源代码

private function _buildMultipart()
{
	$multipart = '';
	for ($i = sizeof($this->parts) - 1; $i >= 0; $i--)
	{
		$multipart .= self::header_eol . $this->_encodeAttachment($this->parts[$i]) . "--" . $this->boundry;
	}
	return $multipart . "--\n";
}

private _cleanEmail( string $email ) (在 Mail 中定义)

清理邮件地址

参数

  • string $email required - 邮件地址

返回值

  • string - 清理后的邮件地址

源代码

private function _cleanEmail($email)
{
	$email = str_replace(' ', '', $email);
	$email = str_replace("\t", '', $email);
	$email = str_replace("\r", '', $email);
	$email = str_replace("\n", '', $email);
	$email = str_replace(',,', ',', $email);
	$email = preg_replace("#\#\[\]'\"\(\):;/\$!?\^&\*\{\}#", '', $email);
	return $email;
}

private _encodeAttachment( [ array $part = array(0) ] ) (在 Mail 中定义)

加密附件

参数

  • array $part = array(0) - 原始数据 [ctype,encode,name,data]

返回值

  • string - 处理的数据

源代码

private function _encodeAttachment($part = array())
{
	$msg = chunk_split(base64_encode($part['data']));
	$headers = array();
	$header_str = '';
	$headers['Content-Type'] = $part['ctype'] . ($part['name'] ? "; name =\"" . $part['name'] . "\"" : '');
	$headers['Content-Transfer-Encoding'] = $part['encode'];
	$headers['Content-Disposition'] = "attachment; filename=\"" . $part['name'] . "\"";
	$headers = $this->_encodeHeaders($headers);
	foreach ($headers as $k => $v)
	{
		$header_str .= $k . ': ' . $v . self::header_eol;
	}
	$header_str .= "\n\n" . $msg . "\n";
	return $header_str;
}

private _encodeHeaders( [ array $headers = array(0) ] ) (在 Mail 中定义)

编码头部 - RFC2047

参数

  • array $headers = array(0) - 头部数组

Tags

  • See - http://www.faqs.org/rfcs/rfc822.html, http://www.faqs.org/rfcs/rfc2045, http://www.faqs.org/rfcs/rfc2047, http://us2.php.net/manual/en/function.mail.php#27997

返回值

  • array - Headers encoded per RFCs

源代码

private function _encodeHeaders($headers = array())
{
	$enc_headers = count($headers) ? $headers : $this->mail_headers;
	foreach ($enc_headers as $header => $value)
	{
		$orig_value = $value;
		// 邮件传送代理似乎不喜欢“From”编码,所以剥离后继续
		if ($header == 'From' || $header == 'Content-Type' || $header == 'Content-Disposition')
		{
			$this->mail_headers[$header] = $orig_value;
			$enc_headers[$header] = $orig_value;
			continue;
		}
		// 对于 php mail,标题不保留于头部
		if ($this->mail_method != 'smtp' && $header == 'Subject')
		{
			unset($this->mail_headers[$header]);
		}
		// 不要打扰编码,除非我们有需要进行编码的字符
		if (!preg_match('/(\w*[\x80-\xFF]+\w*)/', $value))
		{
			if ($header != 'Subject')
			{
				$this->mail_headers[$header] = $orig_value;
			}
			$enc_headers[$header] = $orig_value;
			continue;
		}
		// Base64 编码
		$start = '=?' . $this->char_set . '?B?';
		$end = '?=';
		$spacer = $end . self::header_eol . ' ' . $start;
		$length = 75 - strlen($start) - strlen($end);
		$length = $length - ($length % 4);
		$value = base64_encode($value);
		$value = chunk_split($value, $length, $spacer);
		$spacer = preg_quote($spacer);
		$value = preg_replace('/' . $spacer . "$/", '', $value);
		$value = $start . $value . $end;
		if (!count($headers) && $header != 'Subject')
		{
			$this->mail_headers[$header] = $value;
		}
		else
		{
			$enc_headers[$header] = $value;
		}
	}
	return $enc_headers;
}

private _fatalError( string $msg [, string $help = string(0) "" ] ) (在 Mail 中定义)

致命错误处理器

参数

  • string $msg required - 错误信息
  • string $help = string(0) "" - 错误帮助或描述

返回值

  • boolean

源代码

private function _fatalError($msg, $help = '')
{
	$this->error = true;
	$this->error_msg = $msg;
	$this->error_help = $help;
	return false;
}

private _smtpConnect( ) (在 Mail 中定义)

SMTP 连接

返回值

  • boolean - 连接成功

源代码

private function _smtpConnect()
{
	$this->smtp_fp = @fsockopen($this->smtp_host, intval($this->smtp_port), $errno, $errstr, 30);
	if (!$this->smtp_fp)
	{
		$this->_smtpError("Could not open a socket to the SMTP server ({$errno}:{$errstr}");
		return false;
	}
	$this->_smtpGetLine();
	$this->smtp_code = substr($this->smtp_msg, 0, 3);
	if ($this->smtp_code == 220)
	{
		// HELO
		$this->_smtpSendCmd("{$this->smtp_helo} " . $this->smtp_host);
		if ($this->smtp_code != 250)
		{
			$this->_smtpError("HELO (using: {$this->smtp_helo})");
			return false;
		}
		if ($this->smtp_user && $this->smtp_pass)
		{
			$this->_smtpSendCmd('AUTH LOGIN');
			if ($this->smtp_code == 334)
			{
				$this->_smtpSendCmd(base64_encode($this->smtp_user));
				if ($this->smtp_code != 334)
				{
					$this->_smtpError('Username not accepted from the server');
					return false;
				}
				$this->_smtpSendCmd(base64_encode($this->smtp_pass));
				if ($this->smtp_code != 235)
				{
					$this->_smtpError('Password not accepted from the server');
					return;
				}
			}
			else
			{
				$this->_smtpError('This server does not support authorisation');
				return;
			}
		}
	}
	else
	{
		$this->_smtpError('Could not connect to the SMTP server');
		return false;
	}
	return true;
}

private _smtpCrlfEncode( string $data ) (在 Mail 中定义)

编码数据以使其安全传输

参数

  • string $data required - 原始数据

返回值

  • string - CRLF 编码的数据

源代码

private function _smtpCrlfEncode($data)
{
	$data.= "\n";
	$data = str_replace("\n", "\r\n", str_replace("\r", '', $data));
	$data = str_replace("\n.\r\n", "\n. \r\n", $data);
	return $data;
}

private _smtpDisconnect( ) (在 Mail 中定义)

SMTP 断开

返回值

  • boolean - 断开成功了吗?

源代码

private function _smtpDisconnect()
{
	$this->_smtpSendCmd('quit');
	if ($this->smtp_code != 221)
	{
		$this->_smtpError("Unable to exit SMTP server with 'quit' command");
		return false;
	}
	return @fclose($this->smtp_fp);
}

private _smtpError( [ string $err = string(0) "" ] ) (在 Mail 中定义)

SMTP 错误处理

参数

  • string $err = string(0) "" - SMTP 错误

返回值

  • boolean

源代码

private function _smtpError($err = '')
{
	$this->smtp_msg = $err;
	$this->_fatalError($err);
	return false;
}

private _smtpGetLine( ) (在 Mail 中定义)

SMTP: 得到下一行

返回值

  • void

源代码

private function _smtpGetLine()
{
	$this->smtp_msg = '';
	while ($line = @fgets($this->smtp_fp, 515))
	{
		$this->smtp_msg .= $line;
		if (substr($line, 3, 1) == ' ')
			break;
	}
}

private _smtpSendCmd( string $cmd ) (在 Mail 中定义)

SMTP 发送命令

参数

  • string $cmd required - SMTP 命令

返回值

  • boolean - 命令成功了吗?

源代码

private function _smtpSendCmd($cmd)
{
	$this->smtp_msg = '';
	$this->smtp_code = '';
	@fputs($this->smtp_fp, $cmd . "\r\n");
	$this->_smtpGetLine();
	$this->smtp_code = substr($this->smtp_msg, 0, 3);
	return $this->smtp_code == '' ? false : true;
}

private _smtpSendMail( ) (在 Mail 中定义)

发送 SMTP 邮件

返回值

  • void

源代码

private function _smtpSendMail()
{
	$data = $this->_smtpCrlfEncode($this->rfc_headers . "\n\n" . $this->message);
	//-----------------------------------------
	// Wrap in brackets
	//-----------------------------------------
	if ($this->wrap_brackets)
	{
		if (!preg_match("/^</", $this->from))
		{
			$this->from = '<' . $this->from . '>';
		}
	}
	// 发件人
	$this->_smtpSendCmd('MAIL FROM:' . $this->from);
	if ($this->smtp_code != 250)
	{
		$this->_smtpError('Mail from command failed');
		return false;
	}
	$toArr = array($this->to);
	if (count($this->bcc) > 0)
	{
		foreach ($this->bcc as $bcc)
		{
			$toArr[] = $bcc;
		}
	}
	// 收件人
	foreach ($toArr as $to_email)
	{
		if ($this->wrap_brackets)
		{
			$this->_smtpSendCmd('RCPT TO:<' . $to_email . '>');
		}
		else
		{
			$this->_smtpSendCmd('RCPT TO:' . $to_email);
		}
		if ($this->smtp_code != 250)
		{
			$this->_smtpError("Incorrect email address: $to_email");
		}
	}
	// 发送邮件
	$this->_smtpSendCmd('DATA');
	if ($this->smtp_code == 354)
	{
		fputs($this->smtp_fp, $data . "\r\n");
	}
	else
	{
		$this->_smtpError('Error writing email body to SMTP server');
		return false;
	}
	// 去吧,滚!
	$this->_smtpSendCmd('.');
	if ($this->smtp_code != 250)
	{
		$this->_smtpError('Email was not sent successfully');
		return false;
	}
}