Search by

EasySwoole mailer component

Package info

github.com/easy-swoole/smtp

pkg:composer/easyswoole/smtp

Statistics

Installs: 16 019

Dependents: 1

Suggesters: 0

Stars: 10

Open Issues: 5

3.0.1 2026-10-15 06:22 UTC

This package is auto-updated.

Last update: 2026-10-15 06:23:23 UTC


README

基于 Swoole 协程客户端的轻量 SMTP 邮件发送组件。

支持:

  • 纯文本和 HTML 邮件
  • To、Cc、Bcc 和 Reply-To
  • 单个或多个附件、自定义附件名
  • UTF-8 主题、正文与附件名
  • SSL/TLS 直连
  • 返回状态码或抛出异常两种错误处理模式

环境要求

  • PHP 8.1 或更高版本
  • Swoole 5.1 或更高版本
  • mbstring 扩展
  • Composer

检查运行环境:

php -v
php -m | grep -E 'swoole|mbstring'

安装

composer require easyswoole/smtp

快速开始

Mailer 内部使用 Swoole\Coroutine\Client,因此 send() 必须在 Swoole 协程环境中调用。

<?php

require __DIR__ . '/vendor/autoload.php';

use EasySwoole\Smtp\Mailer;
use EasySwoole\Smtp\Request\Text;
use Swoole\Coroutine;

$mailer = new Mailer(true);
$mailer->setHost('smtp.example.com');
$mailer->setPort(465);
$mailer->setSsl(true);
$mailer->setUsername('account@example.com');
$mailer->setPassword('smtp-password');
$mailer->setFrom('account@example.com', '系统通知');
$mailer->addAddress('user@example.com', '收件人');

$message = new Text();
$message->setSubject('测试邮件');
$message->setBody('这是一封测试邮件。');

Coroutine\run(function () use ($mailer, $message): void {
    $mailer->send($message);
});

在 EasySwoole 等已经运行于协程环境的框架中,直接调用 $mailer->send($message) 即可,不要再次嵌套 Coroutine\run()。

完整示例

下面的例子展示 HTML、多个收件人、抄送、密送、回复地址和多个附件:

<?php

require __DIR__ . '/vendor/autoload.php';

use EasySwoole\Smtp\Mailer;
use EasySwoole\Smtp\Request\Html;
use Swoole\Coroutine;

$mailer = new Mailer(true);
$mailer->setHost('smtp.example.com');
$mailer->setPort(465);
$mailer->setSsl(true);
$mailer->setUsername('account@example.com');
$mailer->setPassword('smtp-password');
$mailer->setTimeout(10);

$mailer->setFrom('sender@example.com', '订单系统');
$mailer->addAddress('customer@example.com', '客户');
$mailer->addAddress('other@example.com');
$mailer->addCc('sales@example.com', '销售团队');
$mailer->addBcc('audit@example.com');
$mailer->setReplyTo('support@example.com', '客服');

$message = new Html();
$message->setSubject('订单已创建');
$message->setBody('<h1>订单创建成功</h1><p>订单详情请查看附件。</p>');
$message->addAttachment('/absolute/path/order.pdf');
$message->addAttachment('/absolute/path/items.csv', '订单明细.csv');

Coroutine\run(function () use ($mailer, $message): void {
    $response = $mailer->send($message);
    echo $response->getMsg(); // ok.
});

邮件内容

纯文本邮件

use EasySwoole\Smtp\Request\Text;

$message = new Text();
$message->setSubject('纯文本主题');
$message->setBody("第一行\n第二行");

HTML 邮件

use EasySwoole\Smtp\Request\Html;

$message = new Html();
$message->setSubject('HTML 主题');
$message->setBody('<h1>Hello</h1><p>邮件正文</p>');

默认字符集为 UTF-8。需要其他字符集时,可以调用:

$message->setCharset('ISO-8859-1');

附件

// 使用源文件名
$message->addAttachment('/absolute/path/report.pdf');

// 指定邮件中显示的文件名
$message->addAttachment('/absolute/path/data.csv', '统计数据.csv');

// 可以继续添加更多附件
$message->addAttachment('/absolute/path/image.png', '截图.png');

附件说明:

  • 必须传入本机可读文件的路径,建议使用绝对路径。
  • 第二个参数只影响邮件中显示的文件名,不会修改源文件。
  • 二进制附件自动使用 Base64 编码。
  • MIME 类型根据源文件扩展名识别,无法识别时使用 application/octet-stream。
  • 支持空文件。
  • 文件不存在、不是普通文件或不可读时,会抛出 EasySwoole\Smtp\Exception\Exception。

收件人与邮件头

$mailer->setFrom('sender@example.com', '发件人');
$mailer->addAddress('to@example.com', '主收件人');
$mailer->addCc('cc@example.com', '抄送人');
$mailer->addBcc('bcc@example.com', '密送人');
$mailer->setReplyTo('reply@example.com', '回复联系人');
  • addAddress()、addCc() 和 addBcc() 都可以调用多次。
  • 未调用 setFrom() 时,SMTP 登录用户名会作为发件地址。
  • Bcc 地址只参与 SMTP 投递,不会写入邮件头,因此其他收件人不可见。
  • 未设置 To、但设置了 Cc 或 Bcc 时,To 邮件头会使用 undisclosed-recipients:;。

Mailer 配置

方法 默认值 说明
new Mailer(bool $enableException = false) false 是否在 SMTP 阶段失败时抛出异常
setHost(string $host) 空 SMTP 服务器地址,发送前必须设置
setPort(int $port) 465 SMTP 服务器端口
setSsl(bool $ssl) true 是否使用 SSL/TLS 直连
setUsername(string $username) 空 SMTP 登录用户名
setPassword(string $password) 空 SMTP 密码或服务商授权码
setFrom(string $address, string $name = '') 登录用户名 设置 envelope sender 和 From 邮件头
addAddress(string $address, string $name = '') — 添加 To 收件人
addCc(string $address, string $name = '') — 添加 Cc 收件人
addBcc(string $address, string $name = '') — 添加 Bcc 收件人
setReplyTo(string $address, string $name = '') 未设置 设置 Reply-To 邮件头
setTimeout(int $seconds) 5 连接及响应等待时间
setMaxPackage(int $bytes) 2097152 Swoole 客户端接收包上限,不是附件大小限制
setEnableException(bool $enabled) false 动态切换异常模式

SMTP 兼容性

当前实现使用:

  • EHLO
  • AUTH LOGIN
  • MAIL FROM / RCPT TO / DATA
  • SSL/TLS 直连

常见的 465 端口通常使用 setSsl(true)。若服务商提供普通明文端口,可使用 setSsl(false)。

当前版本不实现 STARTTLS 升级,也不支持 OAuth 或其他 SASL 认证机制。使用 587 等端口前,请确认服务商是否要求 STARTTLS;如果强制要求,则当前版本不能直接连接。

错误处理

返回响应对象

默认模式不会因 SMTP 状态错误抛出异常,而是返回 EasySwoole\Smtp\Protocol\Response:

use EasySwoole\Smtp\Protocol\Response;

$mailer = new Mailer();

$response = $mailer->send($message);
if ($response->getStatus() !== Response::STATUS_OK) {
    printf("发送失败:[%d] %s\n", $response->getStatus(), $response->getMsg());
}

异常模式

use EasySwoole\Smtp\Exception\Exception;

$mailer = new Mailer(true);

try {
    $mailer->send($message);
} catch (Exception $exception) {
    echo '发送失败:' . $exception->getMessage();
}

异常模式只改变 SMTP 阶段错误的返回方式。附件文件不可读等消息构建错误始终会抛出异常。

状态码

状态码 常量 含义
0 STATUS_OK 发送成功
101 STATUS_CONNECT_TIMEOUT 连接失败或超时
102 STATUS_NOT_SMTP_PROTOCOL 未收到有效的 SMTP 欢迎响应
103 STATUS_RECEIVE_TIMEOUT 接收服务器响应超时
201 STATUS_IDENTIFY_SENDER_ERROR EHLO 阶段失败
202 STATUS_AUTH_MODE_ERROR 服务端不支持当前认证模式
203 STATUS_USERNAME_ERROR 用户名认证失败
204 STATUS_PASSWORD_ERROR 密码认证失败
205 STATUS_FROM_MAIL_ERROR 发件人地址被拒绝
206 STATUS_RCPT_MAIL_ERROR 收件人地址被拒绝
207 STATUS_DATA_START_ERROR DATA 命令被拒绝
208 STATUS_DATA_END_ERROR 邮件内容提交失败
209 STATUS_QUIT_ERROR SMTP 会话退出失败

常见问题

API must be called in the coroutine

说明 send() 在非协程环境中执行。CLI 脚本可用 Coroutine\run() 包裹;EasySwoole 请求处理器等已有协程环境中应直接调用。

连接 587 端口失败

许多服务商的 587 端口要求 STARTTLS,而当前组件仅支持 SSL/TLS 直连或普通连接。请使用服务商提供的 SSL 直连端口,通常是 465。

登录密码正确但认证失败

部分邮箱要求使用单独生成的 SMTP 授权码,而不是网页登录密码。请同时确认服务商已启用 SMTP 服务且支持 AUTH LOGIN。

附件发送失败

确认文件使用绝对路径、进程对文件有读取权限,并检查运行用户与 CLI 用户是否一致。

开发与测试

安装开发依赖并运行测试:

composer install
composer test

也可以直接运行:

vendor/bin/phpunit
vendor/bin/phpunit tests/SmtpIntegrationTest.php

测试套件基于 PHPUnit 10,包括:

  • 内容编码与 MIME 类型单元测试
  • 纯文本、HTML、附件和空附件测试
  • SMTP 命令、邮件头、响应与异常测试
  • 本地 Swoole 协程 Mock SMTP 集成测试

Mock SMTP 测试会验证 EHLO、AUTH LOGIN、发件人、To/Cc/Bcc、DATA、附件编码、dot-stuffing 和 QUIT 的完整流程。它只监听本机随机端口,不连接真实 SMTP 服务器,也不会向外发送邮件。

License

Apache-2.0