dimarick/net_smtp

SMTP协议的实现

v2.0.0beta4 2020-04-25 18:44 UTC

README

用户文档

目录

1   依赖关系

1.1   PEAR_Error

Net_SMTP包使用PEAR_Error类来处理所有错误。

1.2   Net_Socket

使用Net_Socket包作为所有网络通信的基础。可以通过$socket_options构造参数指定连接选项。

$socket_options = array('ssl' => array('verify_peer_name' => false));
$smtp = new Net_SMTP($host, null, null, false, 0, $socket_options);

注意:PHP 5.6引入了OpenSSL更改。默认情况下现在启用了对等证书验证。虽然不推荐,但可以使用$socket_options来禁用对等验证(如上所示)。

1.3   Auth_SASL

Auth_SASL包是一个可选的依赖项。如果可用,Net_SMTP包将能够支持DIGEST-MD5CRAM-MD5 SMTP认证方法。否则,仅提供LOGINPLAIN方法。

2   错误处理

如果发生错误,Net_SMTP类的所有公共方法都返回一个PEAR_Error对象。检查PEAR_Error对象的标准方法是通过使用PEAR::isError()

if (PEAR::isError($error = $smtp->connect())) {
    die($error->getMessage());
}

3   SMTP认证

Net_SMTP包支持SMTP认证标准(如RFC-2554定义)。Net_SMTP包按优先级顺序支持以下认证方法:

3.1   >DIGEST-MD5

DIGEST-MD5认证方法使用RSA数据安全公司的MD5消息摘要算法。它被认为是SMTP认证中最安全的方法。

注意:DIGEST-MD5认证方法仅在对AUTH_SASL包可用时受支持。

3.2   >CRAM-MD5

在安全性方面,CRAM-MD5认证方法已被DIGEST-MD5方法取代。它在此提供是为了与可能不支持较新DIGEST-MD5算法的旧SMTP服务器兼容。

注意:CRAM-MD5认证方法仅在对AUTH_SASL包可用时受支持。

3.3   LOGIN

LOGIN 身份验证方法使用 Base64 编码方案对用户的密码进行加密。由于解密 Base64 编码的字符串很简单,因此 LOGIN 不被认为是一种安全的身份验证方法,应该避免使用。

3.4   PLAIN

PLAIN 身份验证方法以明文形式发送用户的密码。这种身份验证方法不安全,应该避免使用。

4   安全连接

如果已在 PHP 中启用了 安全套接字传输,则可以建立到远程 SMTP 服务器的安全连接

$smtp = new Net_SMTP('ssl://mail.example.com', 465);

以下示例使用 ssl:// 传输连接到 mail.example.com 的 465 端口(一个常见的 SMTPS 端口)。

5   发送数据

消息数据使用 data() 方法发送。数据可以提供为一个字符串,或者作为一个打开的文件资源。

如果提供字符串,它将通过 数据引用 系统传递,并作为单个块发送到套接字连接。所有这些操作都是基于内存的,因此发送大消息可能会导致内存使用量很高。

如果提供打开的文件资源,则 data() 方法将逐行从文件中读取消息数据。每个块将引用并单独发送到套接字连接,从而减少整个数据发送操作的内存开销。

可以通过将可选的第二个参数作为 data() 传递来单独指定标题数据,而不是消息体数据。这对于使用打开的文件资源提供消息数据时尤其有用,因为它允许在运行时动态构建标题字段(如 Subject:)。

$smtp->data($fp, "Subject: My Subject");

6   数据引用

默认情况下,所有输出字符串数据都根据 SMTP 标准进行引用。这意味着所有本机 Unix (\n) 和 Mac (\r) 换行符都转换为 Internet 标准的 CRLF (\r\n) 换行符。此外,由于 SMTP 协议使用单个前导点 (.) 来表示消息数据的结束,因此原始数据字符串中的单个前导点会被“加倍”(例如,“..”)。

当涉及大量数据时,这些字符串转换可能很昂贵。例如,Net_SMTP 包不了解 MIME 部分(它只是将 MIME 消息视为一个大的字符字符串),因此它无法在查找可能需要引用的字符时跳过非文本附件。

因此,可以通过扩展 Net_SMTP 类来实现自定义引用例程。只需创建一个基于 Net_SMTP 类的新类,并重新实现 quotedata() 方法

require 'Net_SMTP.php';

class Net_SMTP_custom extends Net_SMTP
{
    function quotedata($data)
    {
        /* Perform custom data quoting */
    }
}

注意,$data 参数将以引用的方式传递给 quotedata() 函数 by reference。这意味着可以直接对 $data 进行操作。这也消除了在 quotedata() 方法之间复制大型 $data 字符串的开销。

7   服务器响应

Net_SMTP 包保留服务器的最后响应以供进一步检查。getResponse() 方法返回一个包含服务器响应代码(作为整数)和响应参数(作为字符串)的 2 元组(两个元素的数组)。

成功连接后,可以通过 getGreeting() 方法获取服务器的问候字符串。

8   调试

Net_SMTP 包包含内置的调试输出例程(默认情况下禁用)。调试输出必须通过 setDebug() 方法显式启用

$smtp->setDebug(true);

默认情况下,调试消息将发送到标准输出流。如果需要更多的输出控制,您可以可选地安装自己的调试处理程序。

function debugHandler($smtp, $message)
{
    echo "[$smtp->host] $message\n";
}

$smtp->setDebug(true, "debugHandler");

9   示例

9.1   基本用法

以下脚本演示了如何使用 Net_SMTP 包发送简单的电子邮件消息

require 'Net/SMTP.php';

$host = 'mail.example.com';
$from = 'user@example.com';
$rcpt = array('recipient1@example.com', 'recipient2@example.com');
$subj = "Subject: Test Message\n";
$body = "Body Line 1\nBody Line 2";

/* Create a new Net_SMTP object. */
if (! ($smtp = new Net_SMTP($host))) {
    die("Unable to instantiate Net_SMTP object\n");
}

/* Connect to the SMTP server. */
if (PEAR::isError($e = $smtp->connect())) {
    die($e->getMessage() . "\n");
}

/* Send the 'MAIL FROM:' SMTP command. */
if (PEAR::isError($smtp->mailFrom($from))) {
    die("Unable to set sender to <$from>\n");
}

/* Address the message to each of the recipients. */
foreach ($rcpt as $to) {
    if (PEAR::isError($res = $smtp->rcptTo($to))) {
        die("Unable to add recipient <$to>: " . $res->getMessage() . "\n");
    }
}

/* Set the body of the message. */
if (PEAR::isError($smtp->data($subj . "\r\n" . $body))) {
    die("Unable to send data\n");
}

/* Disconnect from the SMTP server. */
$smtp->disconnect();