官方技术指南 Zero-Build PHP 8.2+ 架构 针对 Shared Hosting 深度优化

文档 与系统百科

MarbleSend 全面技术指南、UI 元素目录与 shared-hosting 优化手册。

Filter:
核心

系统架构与主机运行基石

设计理念:自托管、单租户、zero-build、shared-hosting 友好

MarbleSend 从零开始构建,旨在彻底解决邮件营销软件的痛点:不再需要昂贵的独立 VPS 实例、Redis 服务器、Node 构建流水线或复杂的 Docker 编排。MarbleSend 可在标准 shared-hosting(cPanel、Hostinger、DirectAdmin、Plesk、LiteSpeed)上运行,采用纯 PHP 8.2+,无需任何服务端编译。

100% Prepared PDO

零 SQL 注入风险

每个数据库查询均使用严格的 prepared statements,无 ORM 性能损耗。

AES-256-GCM

静态存储加密(At-Rest)

SMTP 凭据、AI API 密钥及 webhook secret 均在 Crypto.php 中加密。

原子队列

绝无重复发送

Worker 通过严格限制截止时间的 MySQL 状态更新,原子化认领队列批次。

Zero-Build UI

即时部署

预编译 Tailwind CSS 与 vendored Alpine.js。上传 zip,运行安装程序即可。

0.1 Zero-Build 托管与运行环境设计哲学

大多数现代 Web 应用都需要 Node.js 构建流水线、Redis 常驻服务、Docker 容器编排或 VPS root 权限。MarbleSend 完全摒弃了这一复杂性。专为高性价比的虚拟主机(cPanel、Hostinger、Plesk、LiteSpeed)量身定制,仅凭纯 PHP 8.2+ 即可稳定运行,服务器端零编译。

服务器端零编译

生产服务器无需安装 npm、Webpack、Vite 或 Composer。Tailwind CSS 已预编译为静态资源,Alpine.js 本地打包分发,PHPMailer 6.9.x 直接存放在 vendor-lite 目录。

轻量级内存占用

即便在处理大批量邮件队列时,峰值内存占用也稳定在 32MB 以下。在虚拟主机严格的内存配额(php.ini 64MB-128MB 分配)下依然丝滑运行。

无高危禁用函数

严格避开共享虚拟主机常用的禁用函数(exec、shell_exec、system、passthru、eval、proc_close)。所有外部请求均使用原生超时控制的 cURL。

0.2 安全边界与目录隔离架构

MarbleSend 采用严密的双层目录结构,将公开 Web 资源与敏感应用核心代码及 storage 物理隔离,彻底消除目录遍历和 files 泄露风险。

完全隔离的 Document Root (public/)

仅 public/ 目录对 Web 服务器公开。将域名 DocumentRoot 指向 /public 即可。即使 Apache/Nginx 启用了目录索引,也无法访问核心源码 files。

受保护的应用内核 (app/)

控制器、服务类、库、视图与配置均位于 document root 外的 app/ 目录中。app/config/config.php 中的数据库密码与加密密钥无法通过直接 HTTP 请求获取。

安全的 storage 与迁移文件

storage/ 目录(包含 worker 日志)与 migrations/ 目录(包含原始 SQL 架构 files)完全置于 public/ 之外,防止系统日志或表结构被恶意下载。

0.3 Zero-ORM 数据库设计与 PDO 预处理语句

像 Eloquent 或 Doctrine 这样的 ORM 框架会带来巨大的内存开销、复杂的对象映射转换和难以预测的 N+1 查询。MarbleSend 直接采用 PHP 原生 PDO 与 100% 预处理语句。

IMMUNITY

100% 预处理语句 Prepared Statements

每一个数据库查询均显式绑定参数(PDO::PARAM_STR、PDO::PARAM_INT)。SQL 语句结构与用户输入数据在底层完全分离,数学级别杜绝 SQL 注入攻击。

PERFORMANCE

性能可预测的高效原生查询

直接执行 SQL 免除了 ORM 对象实例化的巨大开销,列表查询与批量队列更新速度提升高达 5 倍,且在共享数据库服务器上 CPU 消耗极低。

IDEMPOTENCY

幂等数据迁移引擎

数据库版本由编号 SQL files(0001_initial.sql 至 0019_add_feedback_attachment.sql)严格追踪,迁移程序自带 IF NOT EXISTS 防重执行保护,并记录在 cm_migrations 表中。

SINGLE-TENANT

单租户 Single-Tenant 数据隔离

纯粹的单租户独立软件设计,表结构不设 tenant_id 冗余字段。B-Tree 索引紧凑高效,避免顺序全表扫描,从根本上杜绝租户间数据串扰泄露。

0.4 静态存储加密与高标准密码学规范

敏感机密绝不以明文存储。MarbleSend 通过 App\Lib\Crypto 采用行业标准的带认证对称加密算法保护所有敏感凭据。

AES-256-GCM

AES-256-GCM 认证加密

采用伽罗瓦/计数器模式高级加密标准(AES-256-GCM),不仅保证机密性,还提供密码学级别的完整性校验标签,任何数据篡改均会被即时拦截。

RANDOM_BYTES()

独一无二的 96 位随机 IV

每次加密均调用 random_bytes() 生成高强度 12 字节(96 位)随机初始化向量(IV),确保相同明文也会生成完全随机且不可预测的 ciphertexts。

SECRETS CATALOG

加密机密凭证清单

自动全面加密保护 SMTP 中继密码、BYOK AI API 密钥(OpenAI、Claude、Gemini、DeepSeek、Kimi、OpenRouter)、Webhook 签名机密以及 Envato Purchase Code。

MASTER KEY ISOLATION

Master Key 根密钥隔离

32 字节的 ENCRYPTION_KEY 在系统安装时随机生成,并仅保存在 app/config/config.php(权限 0600)中。数据库内绝不保存主加密密钥。

0.5 Dual-Worker 双模式后台与并发安全机制

MarbleSend 将所有耗时及定时调度任务交由统一的后台 worker 异步处理,确保管理员 dashboard 无论何时都能保持秒开与极致响应。

UNIFIED RUNNER

单一主控后台运行程序

worker.php 统一调度邮件队列批量发送、循环周期任务运算、RSS 自动订阅拉取、自动化欢迎序列触发以及未打开邮件的智能再发送。

CLI & WEB-CRON

CLI Cron 与 Web-Cron 双向兼容

可通过系统原生 crontab(* * * * * php /path/to/worker.php)或安全的外部 HTTP 请求访问 /cron.php?key=YOUR_KEY。两条通道运行完全相同的底层核心业务逻辑。

ATOMIC CLAIM

原子队列抢占机制(杜绝重复发送)

Worker 实例通过原子 SQL 状态更新抢占批次(UPDATE cm_email_queue SET status = 'processing' WHERE status = 'pending' LIMIT N),即使多进程并发也绝不会发生重复发信。

HEARTBEAT RECOVERY

运行心跳监测与停滞任务自动恢复

在 cm_settings 中实时更新运行心跳。若 worker 进程意外终止(如主机执行超时),后续执行程序会自动识别超时的停滞任务并重置重新派发。

0.6 服务器配置要求与虚拟主机兼容性矩阵

MarbleSend 经过全面验证,完美兼容所有满足 PHP 8.2+ 基准要求的标准虚拟主机、服务器控制面板以及独立服务器环境。

组件项目 最低要求 推荐配置 运行维护说明
PHP 运行环境 PHP 8.2.0+ PHP 8.2 或 8.3 整个应用核心 files 均开启 strict_types=1 严格类型声明。
数据库引擎 MySQL 8.0+ / MariaDB 10.6+ MariaDB 10.11+ 或 MySQL 8.0+ 必须使用 InnoDB 引擎。采用完整 UTF8MB4 字符集。
必需 PHP 扩展 pdo_mysql, openssl, mbstring, json, curl, simplexml, sodium 启用所有标准核心扩展 99% 的虚拟主机均默认开启。可选:intl 扩展以支持多语言数字格式。
Web 服务器 Apache, Nginx, LiteSpeed, Caddy Apache + mod_rewrite 或 LiteSpeed 根目录及 public/ 目录下均已内嵌预配置好的 .htaccess files。
内存限制配额 32MB memory_limit 64MB - 128MB 队列分块发信采用保守批次策略,避免超出主机内存上限。
Cron 任务调度器 CLI crontab 或 Web-Cron HTTP 探测 CLI cron 每 1 分钟执行一次 针对无法使用 SSH/CLI 的主机提供 Web-Cron 备用端点(/cron.php?key=...)。

已通过实测的控制面板

在 cPanel、Hostinger hPanel、Plesk、DirectAdmin、CyberPanel、AApanel、CloudPanel 以及标准 Ubuntu/Debian LAMP/LEMP 架构上均完成严格测试与验证。

模块 01

仪表盘概览 (/dashboard)

针对受众健康度、投递 KPI、worker 心跳和计划任务自动化聚合的总控台。

仪表盘组件结构与技术支持检查器

悬停或点击下方任何元素以查看后端详情
KPI 卡片 1

总发送量

日志汇总与月度计数器
KPI 卡片 2

打开量 / 打开率

1x1 跟踪像素与 Apple MPP 说明
KPI 卡片 3

点击量 / CTR

点击重定向注入器
KPI 04

退订受众

退订率与 RFC 规范合规性
运维卡片 4

Worker 心跳

Cron 状态与 1 分钟执行间隔
可视化图表

发信量增长图表

7天、30天、90天、本年度规模
动态信息流

近期广播列表

状态生命周期与审计追踪
安全提示栏

送达率健康度

SMTP 配置就绪情况

数据库影响:

技术支持团队专业提示:

1.1 邮件表现 KPI 卡片

元素 计算公式与来源 视觉含义 支持减负设计原理
总发送量卡片 COUNT(cm_email_logs) + SUM(cm_campaigns.sent_count) 显示历史累计发送的所有广播和计划邮件。副标题显示本公历月份的发送量。 防止因清理较旧日志记录而产生困惑;历史 Campaign 计数器确保历史累计总数永不减少。
总打开量 / 打开率 COUNT(DISTINCT contact_id WHERE opened_at IS NOT NULL) / Total Sent * 100 通过注入到 HTML 邮件页脚的透明 1x1 跟踪像素衡量互动情况。 Apple MPP 免责声明:iOS 邮件隐私保护通过 Apple 代理预取图片,这可能会虚高打开率。CTR 是真实的商业衡量指标。
总点击量 / CTR COUNT(DISTINCT contact_id WHERE clicked_at IS NOT NULL) / Total Sent * 100 衡量独立订阅者链接点击。通过 /track/click.php 重写。 退订链接和确认链接已从 Campaign CTR 中排除,以保持统计数据的严谨性。
退订卡片 COUNT(status = 'unsubscribed') / Total Contacts * 100 收件人列表通过强制性的一键退订机制退订的比例。 健康阈值应 < 0.5%。退订率 > 1% 则表明受众疲劳、使用了购买的名单或相关性低下。

总发送量与月度发信吞吐

全面统计通过单次广播、循环计划、RSS 订阅和自动回复器成功发出的历史邮件总数。副标题突出显示当前日历月的投递量。由于系统聚合了历史 Campaigns 统计与活跃邮件日志,即便后期维护清理数据库日志,总计数也不会出现异常下降。

独立打开数与 Apple MPP 机制解析

通过插入在 HTML 邮件页脚的透明 1x1 追踪像素统计。针对同一联系人和 Campaign 仅记录首次互动。重要说明:Apple 邮件隐私保护(MPP)会通过代理预先加载图片,可能导致虚高;因此点击率(CTR)才是评估真实转化意向的核心指标。

独立点击数与 URL 重写引擎

邮件正文中的每个标准超链接都会被重写为 /track/click.php 路径,在重定向至目标页面前记录联系人 ID、Campaign ID、目标 URL 和时间戳。为保护用户隐私并遵守法规,退订链接(/unsubscribe.php)与确认链接(/confirm.php)严格免于重写。

退订联系人与发信域声誉防护

记录通过邮件正文退订链接或 RFC 8058 单击标头退订的用户数量。健康的列表退订率应维持在 0.5% 以下。一旦超过 1.0%,MarbleSend 会主动提醒管理员优化名单质量和发信频次,避免发信域被主流服务商(Gmail、Yahoo、Outlook)降权。

1.2 运维与 Worker 健康心跳

MarbleSend 基于单一的主后台运行器 worker.php 运行。仪表盘检查 cm_settings['worker_last_run'] 以判断 cron 是否每 60 秒正常触发。

活动状态(Cron 运行正常)

当 worker.php 在过去 3 分钟内运行时,徽章显示“活动”。队列批次实时处理,定时通讯准时触发,自动回复器即时响应。

非活动状态(未检测到 Cron)

如果超过 3 分钟未记录心跳,徽章将变为红色。点击卡片可立即跳转至 Settings → 系统状态,查看准确的 crontab CLI 命令与 web-cron fallback URL。

活跃联系人与受众总盘对比

展示当前处于 active 状态的受众占全部联系人的比例。MarbleSend 实施严密的状态机机制:active、pending(等待双向 opt-in 验证)、unsubscribed 和 suppressed(退信或投诉)。投递作业严格仅匹配 WHERE status = 'active' 的受众。

月度与历史累计 Campaigns 规模

汇总当前日历月派发的邮件活动及平台累计创建的全部 Campaigns,让运营人员直观掌握营销节奏与产能。

下一批就绪计划解析

实时检索生效中的循环计划(按 next_run_at ASC LIMIT 1 排序),显示即将发送的刊物名称与倒计时。全部计划时间均由 SchedulerService::computeNextRun() 严格计算,并以 UTC 格式存储,杜绝夏令时(DST)偏差。

Worker 心跳与虚拟主机 Cron 调度

监测 worker.php 在过去 180 秒内是否按时执行。在虚拟主机(cPanel、Hostinger 等)环境中,请将 crontab 设定为 * * * * * php /path/to/worker.php >/dev/null 2>&1。若不支持命令行,可使用外部免费监控(如 cron-job.org)访问 Web-Cron 保障端点(/cron.php?key=YOUR_KEY)。

1.3 Campaign 增长可视化图表

增长可视化图表支持 4 个可选时间范围渲染发送量分布:7 天、30 天、90 天以及本年迄今(YTD)。每个柱状图代表聚合的时间分段,悬停时显示发送数与打开数。

多周期灵活切换(7天、30天、90天、本年度)

支持在周度短线(7天)、月度波动(30天)、季度分析(90天)和本年度累计总览之间秒级切换。

纯原生零依赖的轻巧弹性柱状图

基于峰值发信量直接通过原生 CSS flexbox 计算高度呈现,摆脱笨重外部脚本,在移动设备和轻量级服务器上也能即开即看。

双指标交互悬浮提示窗

将光标移至柱状图上,即时展示对应的精确时间区间、邮件投递总数以及独立打开人数。

实时投递动态与系统健康流

右侧栏实时捕捉最新 Campaign 执行进程,配有动态状态标签(Completed、Sending 呼吸灯、Failed、Draft)、投递完成率及常驻的系统心跳监视卡片。

Completed

status = 'completed'

Sending

status = 'sending'

Failed

status = 'failed'

Draft

status = 'draft'

Campaigns 历史记录与投递审计总表

底部表格记录近期广播的详实元数据:包括邮件名称、生命周期状态、来源标签(manual、循环计划、RSS 抓取、未开补发)、受众送达比例与验证后的打开转化率。

Campaign 名称与来源

显示 Campaign 主题、创建日期和来源标签(manual、recurring、rss 或 resend_unopened)。

收件人与送达比率

即时统计送达与失败的消息数量,以及实时打开率和点击率百分比。

分析报告链接

直接跳转至 Campaign 报告页面,查看收件人级别的事件日志和未打开重发弹窗。

1.5 邮件送达率健康检查警示横幅

当您的发信域名缺少经过验证的 SPF、DKIM 或 DMARC record 时,MarbleSend 会在 KPI 指标上方显著显示警示横幅。点击“验证域名 DNS”将打开 /settings?tab=deliverability 下的 4 步诊断向导,防止用户因向未经身份验证的邮箱投递而损害域名声誉。

有效 SMTP 配置核查

标注当前在 Settings 中配置生效的外发 SMTP 节点数量。MarbleSend 支持多服务器多通道轮换发信,均衡分摊发送负载。

中继缺失告警与发信前置防护

如果系统未检测到任何可用 SMTP 节点,页面将显示显眼的红色警报,在发起 Campaigns 之前强制拦截,杜绝队列阻塞故障。

1.6 快捷入口与自动化作业流

打通仪表盘与核心模块的操作枢纽:快速建立定时周期简报、连接 RSS 博客自动生成期刊、受众名单导入、双重 opt-in 认证以及防黑名单自动抑制保护。

自动化作业流(定时循环与 RSS)

按照 cron 时间表或在关联的 WordPress/Ghost/Substack 站点发布新博文时,全自动编译并发放邮件,彻底告别手动搬运。

受众池与联系人全生命周期管理

支持 CSV 批量导入联系人、分类打标、强制 double opt-in 规范验证,并对退信和退订邮箱执行自动拉黑隔离。

模块 02

Campaign 管理与报告 (/campaigns)

高速广播编辑器、标签定向受众筛选器、预检安全引擎以及全方位的投递报告。

Interactive Campaigns UI Inspector

点击任意组件以检查其数据库模式影响及运维操作建议
PROGRESS

实时调度监控器

实时统计与事件流
AUDIENCE

收件人选择器

Tag 筛选与全选控制
COMPOSER

三重視图编辑器

代码、分屏与预览
SAFETY

Preflight 预检引擎

6 点自动化安全巡检
TESTING

测试发送诊断

无队列直接抽样
ATTRIBUTION

UTM 与链接重写器

UTM 参数与 302 点击追踪
PORTFOLIO

历史广播档案

status 与来源筛选
ANALYTICS

投递后深度报表

CTR、MPP 与自动重发

数据库影响:

技术支持团队专业提示:

2.1 实时 Campaign 监控横幅

每当广播处于正在分发状态时,/campaigns 顶部会滑入一个常驻监控横幅。它每 1.5 秒轮询一次 /api/campaigns/:id/progress,无需刷新整个页面。

Summer Launch Newsletter

Sending

74% complete

7,420 / 10,000 emails

队列中

2,528

正在发送

40

发送成功

7,420

发送失败

12

Recent Events Real-time status
ana.wijaya@example.com Delivered
budi.santoso@example.org Delivered
chen.li@example.net 550 5.1.1 User unknown
dewi.lestari@example.com Delivered
eko.prasetyo@example.org 正在发送
View Full Report

1.5 秒级轮询引擎

每 1.5 秒异步请求 /api/campaigns/:id/progress,实时呈现发送吞吐量而无需重新加载页面。

最新投递事件流

实时事件记录器,展示最近 5 条收件人 status 变动,提供即时送达确认与 SMTP 错误诊断。

TELEMETRY NOTE

如果后台 worker.php 出现延迟或 cron 任务停滞,系统会弹出带有快速排障指引的警告徽章。

2.2 收件人选择器与标签过滤器(左栏)

左侧栏支持精准的目标受众定位。管理员可以按自定义联系人标签筛选、按邮箱/姓名关键字搜索,并选择单个联系人或点击“选择所有匹配项”。

状态机过滤保障:

无论何种选择或搜索条件,查询引擎始终严格强制 status = 'active'。已退订、待确认或被抑制的联系人会自动从队列中排除。

多 Tag 交集筛选

按 tag 选择特定订阅者群组。收件人选择器会在毫秒级内动态计算交集联系人总数。

防抖实时搜索 (300ms)

支持按姓名或邮箱即时检索,内置 300ms 防抖机制,有效避免庞大列表对数据库造成突发负载。

全局选择控制面板

可勾选单个联系人,或使用“全选”开关一键圈定符合当前筛选条件的所有联系人。

分组

联系人按分组组织(一位联系人可属于多个分组;每位联系人至少属于一个分组,默认是 General)。在 Select Recipients 中选择“按分组”,即可发送给所选分组中的每位活跃联系人——整个分组,而不仅是当前查看的页面;选择“手动选择”则可挑选单个联系人(可按一个分组筛选)。

分组还可用作计划的受众、autoresponder 规则的触发条件、注册页面的去向,以及缩小对未打开者的重发范围。删除分组不会删除其中的联系人;依赖该分组的 autoresponder 规则会被停用。

2.3 Campaign 编辑器与分屏编辑模式

分屏模式

左侧代码实时编辑,右侧实时展示自适应响应式 iframe 预览。

仅代码模式

全宽无干扰 HTML 代码编辑器,带有边栏行号与 syntax 标签页。

实时预览模式

支持桌面端(100%)、平板端(600px)和移动端(375px)设备视口切换的沙箱渲染。

Placeholder 变量与文本替换引擎

支持使用 {{name}}、{{email}}、{{unsubscribe_link}}、{{offer_url}} 和 {{track_pixel}} 标签进行动态邮件个性化渲染。

沙箱化多端响应式视口

在发送前,可在完全隔离的 iframe 沙箱中预览手机端 (375px)、平板端 (600px) 和桌面端 (100%) 的响应式渲染效果。

2.4 6 点自动化预检安全机制

为防止灾难性失误(如发送占位符损坏、缺少退订链接或包含垃圾邮件触发词的邮件),MarbleSend 在正式发布前要求执行预检。

安全检查项目 严重程度 规则与检测机制 未通过的后果
1. 退订链接 严重(CRITICAL) 检查是否存在 {{unsubscribe_link}} token。 发送将被阻止。根据 CAN-SPAM、GDPR 及 2024 年 Yahoo/Google 发件人合规要求强制执行。
2. 占位符有效性 严重(CRITICAL) 检测未知的占位符标签(例如拼写错误 {{first_nam}})。 在纠正或移除未知标签之前,发送将被阻止。
3. 收件人受众 严重(CRITICAL) 验证所选活动收件人数量 > 0。 无法向空受众列表发送广播。
4. SMTP 连通性 严重(CRITICAL) 验证所选 SMTP 配置的主机和凭据。 防止因中继凭据失效导致队列停滞。
5. 垃圾邮件触发词 警告(WARNING) 扫描主题和正文中的垃圾邮件触发词短语(如 "100% free"、"act now"、"limited time")。 显示警告横幅;管理员可以审查后继续。
6. 主题行长度 提示(INFO) 建议保持在 30–60 个字符,以获得最佳的移动端显示效果。 旨在提高打开率的参考提示。

Preflight 预检防错门禁

在提交入队前严格核验 6 条自动化安全规则。若存在任何致命级别错误,发送按钮将被彻底禁用。

2.5 测试发送诊断与确认弹窗

在将成千上万封邮件提交至队列之前,“发送测试邮件”按钮可直接向管理员或 QA 邮箱发送单封即时测试邮件,而不触及数据库收件人列表。所有占位符标签({{first_name}}、{{email}}、{{unsubscribe_link}})均填充模拟预览值,以便您检查邮件在 Gmail、Apple Mail 和 Outlook 中的渲染效果。

模拟数据真实插值

将订阅者变量替换为高仿真预览值(如 Jane Doe、测试退订链接),以便进行真实的视觉核验。

发布前核对确认弹窗

双重确认对话框,在创建队列前清晰陈列收件人总数、选定发件人配置及启用的 UTM 标签。

2.6 自动化 UTM 跟踪注入

所有出站锚点链接(<a href="...">)均通过 App\Services\TrackingInjector 处理。在进行点击重定向包装之前,会自动追加 UTM 参数(utm_source、utm_medium、utm_campaign、utm_content)。Mailto 链接、tel 链接及退订链接均保持原样,不受影响。

PIPELINE 01

步骤 1: UTM 查询参数注入

在不损坏既有查询参数的前提下,向每个超链接自动追加 utm_source、utm_medium、utm_campaign 和 utm_content。

PIPELINE 02

步骤 2: 追踪像素植入

在闭合 </body> 标签前插入 1x1 透明 GIF 图片,当邮件客户端渲染时即时记录打开事件。

PIPELINE 03

步骤 3: 302 点击重写引擎

将外部链接重写为 /track/click.php?h=...,在完成毫秒级跳转的同时记录首触点击遥测日志。

严格合规豁免策略

退订链接、mailto/tel 协议以及 double opt-in 确认链接被严格排除在 UTM 和点击追踪重写之外。

2.7 Campaign 历史与归档 (/campaigns/history)

完整的历史档案支持按来源(manual、recurring、rss、resend_unopened)、状态(completed、sending、failed、draft)以及日期范围等多属性进行筛选。管理员可以多选 Campaign 以导出下载汇总的 CSV 投递日志。

投递来源追踪管线

按来源细分广播类别:手动 Composer、循环调度任务、RSS 博客触发或针对未打开者的重发克隆。

多 status 过滤与 CSV 导出

支持按已完成、发送中、失败和草稿状态筛选归档。只需一键即可打包下载详尽的送达日志。

一键广播任务克隆

可将历史广播完整克隆回 composer,原有 HTML 排版、subject 行及发件人配置均完好保留。

2.8 分析报告与“未打开重发”功能

可选:选择分组,仅向属于这些分组且未打开邮件的联系人重发。重发永远不会超出原 Campaign 的收件人范围。

在 /campaigns/:id/report 下,MarbleSend 呈现详尽的发送后报告:

KPI METRICS

4 维 Bento 核心表现指标

全面追踪已发送量 (100%)、投递失败数、独立打开数与打开率,以及独立点击数与 CTR。

TEMPORAL CLUSTERS

24 小时互动分布曲线

展示前 72 小时内的逐时打开热点分布,帮助定位最适合目标受众的黄金发送时段。

ENGAGEMENT RECOVERY

精准未打开重发功能

针对 opened_at IS NULL 的未打开订阅者快速克隆任务,支持更换全新 subject 重新激活 15–25% 额外打开,同时避免重复打扰活跃读者。

模块 03

联系人中心与增长工具 (/contacts)

订阅者全生命周期管理、CSV 导入、GDPR 合规、自定义注册页面与自动回复器。

交互式联系人界面检查器

点击任意组件以检查数据库架构影响与运维支持技巧
生命周期

4 状态状态机

active/pending/unsub/supp
筛选过滤

搜索与筛选引擎

标签、状态与防抖
遥测审计

审计与合规抽屉

IP、时间戳与退信
数据导入

RFC 4180 CSV 导入器

5万行容量与去重保障
转化漏斗

独立托管注册页

双重验证与漏斗
自动化

标签自动回复器

事件驱动点滴规则
批量管理

批量管理中心

跨页细分操作
合规保障

GDPR 隐私与清除

JSON 导出与彻底清除

数据库影响:

技术支持团队专业提示:

3.1 订阅者 4 状态生命周期状态机

MarbleSend 为所有联系人维护严格统一的状态机,没有任何额外的 boolean 标志。每一个发信流程均统一执行 WHERE status = 'active' 进行筛选。

active

活跃订阅者

已确认自愿订阅,邮箱有效。具备接收 Campaign、计划任务及自动回复邮件的资格。

pending

双重确认等待中

通过双重确认表单注册,正等待点击确认邮件。在确认之前不参与广播群发。

unsubscribed

已退订

已点击退订链接。永久不再发送。未经显式重新订阅,不可手动重新激活。

suppressed

硬退信 / 投诉

因无效邮箱(5xx SMTP 错误)、垃圾邮件投诉或管理员手动抑制而被永久抑制。

状态 转换触发条件 目标状态 Campaign 派发影响
active 订阅者点击退订链接或 RFC 8058 邮件头 unsubscribed 立即从未来的所有广播队列与定时计划中排除。
active SMTP 5xx 永久退信或连续第 3 次软退信 suppressed 永久隔离列入黑名单,以保护发信域名的送达声誉。
pending 订阅者点击双重验证邮件中的 Token 确认链接 active 升级为 active;有资格接收普通 Campaigns 及自动回复邮件。
suppressed 管理员在确认后手动解除压制限制 active 重置软退信计数器;恢复至活动发送队列中。

架构防护:零冗余布尔标志

MarbleSend 强制采用单列 ENUM (cm_contacts.status)。许多系统因 is_active、is_unsubscribed、is_bounced 等布尔标志冲突而频发数据损坏。在 MarbleSend 中,每个发送查询均明确包含 WHERE status = 'active',毫无歧义。

3.2 实时筛选、搜索与行级操作

联系人表格具有基于 Alpine.js 的即时响应式过滤功能,可按标签、订阅者状态(active、pending、unsubscribed、suppressed)进行筛选,并支持针对邮箱和姓氏/名字的无卡顿防抖搜索。

每位联系人至少属于一个分组(默认 General)。用“分组”筛选器缩小表格范围,用“管理分组”创建、重命名或删除分组——删除分组不会删除其中的联系人。

JSON 标签存储与标准化

标签以规范化 JSON 数组形式存储在 cm_contacts.tags 中。大小写不敏感,自动去除空格并建立索引以支持高速检索。

300ms 防抖即时搜索

检索同时涵盖邮箱地址、名字与姓氏,并设置 300ms 防抖缓冲以减轻数据库压力。

服务端分页与大容量伸缩

凭借高效的 SQL LIMIT 与 OFFSET 查询,在极低内存占用下顺畅浏览超过 50,000 名订阅者的列表。

直接编辑

无需刷新页面,内联更新姓名、自定义元数据和标签项。

手动抑制

即时抑制联系人,使其立即失去进入所有队列的资格。

GDPR 物理删除

依据 GDPR 第 17 条永久清除联系人资料、日志与队列记录项。

3.3 详情抽屉、GDPR 审计跟踪与 JSON 导出

点击任何联系人行即可滑出审计抽屉。它展示全生命周期指标(接收邮件总数、打开率、点击数)、订阅时的 IP 地址、订阅时间戳、注册表单 slug,以及一键导出 GDPR JSON 按钮,完全符合第 15 条(访问权)和第 20 条(数据可移植权)。

订阅时间戳与许可来源

精准记录日期、精确时间以及获客渠道(手动录入、CSV 导入、注册页别名或 API),作为法律合规依据。

已验证的 IP 地址记录

在提交注册表单的瞬间捕获订阅者 IP 地址,符合 GDPR 与 CAN-SPAM 的法定举证标准。

生命周期互动遥测

统计累计发信量并记录最后一次验证打开的时间戳,精准区分活跃受众与休眠用户。

软退信自动升级压制

严密监控连续临时投递失败(X / 3)。一旦遭遇连续第 3 次软退信,联系人状态自动转换为 suppressed。

3.4 CSV 导入器与列映射

导入器支持解析多达 50,000 行的 CSV files。它能自动检测分隔符(逗号、分号、制表符),并提供可视化下拉菜单将列映射至:邮箱、名字、姓氏和标签。

选择导入的联系人加入哪些分组(未选择则为 General)。已有联系人会被加入这些分组,不会从其已属的分组中移除。

内存安全的分块分批导入

以事务数据块方式流式处理多达 50,000 行的文件,即使在内存严苛的虚拟主机上也始终保持在 32MB 以下。

自动分隔符识别与智能映射

自动识别逗号、分号及制表符,并为邮箱、名、姓和标签提供可视化列映射交互。

批量打标与导入后审计

为导入批次内的所有联系人统一定义全局标签,并清晰汇报新增、更新与跳过的数据统计。

跳过重复

保留现有联系人详情与标签,仅插入新增的数据行。

更新空白字段

补充缺失的姓名并追加新标签,不覆盖现有数据。

全部覆盖

完全更新姓名和标签,以精确匹配导入的 CSV file。

3.5 公共注册页面 (/s/:slug)

位于联系人模块的第 2 个标签页。创建具有自定义标题、描述、输入标签和提交按钮的独立品牌订阅页面。功能包括:

选择来自此页面的订阅者加入的分组(未选择则为 General)。之后被删除的分组会自动忽略。

总浏览量

统计所有有效注册漏斗累积的落地页浏览曝光次数。

平均转化率

计算所有托管表单提交量与访问曝光次数的百分比。

运行中页面 / 容量上限

展示当前启用的落地页面数量与 20 页系统上限的对比。

近 30 天新增提交

追踪过去 30 天滚动周期内成功获客的新增订阅者总量。

全渠道表单嵌入集成

表单可灵活部署于各处:直接访问链接 (/subscribe?slug=...)、原生 HTML 代码、响应式 iframe 或 JS 弹窗代码。

双重确认引擎

生成具有 HMAC 签名的确认 token,并自动发送确认邮件。

自动打标签

在订阅时为用户分配指定标签,以触发个性化点滴邮件序列(drip sequence)。

自定义重定向

订阅确认后,将新订阅者引导至您的感谢页面或引流赠品 URL。

3.6 自动回复器与邮件序列 (Drip Sequences)

位于 Contacts 的标签页 3。设置自动欢迎邮件:新订阅者一旦变为活跃(注册后立即,或确认 double opt-in 之后)即进入队列。规则匹配一个标签或一个分组;没有延迟设置。邮件由后台 worker 投递,并自动遵守 suppression 规则。

规则可以按分组而不是标签触发。分组规则在该分组中创建新的活跃联系人或其通过邮件确认时运行——而不是在已有联系人之后被加入该分组时运行(与标签规则相同)。删除分组会停用该规则。

基于标签的事件监听器

当新的活跃订阅者带有规则的标签或属于其分组时触发——在注册页面、API 调用或手动添加(single opt-in)之后立即触发,或在 double opt-in 确认之后触发。CSV 导入不会触发,之后给已有联系人添加标签或分组也不会触发。

专属独立 SMTP 路由

通过高信誉评级的专用 SMTP 发送事务性欢迎邮件,与大宗营销广播通道物理隔离。

Worker 异步队列执行

将邮件渲染与投递完全移交 worker.php 异步调度,杜绝网页超时,保障表单秒级响应。

防死循环与单次去重保障

防止重复触发规则,确保订阅者即便多次打上同一标签也不会收到冗余的重复欢迎邮件。

3.7 批量管理与受众分群 (/contacts/list)

在 /contacts/list 下进行大批量受众管理与批处理操作:跨页选择、批量打标签或移除标签、同时抑制数千个沉睡潜在客户,或将目标细分人群导出为 UTF-8 编码的 CSV files。

“添加到分组”和“从分组移除”适用于所有选中的联系人。将联系人从其最后一个分组移除后,会回到 General。

批量追加标签

单条 SQL 查询为所有选中联系人追加指定标签,完整保留联系人原有标签。

批量移除标签

从所选名单中精准批量剥离指定的单个或多个标签。

导出筛选后的 CSV

将筛选出的特定受众子集直接流式导出为包含完整元数据的 RFC 4180 CSV 文件。

批量压制列黑 (Suppression)

迅速将休眠或高风险联系人统一列入隔离压制名单,巩固发信人信誉。

批量退订标记

批量处理来自外部渠道或线下活动收集的退订需求。

GDPR 彻底物理擦除

根据 GDPR 第 17 条要求,彻底且不可逆地抹除订阅者记录与关联遥测日志。

3.8 GDPR 隐私规范、审计导出与删除标准

内置严格契合欧盟通用数据保护条例 (GDPR)、加州 CCPA 及 CAN-SPAM 法案要求的隐私合规管控。

GDPR 导出(JSON)也会列出该联系人所属的分组。

第 15 与 20 条:结构化 JSON 数据导出

生成包含联系人完整资料、许可 IP、订阅时间戳及发信日志的机器可读 JSON 档案。

第 17 条:被遗忘权(级联彻底清除)

永久物理删除操作将级联清理 cm_contacts、cm_email_logs 与 cm_email_queue,彻底销毁所有可识别隐私。

解除压制安全防线

重新激活已被压制的地址必须经过管理员二次显式确认,防止意外向失效邮箱误投邮件。

模块 04

模板工坊与 AI 文案撰写 (/templates)

8 种邮件安全的表格布局、带迷你 CSS 重置的沙盒 iframe 预览、面向销售的 AI 文案助手,以及用于通讯的 Markdown 新闻文章。

Templates Studio UI 检查器

点击下方任一组件查看数据库查询、数据表影响和运维操作建议
SIDEBAR

Template 库

即时搜索与 slug 键
PRESETS

Starter 布局

8 款基于表格的邮件布局
EDITOR

原生代码编辑器

Tab 缩进与美化
PREVIEW

沙箱隔离 Viewport

桌面与手机视口边框
TOKENS

动态 Tokens 调色板

一键插入占位符
DIAGNOSTIC

测试邮件发送器

实时 SMTP 验证弹窗
AI COPY

AI Copywriter 抽屉

生成与润色 templates
AI AUDIT

主题评审器

1–100 评分与垃圾词审计
文章

新闻文章

面向通讯的 Markdown 文章

数据库影响:

技术支持团队专业提示:

4.1 Template 库、自定义 Slugs 与元数据管理

集中管理所有营销、事务性及自动回复邮件 templates 的核心库。具备客户端即时筛选、不可变 URL slugs 和实时草稿指示器。

不可变 Template Slugs

Slug ID(如 #monthly-newsletter)在创建时定义并在保存后锁定,确保自动化 RSS Campaigns 与触发序列绝不失效。

亚秒级防抖即时搜索

客户端 Alpine 筛选器可飞速检索 template 标题、主题和唯一 slug,无需产生任何多余的数据库往返请求。

实时草稿状态同步

专属虚线指示卡片能够直观区分内存中编辑的草稿与线上正式 templates,杜绝无意覆盖。

独立 Campaigns 历史快照

修改或删除库中 template 绝不会破坏已发送的历史记录。已发出的 Campaigns 会在 cm_campaigns 中保留独立静态快照。

4.2 8 款经过实测的基于表格的响应式 Starter 布局

传统桌面邮件客户端(特别是基于 Word HTML 引擎的 Microsoft Outlook)不支持 CSS Grid 或 Flexbox。MarbleSend 提供 8 款兼容 Gmail、Outlook、Apple Mail 和 Yahoo 的响应式表格布局:

1. 极简空白

包含合规必需退订页脚的极简留白画布。

2. 新品发布

头部大图、核心价值主张与醒目的 CTA 按钮。

3. 月度通讯

精选社论、双栏文章资讯速览。

4. 新闻文章通讯

页眉横幅加上用于新闻文章计划的 {{news_posts}} 区块。

5. 欢迎序列

个性化新手引导、三步入门指引。

6. 网络研讨会邀请

日期/时间徽章、主讲人简介与 RSVP 报名按钮。

7. 博客精选

编号文章列表、预计阅读时间与作者标签。

8. 挽回召回

限时紧急折扣优惠券、基于损失厌恶心理的转化文案。

嵌套表格架构与内联 CSS

每套 starter 布局均采用显式像素宽度限制、单元格边距为零的嵌套 <table> 元素和预内联 CSS 构建,保障排版万无一失。

4.3 原生 HTML 代码编辑器与整洁格式化

专为邮件前端开发者定制的高效编辑器,支持 Tab 键缩进捕获、实时字符统计与自动化空行规范化。

Tab 键智能缩进捕获

在文本区按下 Tab 键将插入 2 个空格而非切换网页焦点,方便在浏览器内流畅调整代码层级。

一键代码美化("Clean")

统一不规则缩进,清除多余回车空行,在完全保留行内样式声明的前提下规整嵌套表格代码。

体积监控与截断防范

实时字符计数器监控邮件体积。将 HTML 重量控制在 102 KB 以内,防止被 Gmail 截断并显示 "[Message clipped]" 提示。

彻底杜绝 WYSIWYG 冗余垃圾代码

直接编写原生 HTML 可杜绝可视化拖拽工具生成的杂乱 CSS 类名、非标字体及隐藏 span 标签,守护送达率。

4.4 沙箱隔离多设备响应式 Viewports

在沙箱隔离的 iframe 中仿真桌面与移动邮件客户端,既隔绝样式外溢以保护管理后台,又能提供瞬时视觉反馈。

Iframe 安全性与 CSS 样式隔离

采用 sandbox="allow-same-origin" 特性,完全隔绝邮件 CSS 规则对 MarbleSend 后台界面样式的干扰。

桌面端与 320px 移动端视口切换

一键在全宽桌面视口与逼真的 320px 手机边框视口间快速切换,校验单列自适应响应表现。

实时主题行仿真栏

顶部预览栏即时呈现解析后的主题文本,在正式发出前直观查看个性化占位符替换后的视觉效果。

动态 Syntax 语法错误警告横幅

自动扫描草稿代码,一旦探测到未闭合的占位符标签或非法合并 tokens 便立即弹出告警提示。

4.5 动态个性化 Tokens 与 RFC 规范兼容

发送时,模板引擎会把 token 动态替换为收件人属性、安全的跟踪链接、RSS 文章摘要和新闻文章。

{{name}}

收件人全名(若为空则默认回退为 "there")

{{email}}

收件人电子邮箱地址

{{unsubscribe_link}}

符合 RFC 8058 标准的一键退订链接

{{confirm_link}}

用于注册页面的 double opt-in 确认 URL

{{posts}}

自动化 RSS 新闻通讯的博客文章遍历循环块

{{feed_title}}

所关联 RSS/Atom 内容订阅源的名称

{{latest_post_title}}

最新发布的一篇博客文章标题

{{posts_count}}

本次新闻通讯中收录的新文章数量统计

{{news_posts}}

用于通讯计划的新闻文章区块(封面、标题、副标题、正文)

{{news_posts_count}}

本次发送包含的新闻文章数量

{{news_latest_post_title}}

本次发送中最新新闻文章的标题

法定合规要求与送达率护航

所有营销广播邮件必须附带 {{unsubscribe_link}}。缺失有效退订途径的邮件将直接违反 CAN-SPAM、GDPR 及 CASL,招致主流服务商封禁。

4.6 单次测试发送诊断与投递前审查

弹窗式诊断工具,支持在正式排期或广播发送前,通过所选 SMTP 配置文件向任意指定邮箱发送实战测试邮件。

多 SMTP 配置文件灵活切换

通过任何已配置的 SMTP 节点发送测试邮件,验证特定邮件路由服务器的 SPF、DKIM 和实际入箱情况。

占位符合成模拟数据填充

自动将个性化 tokens 替换为逼真的测试数据(如 "John Doe"),以便准确核查图文排版与对齐细节。

绕过队列同步直达

绕过后台异步任务队列(cm_email_queue),借助 MailerFactory 立即同步发出并实时返回成功或失败状态。

收件箱与暗黑模式品控

直接发往个人的 Gmail、Outlook 和 Apple Mail 账号,现场排查暗黑模式颜色反转与按钮字体对比度。

4.7 强转化 AI Copywriting 引擎 BYOK

内置 AI 文案助手,通过直连 BYOK(自带密钥)运行,极速生成与打磨高转化且符合邮件排版标准的 templates。

核心原则:生成质量取决于 Prompt 与所选 LLM 模型

MarbleSend 不会将您限制在单一闭源 AI 模型中。由于生成是通过您配置的 BYOK 提供商运行,邮件布局品质、说服力、HTML 表格精准度以及主题审查深度根本上由两个变量决定:您输入的 prompt 指令精细度以及所选 LLM 模型的推理能力。

1. 用户 Prompt 的具体性与上下文深度

AI 模型直接反映您所提供指令的清晰度。类似“写一封促销邮件”的通用 prompt 只能生成平庸文案。要获得卓越效果,请提供结构化上下文:目标受众、核心痛点、主打优惠、语气风格(紧迫、对话式、专业商务)以及明确的行动号召(CTA)。在“编辑模板”标签页中,输入针对性修改指令(例如“缩短第二段”、“在 CTA 按钮上突出 20% 折扣”或“添加 3 点优势摘要卡片”),即可逐步微调模板。

2. LLM 模型级别与推理能力

在 Settings → AI Providers 中,您可以连接顶级推理模型(如 DeepSeek-V4.1-flash、Claude 5 Sonnet 或 GPT-6)或轻量级本地模型(如通过 Ollama 或 Groq 运行的 7B–8B 模型)。顶级模型极擅长嵌套复杂的邮件安全 HTML 表格、自然嵌入个性化 token({{name}}、{{email}}、{{unsubscribe_link}})并输出极具转化力的文案。在“主题选项”标签页中,1–100 评分、垃圾邮件风险与变体推荐均由当前活跃模型即时生成;更强大的模型能提供更深刻的批判分析与更具吸引力的备选方案。

MarbleSend 内置 System Prompt 防护栏

无论 prompt 长度或模型选择如何,AiService.php 均会自动注入可靠的邮件安全架构规范:单表格响应式结构(最大宽度 600px、纯净背景、高对比度卡片)、兼容 Outlook 和 Gmail 的防破损表格 CTA 按钮、零外链图片以规避拦截,以及页脚强制注入 {{unsubscribe_link}} token 以符合全球邮件合规要求。

全量 Template 生成模式

依据目标受众、核心卖点、品牌语调和目标阅读篇幅,一键生成完整的响应式表格 HTML 邮件代码。

上下文感知精修模式

读取编辑器中的现有代码并按自然语言指令精准迭代(如"增加 3 个特性介绍区块"或"强化 CTA 紧迫感")。

交互式可视化双屏对比

并排沙箱 iframe 同步呈现"修改前"与"修改后"的视觉效果,核验无误后再一键应用到当前编辑器中。

主流提供商 API Key 获取全指南

获取 API Key 与目标模型 ID 后,只需通过以下几步即可在 MarbleSend 完成配置:

6.7 双模式 AI 引擎:BYOK 服务商与 MarbleSend AI 额度

4.8 AI 主题评分与送达率检查器

深度扫描库内所有邮件主题行,全方位测评打开率潜力、垃圾邮件拦截风险与字符截断情况,并提供一键替换版本。

全库主题快速索引

读取 cm_templates 数据表中的所有主题并集中于滚动列表中,同时重点高亮当前正在编辑的 template 对应条目。

1–100 多维度科学打分

当前选定的大语言模型从好奇心引发度、清晰度、价值主张与紧迫感四个维度进行量化推演,给出客观百分制总分。

移动端截断预警与垃圾词过滤

对超出手机屏幕限制的过长文本(建议 <= 50 个字符)标红告警,同时敏锐识别 "免费"、"紧急 $$$" 等高危垃圾词。

多角度高转化备选变体

自动衍生出基于好奇心驱动、利益诉求或损失厌恶心理的高转化备用主题行,支持一键载入编辑器。

新闻文章 — 面向通讯的 Substack 风格文章

在“模板”的“文章”标签页中撰写文章(带实时预览的 Markdown)。设置为“新闻文章”的通讯计划会通过填充其模板的 {{news_posts}} 占位符,把每篇就绪文章按从旧到新的顺序只发送一次。文章只存在于你的邮件中 — 没有公开页面。

撰写并标记为就绪

使用工具栏或纯 Markdown。只有把文章从草稿切换为就绪后才会发送。

模板占位符

把 {{news_posts}} 放在文章应出现的位置(“新闻文章通讯”入门模板已包含它)。{{news_posts_count}} 和 {{news_latest_post_title}} 可用于主题。

安排计划

在“计划”中选择通讯,然后选择内容来源:新闻文章。只有从那一刻起标记为就绪的文章才会发送,因此你的存档永远不会被重新发送。不使用智能防重复发送。

设计即安全

文章文本会作为 HTML 转义,仅允许 https 链接和图片。请将每封邮件控制在约 100 KB 以内,以免 Gmail 截断退订链接 — 编辑器会提醒你。

文章工作区概览

打开“模板”并切换到“文章”标签页。左侧是库,右侧是带实时预览的编辑器——与模板工作室布局相同。

部分作用
库列出每篇文章,显示草稿或就绪徽章、已发送次数和最近修改时间。搜索框按标题和副标题筛选;悬停时会出现垃圾桶图标。
标题、副标题、封面标题必填(最多 255 个字符,单行)。副标题(最多 500)显示在其下方。封面图片必须是 https URL——其他内容在保存时会被拒绝。
状态开关草稿文章绝不会被发送。把文章切换为就绪会记录它变为就绪的时刻;该时刻决定哪些计划可以发送它。
Markdown 编辑器工具栏按钮(标题、粗体、斜体、链接、列表、引用、分隔线、图片)会在所选内容周围插入 syntax。一篇文章最多可包含 100,000 个字符。
实时预览使用与真实发送相同的代码,在你选择的模板中渲染未保存的文章,并显示邮件大小(KB)。{{name}} 等占位符使用示例值。
占位符快捷方式编辑器下方的按钮会复制 {{news_posts}},方便粘贴到模板中。

Markdown 参考

文章文本使用一个小而安全的 Markdown 子集编写。此列表之外的内容都保持为纯文本。

Syntax结果
## Heading
### Smaller
标题(1–3 级会变成适合邮件的标题)
**bold** *italic*粗体和斜体
[text](https://example.com)链接。只有 http、https 和 mailto 地址会被链接;其他任何协议(例如 javascript:)都保持为纯文本。
- item
1. item
项目符号列表和编号列表
> quote块引用
---分隔线
![alt](https://example.com/a.png)图片。仅限 https;请始终为屏蔽图片的读者添加简短描述。
(blank line)段落以空行分隔;单个换行在段落内仍然是换行。
<script>alert(1)</script>原始 HTML 从不会被解析:你输入的 <script> 或 <img> 标签会按字面文本显示。

{{news_posts}} 占位符系列

把它们放在模板中;新闻文章计划会在发送时填充它们,早于 {{name}} 这类按收件人处理的 token 被解析。

占位符变为
{{news_posts}}本次发送的文章区块:每篇文章的封面图片、标题、副标题和正文,最早的在前。模板正文中必填。
{{news_posts_count}}本次发送中的文章数量,例如 1。可用于主题和正文。
{{news_latest_post_title}}本次发送中最新文章的标题。非常适合主题行。

正文中必填

如果模板正文没有 {{news_posts}},新闻文章计划在保存时会被拒绝;如果模板之后被编辑,运行会安全失败(文章保持待发送)。

绝不会以原始文本发送

在其他地方使用时——手动 Campaign、RSS 计划或仅模板计划——占位符会被替换为空文本,并且 Campaign 预检会在发送前警告你。

个性化并被跟踪

文章文本走正常流程:文章内的 {{name}} 会按收件人个性化,链接会附带 UTM 参数和点击跟踪,模板中的退订链接保持完整。

文章生命周期

每篇文章都经历相同的简单状态;库中的徽章始终显示当前状态。

草稿

仍在撰写中。绝不会被发送。把就绪文章退回草稿会清除其就绪时间。

就绪

已排队等待发送。只有当文章在该计划的新闻文章模式开启之后变为就绪时,计划才会发送它。重新保存已就绪的文章不会改变它在队列中的位置。

已发送

按计划记录,并在库中显示为“已发送 1×”。即使你之后编辑文章,计划也不会把同一篇文章发送两次。

已删除

移除文章及其投递记录。已送达的邮件不受影响,已删除的文章无法恢复。

邮件大小与安全

文章把完整文本放在邮件内——没有公开页面——因此大小和安全性比仅含链接的摘要更重要。

先转义

你输入的每个字符在应用任何格式之前都会作为 HTML 转义,因此脚本和标签永远到不了收件人的收件箱。

仅限 https

图片和封面必须是 https。链接接受 http、https 和 mailto。其他协议显示为纯文本。

保持在约 100 KB 以内

Gmail 会截断超过约 102 KB 的邮件,并隐藏包含退订链接的页脚。预览会显示以 KB 为单位的大小,并在超过 80 KB 时警告;长文章请减少每封邮件的文章数量。

没有公开存档

文章只存在于你发送的邮件中。没有网页、没有图片上传,也没有自动 AI 调用——图片通过 URL 链接。

快速故障排查

现象检查什么
预览没有显示文章所选模板没有 {{news_posts}} 占位符(列表中标为“无 {{news_posts}}”)。请选择其他模板或添加该占位符。
“邮件较大”警告缩短文章、去掉繁重的格式,或在计划中降低“每封邮件的文章数”。
链接无法点击请写成 [text](https://…),并使用 http、https 或 mailto 地址;其他协议保持为文本。
图片没有显示地址必须以 https 开头并可公开访问。部分邮件应用还会屏蔽远程图片,直到读者允许。
Module 05

Schedules 与 RSS 自动化 (/schedules)

定期通讯发送(模板或新闻文章)、交互式月度发送日历、周期引擎、动态受众定位,以及博客 RSS/Atom 自动 Campaigns。

计划、RSS 与新闻文章 UI 检查器

点击下方任一组件,即可查看数据库查询、架构影响及运维支持建议

Interactive Inspector
日历

日历与月度矩阵

可视化排期分布与执行节奏
节奏

周期性循环引擎

每日、每周、每月及自定义规则
RSS / ATOM

博客订阅自动轮询器

哈希去重与缓存校验
AUDIENCE

动态受众

在执行的精准秒级动态查询标签
审计

触发日志

执行审计与重复投递防御
执行

即时触发 Run Now

无需改变既定周期立即发送
优化

主机优化

8 项经过生产验证的最佳实践
WORKER

Cron 心跳与锁

非阻塞式并发安全屏障
文章

新闻文章模式

Substack 风格的通讯

数据库影响:

技术支持团队专业提示:

5.1 双模式运作: 交互式计划任务管理器与日历全景视图

MarbleSend 提供了针对不同工作流优化的双重视图:紧凑高效的便当网格(Bento-grid)任务管理器 (/schedules) 与宏观交互式月度日历 (/schedules/list)。

紧凑表格与 Bento 网格视图

直观呈现所有周期性广播任务,包含下次运行倒计时、状态切换开关、选中模板缩略图及一键即时触发快捷入口。

交互式 7 列标准日历网格

在周日至周六的标准日历视图中映射未来发信排期,具备当天高亮、快速月份切换以及可点击的任务徽章。

选中计划任务详情抽屉

即时展开的审查面板,提供沙箱安全模板预览、周期循环参数、受众标签规则及常用操作按钮。

5.2 调度节奏引擎、循环规则与 UTC 时区规范化

周期性任务完全由 SchedulerService::computeNextRun() 驱动,彻底弃用脆弱的手工时间戳计算,采用严谨的 PHP DateTimeImmutable 数学运算。

通用 UTC 存储与本地化友好展示

所有 next_run_at 统一在 cm_schedules 中按 UTC 存储。在浏览器端展示时,自动转换为管理员设定的显示时区,同时严格维护收件人送达窗口。

按日与按周循环规则

支持每天固定时间发送,或通过交互式星期药丸按钮自选指定星期几(例如每周二与周四上午)发送。

月份日期自动钳位防护

针对设定在每月 29–31 日的发送任务,MarbleSend 在较短月份(如 2 月 28/29 日)自动将其对齐至该月最后一天。

时区与夏令时 (DST) 智能感知

利用原生 PHP DateTimeZone 运算,确保跨越夏令时调整节点时,广播依然精准在预期的本地时间触发。

5.3 自动化 RSS 与 Atom 订阅源轮询工作流

MarbleSend 借助原生 SimpleXML 与 cURL 直连您的博客或内容源,无需任何外部自动化工具即可将最新文章转换为受众广播。

双格式解析器 (RSS 2.0 与 Atom 1.0)

自动智能探测 XML 根节点,零依赖解析文章标题、摘要、永久链接与发布时间戳。

启动前在线实时订阅源探测

"Test Feed" 按钮实时连接目标 URL,验证 XML 规范合法性,确认 HTTP 200 状态并即时预览最新 3 篇文章。

哈希去重与初始历史基准快照

记录 last_rss_item_id 与发布日期。在初次保存计划时将最新文章作为基准点锁定,杜绝旧历史归档的意外大批量重发。

5.4 执行时动态受众解析与精准收件人定向

计划的受众也可限定为某个分组(与标签同时使用时两者都需匹配)。如果该分组被删除,计划会被停用,而不是悄悄地不发给任何人。

不同于普通 Campaign 的静态名单快照,周期性计划任务在触发运转的精准秒级动态计算当期收件人。

实时受众自动扩充

在预定发送时间前数分钟新增或打上相应标签的订阅者,无需人工 re-sync 即可无缝进入当期投递名单。

严苛的送达可达性状态过滤器

查询逻辑强制执行 WHERE status = 'active',无条件把待确认、已退订及抑制名单排除在周期发送队列之外。

基于标签的细分群体隔离

支持面向全体活跃订阅者发送,或仅定向至符合 JSON 标签数组规则的特定分群(例如 #weekly-digest, #customers)。

5.5 触发执行日志、运行审计与单次追补兜底原则

每次自动化触发都会在 cm_schedule_occurrences 中持久化一条只读审计记录,包含时间、结果、发信量及错误诊断遥测。

三态执行结果遥测

明确区分 'completed'(邮件成功入队)、'skipped'(未检测到新 RSS 文章)与 'failed'(SMTP 断开、模板非法或网络超时)。

单次追补幂等性守护

若主机 cron 在多次计划时间内处于离线状态,服务恢复后 MarbleSend 严格限制最多仅执行一次补发,并将 next_run_at 推进至未来时间。

触发历史审计弹窗

点击侧边栏的 "View Execution History" 即可直接在界面中审查往期执行明细、收件人总数与故障诊断日志。

5.6 按需手动即时触发 ("Run Now") 与紧急广播覆盖

管理员可直接跳过倒计时等待,借助 "Trigger Send Now" 操作即时启动任意计划的额外单次广播。

即时队列组装与推送

瞬间完成模板编译、活跃受众解析,并将批量邮件数据推送至 cm_email_queue,等待下一周期 worker 派发。

原定周期时间线绝对不受干扰

手动即时触发绝不会推迟或重置 next_run_at 时间戳,完美维持日历排期的原有节奏。

诊断测试与重大突发通知利器

用于在真实收件人数据环境下校验模板渲染效果,或在常规作息时间之外即刻发送重要通知。

5.7 高可用 Worker 并发防护、防重叠执行与非阻塞锁

MarbleSend 构建了针对共享主机资源环境的企业级并发防线,彻底根除高延迟网络下的重复投递隐患。

非阻塞式 flock 文件并发锁

worker.php 在 storage/worker.lock 上申请独占锁。若上一周期仍在处理慢速 SMTP 连接,新进触发进程将安全且静默地直接退出。

双执行模式协议一致性

无论是命令行 worker.php 还是 HTTP cron.php,均运行完全相同的执行路径与锁逻辑,确保 cPanel cron 与外部监控行为一致。

原子化任务状态认领

到期计划通过原子化 PDO prepared statements 进行加锁认领,即使在多线程或容器部署下也不会产生竞态重复入队。

5.8 共享主机性能调优与 8 项精选最佳实践

Schedules 页面上的动态 Optimization Tip 卡片汇聚了 8 项在生产环境中验证有效的可靠投递建议:

1. 黄金早晨发送时间窗口

建议将发送时间安排在收件人当地时间周二或周四上午 09:00 至 10:30 之间,以获得最高打开率与点击率。

2. 1 分钟 Cron Worker 频率保证

配置 worker.php 每分钟执行一次 (* * * * *) 并启用 flock 锁防护,实现亚分钟级响应且无进程堆叠。

3. 原子化队列批量认领

使用带有 LIMIT 与索引的预处理语句查询 cm_email_queue,在高并发流量高峰期间消除数据竞争条件。

4. 订阅者时区标签分群调度

按地域标签(#us-east, #apac, #emea)划分订阅者并配置错峰时间表,避免在当地凌晨 3:00 打扰用户。

5. RSS 内容发布缓冲等待

将 RSS 触发时间设为 CMS 文章发布后 1–2 小时,确保 CDN 边缘节点与 XML 缓存已完整同步刷新。

6. 定期归档清理触发历史记录

定期归档清理 cm_schedule_occurrences 中的陈旧日志,在共享主机上保持数据库体积精简与索引高效。

7. 48 小时未打开追投二次触达

在首次发送 48–72 小时后,向 opened_at IS NULL 的收件人更换新主题再次发送,可唤醒 15–25% 的流失关注。

8. 独立专属 SMTP 配置文件路由隔离

为自动化 RSS 博客通知与大批量市场营销 Campaign 分配独立的 SMTP 配置,严格隔离并维护发件域信誉。

5.9 新闻文章计划(Substack 风格的通讯)

通讯计划现在可以发送文章,而不只是一个固定模板。把内容来源设为“新闻文章”,每次运行就会投递“模板”→“文章”中的下一批就绪文章,并通过 {{news_posts}} 插入模板。没有文章等待时不会发送任何内容。

我应该使用哪种内容来源?

仅模板

每次运行都使用同一个模板——适用于定期公告或提醒。可使用智能防重复发送。

RSS 摘要

外部博客订阅源的新文章。首次运行只会把现有文章标记为已见;之后的运行只发送新文章。

新闻文章

你在 MarbleSend 内撰写的文章。每篇就绪文章按从旧到新的顺序发送一次。最适合 Substack 风格的通讯。

六步完成设置

  1. 1打开“模板”→“文章”,用 Markdown 撰写你的文章。
  2. 2创建或打开一个模板,把 {{news_posts}} 放在文章应出现的位置(“新闻文章通讯”入门模板已包含它)。
  3. 3打开“计划”→“新建”,保持类型为通讯,并把内容来源设为“新闻文章”。
  4. 4选择模板、受众、SMTP 配置、每封邮件的文章数(1–20)和周期。
  5. 5保存。此计划只能发送在此刻之后变为就绪的文章。
  6. 6把文章标记为就绪。下一次执行——或“立即运行”——就会投递它。

每次运行会发送哪些文章

每次执行时,计划按四条规则、按此顺序挑选文章。

仅限就绪

草稿会被忽略,无论多久之前创建的。

在截止点之后

文章必须在计划的新闻文章模式开启之后变为就绪。你已有的存档绝不会被重新发送。

此计划尚未发送过

投递按计划记录,所以两个计划可以各发送同一篇文章一次,但绝不会发送两次。

最早的优先,直到上限

“每封邮件的文章数”(默认 1,最多 20)限制合并的数量。其余的等待下一次运行。

示例:你在周一保存计划。周五变为就绪的文章会被忽略;周二变为就绪的文章会在下一次执行时发送,此后该计划不会再发送它。

每次运行会记录什么

每次执行都会出现在计划历史中。只有当一批邮件真正进入队列时,文章才会被标记为已投递。

已发送

已创建并排队一个 Campaign,例如“1 post · 5 recipients queued”。文章被标记为已由此计划发送。

已跳过:没有新文章

没有等待中的就绪文章。不发送任何内容,计划会在下一次执行时再试。

已跳过:没有收件人

受众为空。文章保持待发送,一旦受众有活跃联系人就会发送。

失败

模板缺失或不再包含 {{news_posts}}。文章保持待发送;请修复模板后再次运行。

立即运行与测试发送

立即运行

一次真实的执行,由 worker 在约一分钟内完成。发送待发送的文章并把它们标记为已投递。

发送测试摘要

通过计划自己的 SMTP 配置,把下一批待发送文章(若没有,则是最新的就绪文章)发送到一个地址。绝不会把任何内容标记为已投递,并共用每分钟 5 次的测试上限。

编辑与暂停

  • 把计划从仅模板切换为新闻文章,会在那一刻设定新的截止点;切换回去则清除它。
  • 保存计划表单会重新检查模板是否包含 {{news_posts}}。暂停和恢复只是切换开关,从不检查这一点,所以你始终可以暂停。
  • 在新闻文章模式下,智能防重复发送会自动关闭:否则它会排除所有收到过往期的人。
  • 新闻文章仅适用于通讯计划;RSS 计划保留它们自己的订阅源逻辑。

阅读计划界面

  • 计划列表把这些计划标为“新闻文章”,而不是“通讯”。
  • 详情面板显示有多少就绪文章在等待此计划。
  • 在表单中,不含 {{news_posts}} 的模板会被标记,选择它时会出现警告。

快速故障排查

现象检查什么
我的就绪文章没有被发送检查它是否在计划保存(或切换为新闻文章)之后变为就绪、计划是否已启用,并查看历史条目中的“no recipients”或“failed”。
我刚写完一篇文章,计划就显示“no new posts”文章可能仍是草稿,或已被此计划发送过。打开“模板”→“文章”,查看徽章和“已发送 N×”。
无法保存:模板必须包含 {{news_posts}}把占位符添加到模板正文(不只是主题),或选择其他模板。
我想重新发送旧文章把它的文本复制到新文章中并把新文章标记为就绪——计划绝不会把同一篇文章发送两次。
模块 06

Settings 与基础设施 (/settings)

SMTP 多中继管理、cron 心跳监控、23 种语言国际化、送达率诊断与许可证激活。

Settings 与基础设施 UI Inspector

点击下方任意组件以查看数据库模式影响、后台进程和操作指南

Interactive Inspector
SMTP

SMTP 配置

自定义 SMTP 与托管 SES 中继
WORKER

Worker 与 Cron

1 分钟执行周期
LOCALES

23 种语言与主题

RTL 镜像与深色/浅色模式
API KEYS

REST API 密钥

限定范围的开发者访问权限
WEBHOOKS

事件 Webhook

HMAC-SHA256 事件推送
DELIVERABILITY

送达率套件

SPF、DKIM、DMARC 与 BIMI
AI BYOK

AI 提供商

BYOK 与 MarbleSend 额度
LICENSE

Ed25519 许可证

加密授权令牌

数据库影响:

技术支持团队专业提示:

6.1 双投递架构:BYO SMTP 与托管 Amazon SES 中继

MarbleSend 通过两种稳健的传输模型将活动执行与发信中继彻底解耦:(1) 自带 SMTP(BYO SMTP)用于连接现有的自建或第三方邮件服务器;(2) 基于 Amazon SES 的 MarbleSend SMTP,无需注册 AWS 账户或预热 IP 即可享受即插即用的企业级云分发。活动可灵活绑定任意配置,支持平滑默认回退与原子额度记账。

选项 1: BYO SMTP(自带中继基础设施)

连接任何标准 SMTP 服务商,包括 Postmark、Mailgun、Brevo、SendGrid、Resend 或主机的 cPanel 邮箱。支持 587 端口(STARTTLS)、465 端口(隐式 SSL/TLS)以及本地中继 25 端口,具备自定义身份验证和隔离的发件人头部。

6.1.1 SMTP 邮件服务器服务商(免费、商业与共享主机)

SMTP 目录与对比

使用标准 SMTP 凭据连接自定义邮件传输通道。可在高并发云中继或现有主机邮箱间选择。

重要透明度说明:共享主机发送限制

标准共享主机邮箱执行严格的发信频次与日上限(通常为每天 100–500 封)。群发营销邮件请升级至企业邮箱包或接入云端中继。

专为大批量邮件发送和高收件箱送达率而优化。

服务商 / 官方网站 免费额度 商业价格 SMTP 主机与端口 关键规则与限制
Amazon SES (Direct) Free tier on EC2 only (62k/mo); Otherwise pay-as-you-go $0.10 / 1,000 emails ($1 per 10k) email-smtp.<region>.amazonaws.com
Port 587 (TLS) or 465 (SSL)
Requires AWS account setup, IAM SMTP user credentials, and sandbox exit request.
Brevo 300 emails / day (Free forever) Starter from ~$9/mo (5k emails) to ~$18/mo (20k emails) smtp-relay.brevo.com
Port 587 (TLS)
Free tier resets daily. Great for low-volume testing without entering a credit card.
Mailgun (Sinch) Trial (5,000 emails for 30 days) Foundation: $35/mo (50,000 emails); Scale: $90/mo smtp.mailgun.org (or smtp.eu.mailgun.org)
Port 587 (TLS) or 465 (SSL)
Robust analytics and deliverability. Supports EU data residency.
Twilio SendGrid 100 emails / day (Free forever) Essentials: ~$19.95/mo (50k emails); Pro: ~$89.95/mo smtp.sendgrid.net
Port 587 (TLS) (User: apikey)
Requires Two-Factor Authentication. Username must literally be apikey.
Postmark (ActiveCampaign) Free Developer trial: 100 emails/mo From $15/mo (10,000 emails), $55/mo (50,000 emails) smtp.postmarkapp.com
Port 587 (TLS) or 2525
Industry-leading transactional speed and strict spam filters. Separate broadcast streams required.
Resend 3,000 emails / month (100 / day free) Pro: $20/mo (50,000 emails/mo) smtp.resend.com
Port 465 (SSL) or 587 (TLS) (User: resend)
Modern developer experience, clean UI, quick domain verification via DNS.

标准 cPanel 邮箱适用于轻量日常联络,但严禁用于大批量营销群发。

Host: smtp.hostinger.com | Port 465 (SSL) / 587 (TLS)
Business Email Plans (Per Mailbox)
Free Business Email Rp0 / mo

1 GB storage, 1 forwarding rule, 1 alias, up to 100 mailboxes/domain. Standard webmail & antispam. Strict sending cap (~100-200/day).

Starter Business Email Rp7.900 / mo

5 GB storage, 5 forwarding rules, 5 aliases, expandable mailbox storage. No mailbox limit per domain.

Standard Business Email Rp10.900 / mo

20 GB storage, 20 forwarding rules, 10 aliases, AI Kodee mailbox assistant & smart replies.

Premium Business Email Rp19.900 / mo

50 GB storage, 50 forwarding rules, 30 aliases, full AI suite & priority deliverability.

Hostinger Reach (Email Marketing)
Starter Marketing Rp23.900 / mo

100 recipients, 200 emails / month. Suitable for basic transactional testing.

Grow Marketing Rp36.900 / mo

500 recipients, 500 emails / month, 10 AI credits, remove Reach branding, automations.

Pro Marketing Rp54.900 / mo

1,000 recipients, 7,000 emails / month, 20 AI credits, custom HTML code, send-time optimization.

Namecheap Jellyfish / cPanel

• cPanel Shared: Max ~500 emails/hour per cPanel domain.
• Private Email: Starter (~$1.24/mo per mailbox, 5GB). Pro (~$2.82/mo, 30GB).
• SMTP Host: mail.privateemail.com (Port 465 SSL or 587 TLS).

View Namecheap Email
Bluehost cPanel / M365

• Shared cPanel: Default cap ~500 emails/hour. Internal mail system may defer large sudden bursts.
• Professional Email: Integrated with Microsoft 365 or Google Workspace ($2.99–$9.99/mo).
• SMTP Host: box###.bluehost.com or mail.yourdomain.com (Port 465 SSL).

View Bluehost Email
SiteGround Site Tools

• Site Tools Mail: Included in hosting (StartUp, GrowBig, GoGeek).
• Rate Limits: ~400 emails/hour on StartUp; up to ~800/hour on GoGeek. Strictly intended for transactional mail.
• SMTP Host: mail.yourdomain.com (Port 465 SSL).

View SiteGround Email
DreamHost Custom Panel

• Paid Business Email: ~$1.99/mo per mailbox (25GB storage).
• Strict Outbound Policy: Maximum 100 recipients per hour. Mass marketing prohibited via shared SMTP.
• SMTP Host: smtp.dreamhost.com (Port 465 SSL or 587 TLS).

View DreamHost Email
HostGator cPanel

• cPanel Limit: Max 500 emails/hour per domain on shared plans.
• Workspace Option: Google Workspace addon ($6–$18/mo).
• SMTP Host: mail.yourdomain.com (Port 465 SSL or 587 TLS).

View HostGator Email
GoDaddy Microsoft 365

• M365 Reseller: Email Essentials from ~$1.99–$5.99/mo (10GB-50GB).
• SMTP Relay Note: Direct SMTP AUTH requires enabling Authenticated SMTP in the M365 Admin Portal.
• SMTP Host: smtp.office365.com (Port 587 TLS).

View GoDaddy Email

根据您的服务器网络与防火墙规则选择合适的端口与加密方式。

Port 587 (STARTTLS) STANDARD

The modern standard for email client-to-relay submission (RFC 6409). Starts in cleartext and immediately upgrades connection to TLS. Supported by almost all cloud relays.

Port 465 (SSL / SMTPS) ENCRYPTED

Implicit TLS/SSL wrapper connection (RFC 8314). Required by Hostinger, Namecheap cPanel, and selected enterprise relays. Highly reliable when hosting firewalls restrict 587.

Port 25 (Plain / MTA) BLOCKED

Server-to-server MTA routing. Almost universally blocked on cloud hosts (Hostinger, AWS, DigitalOcean, Hetzner, etc.) to combat spam. Do NOT use for outbound SMTP credentials.

6.1.1 托管 Amazon SES Relay 与自定义发件人域名

MANAGED SES

由 MarbleSend 通过 api.marblesend.com 托管的企业级云投递基础设施。消除共享主机上的 SMTP 端口封锁、IAM 凭证管理和 IP 信誉风险。提供双发件人模式(Friendly From 和 Easy DKIM)、免费初始积分、原子 ledger 审计以及按需动态扩展能力。

选项 2: MarbleSend SMTP via Amazon SES(托管中继)

由 MarbleSend 统一预配置和维护的企业级 Amazon SES 云分发服务。无需配置 AWS 账户、管理 IAM 密钥或执行 IP 预热。通过支付服务商按需充值积分,享受实时额度看板与自动化用量同步。

原子积分账本、幂等性与自动退款

通过 MarbleSend SES 发送的每封邮件均基于队列项 UUID 幂等键(cm_addon_ledger.uq_addon_ledger_key)原子预扣 1 点积分。若中继传输失败,系统将自动解除预扣并瞬间全额退还,无需人工介入。

实时 TLS 套接字诊断与详细通信日志
Easy DKIM

Test Connection 弹窗通过 MailerFactory 执行即时在线 SMTP 握手并发送测试邮件。实时打印原始套接字交互指令,秒级排查认证错误(535 Auth Failed)、中继拒绝(550 Relay Denied)及 TLS 握手超时。

按活动专属路由与平滑默认回退

每个群发活动、定期定时任务或自动回复器均可通过 cm_campaigns.smtp_profile_id 绑定独立 SMTP 配置。若未显式指定,发信引擎将无缝回退至系统标记的默认配置(is_default = 1)。

发件人域名认证(SPF、DKIM、DMARC)

无论选用 BYO SMTP 还是 MarbleSend SES,发信域名都必须配置合规的 SPF、DKIM 和 DMARC 解析记录。MarbleSend 内置的四支柱投递套件会主动巡检您的 DNS,力保邮件直达收件箱。

6.1.2 使用 SES Relay 的发送规则

Amazon SES 只适合保持名单干净的发件人,因此这些规则由 MarbleSend 中继本身强制执行,而不仅仅是本应用。它们无法关闭,适用于通过 SES Relay 发送的每一封邮件。

发件人身份

首次发送前,请在 Settings → SMTP 配置 → 发件人身份与可接受使用 中填写法定名称、邮寄地址、国家、电话号码,并接受可接受使用政策。保存之前发送会一直被阻止。您的名称和地址会显示在每封邮件的页脚;电话号码从不显示。

每封邮件都有退订

每个活动的正文都必须包含 {{unsubscribe_link}} 标签,否则发送会被拒绝。此外,中继还会添加 List-Unsubscribe 和一键退订标头,以及包含您的名称、地址、退订链接和“Sent with MarbleSend”的页脚。页脚无法移除。

基于许可的名单

使用 SES Relay 期间,注册页面和 API 始终使用 double opt-in,公开注册需要 Cloudflare Turnstile,CSV 导入需要勾选确认所有人都已同意。已退订或被抑制(suppressed)的人无法通过公开表单重新订阅。

退信与投诉

硬退信和垃圾邮件投诉会自动到达 MarbleSend,并将联系人设为 suppressed。中继也会拒绝向被抑制的地址发送,且不消耗额度。软退信会重试,只有在反复失败后才会抑制联系人。

限额与自动暂停

每个账户都有每日发送上限(默认 2,000 封)。如果退信或投诉率过高,发送会自动暂停,直到支持团队审核账户;许可证未激活时也会停止。Settings → SMTP 配置 中的横幅会说明原因,队列中的邮件会等待而不会丢失。

经过认证的发送

邮件使用 marblesend.com(验证后可使用您自己的域名)的 DKIM 签名。Return path 使用 mail.marblesend.com,因此 SPF 对齐且 DMARC 通过。回复将发送到您设置的 Reply-To 地址。

服务商 Easy DKIM 实操指南

Easy DKIM 3条 CNAME 解析配置目录(跨服务商)

分步指导如何在主流域名注册商与主机商面板中正确配置 AWS SES Easy DKIM 的 3 条 CNAME 解析记录,避开常见语法陷阱,确保邮件身份即时验证成功。

通用 DNS 架构与核心准则

Easy DKIM 通过 3 条 CNAME 记录将数字加密签名权委托给 Amazon SES。AWS 负责在后台无缝自动轮换底层 1024/2048 位 RSA 密钥,免去管理员未来手动维护的繁琐,因此这 3 条 CNAME 记录必须永久保留生效。

记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token1>._domainkey.yourdomain.com <token1>.dkim.amazonses.com 300 (or Auto)
CNAME <token2>._domainkey.yourdomain.com <token2>.dkim.amazonses.com 300 (or Auto)
CNAME <token3>._domainkey.yourdomain.com <token3>.dkim.amazonses.com 300 (or Auto)
RULE 1
准则 1:谨防「双重域名 (Double Domain)」陷阱

大多数域名注册商后台会自动为「主机记录」补全主域名后缀。如果您误填了 "token._domainkey.yourdomain.com",DNS 服务器将实际解析为 "token._domainkey.yourdomain.com.yourdomain.com",导致 DKIM 验证永远失败。请务必仅填写 "token._domainkey"。

RULE 2
准则 2:必须是 CNAME,绝非 TXT

与使用静态公钥 TXT 记录的传统手动 DKIM 不同,Amazon SES Easy DKIM 采用直接指向 token.dkim.amazonses.com 的 3 条 CNAME 记录。请切勿选择 TXT 记录类型。

RULE 3
准则 3:关闭代理(Cloudflare 灰云 DNS Only)

如果您使用 Cloudflare 或类似 CDN 代理,这 3 条 DKIM CNAME 必须设为「仅限 DNS(灰色云朵 / DNS Only)」。开启 CDN 代理会隐藏真实 CNAME 别名,破坏邮件服务器的加密校验。

终端验证命令 (CLI)
# Check resolution via dig (macOS / Linux):
dig CNAME <token1>._domainkey.yourdomain.com +short

# Check resolution via nslookup (Windows / PowerShell):
nslookup -type=CNAME <token1>._domainkey.yourdomain.com
Hostinger (hPanel DNS 区块)
hPanel DNS
Hostinger hPanel → 域名 (Domains) → 选择目标域名 → DNS / 域名服务器
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token>._domainkey (hPanel auto-appends .yourdomain.com) <token>.dkim.amazonses.com 300 (or 14400)
1

登录 Hostinger hPanel 控制台,进入「域名」模块。

2

点击目标域名,并在左侧导航中选择「DNS / 域名服务器」。

3

在「管理 DNS 记录」下方,将类型下拉菜单切换为 CNAME。

4

在「名称 (Name)」框中,仅输入 token._domainkey(hPanel 已自动在后方标出 .yourdomain.com)。

5

在「目标 (Target)」框中填入 token.dkim.amazonses.com,TTL 保持默认 300 或 14400。

6

点击「添加记录」。对 MarbleSend 提供的其余 2 条 Token 重复此操作。

Hostinger hPanel 会在输入框右侧以灰色字样显示主域名,切勿在名称栏重复输入主域名或添加多余点号。
DreamHost (Web 管理面板)
DreamHost Web Panel
DreamHost 面板 → 网站 (Websites) → 管理网站 → DNS 设置 (或 Domains → Manage Domains → DNS)
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token>._domainkey (DreamHost appends .yourdomain.com) <token>.dkim.amazonses.com Default
1

登录 DreamHost Web 面板,前往 Websites > Manage Websites。

2

找到您的域名,点击 DNS Settings(或进入 Domains > Manage Domains > DNS)。

3

向下滚动到「添加自定义 DNS 记录」区域,点击 Add Record。

4

在 Name 栏中填入 token._domainkey(面板会自动补全主域名后缀)。

5

Type 选择 CNAME,并在 Value 栏中粘贴 token.dkim.amazonses.com。

6

点击 Save / Add Record 保存。重复完成全部 3 条记录。

DreamHost 内部集群 DNS 节点传播通常需要 1–2 小时才能彻底同步。
Namecheap (高级 DNS 解析)
Advanced DNS
Namecheap 仪表盘 → Domain List → Manage → Advanced DNS 选项卡
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME Record <token>._domainkey (never paste root domain here) <token>.dkim.amazonses.com Automatic (or 1 min)
1

登录 Namecheap 控制台,在左侧打开 Domain List,点击域名旁的 Manage。

2

切换到页面上方的 Advanced DNS 选项卡。

3

在 Host Records 板块点击红色按钮「ADD NEW RECORD」。

4

在 Type 下拉列表中选择 CNAME Record。

5

在 Host 栏中严格填入 token._domainkey(切勿包含主域名)。

6

在 Target 中输入 token.dkim.amazonses.com,TTL 选择 Automatic(或 1 min),点击绿色勾号 ✓ 保存。重复录入 3 条。

若域名启用了第三方 Custom DNS,该选项卡将被禁用;请前往您实际生效的 DNS 服务商处添加。
Bluehost (账户管理器 / Zone Editor)
Bluehost DNS
Bluehost 控制台 → 域名 (Domains) → DNS (或 cPanel → Zone Editor)
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token>._domainkey (Bluehost handles suffix automatically) <token>.dkim.amazonses.com 4 Hours (or Default)
1

登录 Bluehost 账户管理器,点击左侧导航的 Domains 并选定您的域名。

2

切换到 DNS 选项卡(传统主机请直接进入 cPanel Zone Editor)。

3

定位到 CNAME (Alias) 区域,点击 Add Record。

4

在 Host Record 栏填入 token._domainkey。

5

在 Points To 栏粘贴 token.dkim.amazonses.com,TTL 选择 4 Hours 或 Default。

6

点击 Save 保存。依次录入其余 2 条 CNAME。

Bluehost 在底层会自动处理域名后缀,严禁将根域名粘贴进 Host Record 框。
SiteGround (Site Tools DNS 区域编辑器)
Site Tools DNS
SiteGround 客户区 → Websites → Site Tools → 域名 (Domain) → DNS Zone Editor
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token>._domainkey (Site Tools appends .yourdomain.com) <token>.dkim.amazonses.com 1 hour (3600)
1

登录 SiteGround 客户中心,进入 Websites 并打开对应域名的 Site Tools。

2

在左侧菜单展开 Domain,进入 DNS Zone Editor。

3

在「创建新记录」下方点击 CNAME 标签页。

4

在 Name 栏输入 token._domainkey(系统右侧已固定锁定 .yourdomain.com)。

5

在 Resolves To 栏输入 token.dkim.amazonses.com,TTL 保持默认 1 小时 (3600)。

6

点击 Create。重复添加剩余的 2 条记录。

SiteGround 解析生效极快(通常仅需数秒)。请检查该子域上没有残存的同名 TXT 冲突记录。
HostGator (cPanel Zone Editor)
cPanel Zone Editor
HostGator 门户 → cPanel → 域名 (Domains) → Zone Editor
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token>._domainkey (cPanel automatically appends dot) <token>.dkim.amazonses.com 14400 (or 3600)
1

登录 HostGator 客户中心并启动 cPanel。

2

在 Domains 区域点击 Zone Editor。

3

找到目标域名,点击「+ CNAME Record」(或 Manage > Add Record)。

4

在 Name 栏填入 token._domainkey(cPanel 会自动在末尾追加域名和点号)。

5

在 CNAME / Record 栏填入 token.dkim.amazonses.com。

6

点击 Add a CNAME Record。重复添加全部 3 条。

在 cPanel Zone Editor 列表中核对记录全称,确认呈现为 token._domainkey.yourdomain.com. 且未产生重复叠加。
GoDaddy (域名资产 DNS 管理)
GoDaddy DNS
GoDaddy 账户 → 我的所有产品 → 域名 → DNS (或 管理 DNS)
记录类型 主机记录 / 名称 (Host/Name) 记录值 / 指向 (Value/Target) TTL 生存时间
CNAME <token>._domainkey (never include root domain in GoDaddy) <token>.dkim.amazonses.com 1/2 Hour (or Default)
1

登录 GoDaddy 账户,进入「我的所有产品」页面。

2

在域名列表中找到目标域名,点击 DNS(或三点图标 > 管理 DNS)。

3

在 DNS 记录区域点击「添加新记录 (Add New Record)」。

4

记录类型下拉菜单选择 CNAME。

5

名称 (Name) 栏中严格仅输入 token._domainkey(绝不可写 .yourdomain.com!)。

6

值 (Value) 填入 token.dkim.amazonses.com,TTL 选 1/2 小时(或默认),保存即可。重复完成 3 条记录。

GoDaddy 会强制自动追加主域名。如果手动填入完整域名将直接触发解析语法报错或生成无效的双重域名记录。
DNS 验证与全球生效传播

保存好 3 条 CNAME 记录后,DNS 全球生效通常需要 5–30 分钟(视 TTL 决定,最长 24–48 小时)。回到 MarbleSend 的「设置 > SMTP」,打开自定义发件域名卡片并点击「验证 DNS」。经由 Amazon SES 校验通过后,徽章将即刻转为「已验证」绿色状态。

6.2 后台 Worker 心跳、1 分钟 Cron 与 Concurrency Guard

MarbleSend 在后台发送邮件。cron 任务是主机面板里的一个计时器,每分钟唤醒 MarbleSend 一次,使它能够运行计划任务和 autoresponder、重试失败的发送、收集 bounce 并让较长的 Campaign 持续进行。您发送的 Campaign 会立即开始,但之后需要发生的一切都依赖这个计时器。如果 Settings → 系统状态 显示 未检测到 Cron,说明计时器不存在、没有每分钟运行,或指向了错误的位置。下面三个步骤可以解决这个问题。

第 1 步:复制您的 cron 行

打开 Settings → 系统状态,找到 Cron Job 定时任务命令,然后点击 复制命令。这一行已经包含正确的 folder,并且在服务器告知我们时包含正确的 PHP。请原样使用;本页下方的示例只展示一行的形式。如果 Settings 提示无法检测到 PHP,请向主机商询问 PHP 命令行路径,并替换行首的 php 一词。

第 2 步:在主机面板中添加

请在下方选择您的主机商。菜单名称偶尔会变化,请找最接近的一项。无论哪种面板,任务都必须每分钟(* * * * *)运行,其命令就是第 1 步中的那一行。Plesk、DirectAdmin 和其他面板称之为 Scheduled Tasks 或 Cron Jobs。

Hostinger (hPanel)
  1. 打开您网站的 hPanel → Websites → Dashboard,然后点击侧边栏中的 Cron Jobs。
  2. 将 Type 设为 Custom。(PHP 类型只接受 .php file 的路径;您的行还包含 PHP 命令。)
  3. 将第 1 步的那一行粘贴到 Command to run。
  4. 将计划设为每分钟,或输入 * * * * *。
  5. 点击 Save。任务会出现在 List of Cron Jobs 中,您也可以在那里查看它最近一次的输出。

Hostinger 以 UTC 运行 cron 任务。Single 套餐允许 2 个 cron 任务;Premium 及更高套餐不限数量。

Namecheap

从您的 Namecheap 主机账户打开 cPanel,然后按以下步骤操作。

  1. 打开 cPanel,在 Advanced 部分点击 Cron Jobs。
  2. 在 Add New Cron Job 下,于 Common Settings 中选择 Once Per Minute (* * * * *)。
  3. 将第 1 步的那一行粘贴到 Command。
  4. 点击 Add New Cron Job。任务从现在起每分钟运行。

Namecheap 不允许在共享服务器上运行间隔短于 5 分钟的 cron 任务,也不允许超过 5 个 cron 任务。如果您需要每分钟一次,请使用下方的 Web-Cron。

Bluehost
  1. 登录 Bluehost Portal,点击 Websites,然后点击您网站的 Manage Site。
  2. 打开 Advanced 选项卡,找到 Cron Jobs,点击 Manage,然后点击 Add Cron。
  3. 在 Common Settings 中选择频率(或填写 Minute、Hour、Day、Month 和 Weekday)。
  4. 将第 1 步的那一行粘贴到 Command,然后点击 Add。

Bluehost 自己的文档称,共享主机只会每 15 分钟或更长时间运行一次 cron 任务(有一页写的是 5 分钟)。如果您需要每分钟一次,请使用下方的 Web-Cron。

HostGator

在 Customer Portal 中打开 Websites → Manage Site → Advanced,然后在 Cron Jobs 下点击 Manage 和 Add Cron。表单的字段与 cPanel 相同,因此下面的步骤同样适用。或者打开 cPanel → Advanced → Cron Jobs。

  1. 打开 cPanel,在 Advanced 部分点击 Cron Jobs。
  2. 在 Add New Cron Job 下,于 Common Settings 中选择 Once Per Minute (* * * * *)。
  3. 将第 1 步的那一行粘贴到 Command。
  4. 点击 Add New Cron Job。任务从现在起每分钟运行。

HostGator 的帮助页面没有说明共享主机允许的最短间隔。如果每分钟一次被拒绝,请使用下方的 Web-Cron。

GoDaddy

在您的 GoDaddy 产品页面上,点击 Linux Hosting 旁边的 Manage,然后点击 cPanel Admin,再按以下步骤操作。

  1. 打开 cPanel,在 Advanced 部分点击 Cron Jobs。
  2. 在 Add New Cron Job 下,于 Common Settings 中选择 Once Per Minute (* * * * *)。
  3. 将第 1 步的那一行粘贴到 Command。
  4. 点击 Add New Cron Job。任务从现在起每分钟运行。

GoDaddy 的帮助页面没有说明允许的最短间隔。如果每分钟一次被拒绝,请使用下方的 Web-Cron。

DreamHost
  1. 打开 DreamHost 面板,进入 Cron Jobs,点击 Add New Cron Job。
  2. 选择一个用户(已有的 SFTP 或 shell 用户),为任务设置标题,并可选填写用于接收输出的电子邮件地址。
  3. 将第 1 步的那一行粘贴到 Command。DreamHost 把 PHP 放在类似 /usr/local/php83/bin/php 的路径中(请使用您的 PHP 版本)。
  4. 设置时间并开启 locking,让两次运行永不重叠,然后保存。

在自定义时间下,面板每小时最多只能选择 12 个不同的分钟,因此您能建立的最短规律计划是每 5 分钟一次。时间为太平洋时间。如果您需要每分钟一次,请使用下方的 Web-Cron。

SiteGround
  1. 打开 Site Tools → Devs → Cron Jobs。
  2. 从列表中选择间隔(或设置分钟、小时、日、月和星期)。
  3. 将第 1 步的那一行粘贴到 Command。用于接收输出的电子邮件地址是可选的。
  4. 点击 Create。

SiteGround 的文档展示了 Twice Per Hour 之类的预设,没有说明最短间隔。如果您的套餐没有每分钟的选项,请使用下方的 Web-Cron。

无法使用 cron,或主机商加以限制?请使用 Web-Cron
  1. 打开 Settings → 系统状态,复制 Web-Cron URL。请保密:其中包含您的秘密令牌。
  2. 在 cron-job.org 之类的 cron 服务上创建一个免费账户。
  3. 创建一个任务,粘贴该 URL,并设置为每分钟运行。保存并启用。
  4. Web-Cron 与主机商的 cron 任务二选一,不要同时使用:一个就够了。
第 3 步:检查是否正常运行

等待一两分钟,然后重新加载 Settings → 系统状态。徽章应显示 运行正常,最后心跳 应显示最近一分钟内的时间。同一页面上的 站点健康 应将 worker 显示为 通过。如果您的主机商只允许每 5 或 15 分钟运行一次任务,徽章可能会在 运行正常 和 未检测到 Cron 之间切换,因为它期望最近 5 分钟内有一次运行;worker 每次运行时,邮件仍会发出。

仍然显示 未检测到 Cron?
  • PHP 命令不正确。请向主机商询问 PHP 命令行路径(例如 Hostinger 上的 /opt/alt/php83/usr/bin/php,或许多 cPanel 主机上的 /usr/local/bin/php),并替换行首的 php。
  • 只粘贴了该行的一部分。请粘贴整行,包括末尾的 >/dev/null 2>&1。
  • folder 不对。worker.php 位于包含 public 的 folder 中,而不是在 public 里面。
  • 要查看错误,请在不带 >/dev/null 2>&1 的情况下运行一次该任务并阅读其输出。正常工作的 worker 会输出类似 worker.php: processed=0 的一行。
  • 该任务属于同一账户下的另一个网站。请检查命令中的 folder。
  • 保存后请等待最多 5 分钟,再重新检查。

面向技术用户

邮件编译、受众解析、分发投递和 webhook 触发均通过 1 分钟后台 worker 异步运行。MarbleSend 采用双入口架构(原生 CLI worker.php 或 HTTP cron.php),受非阻塞 file 锁保护以彻底防止进程冲突。

原生 CLI Crontab(选项 A)
* * * * * php /home/USER/your-folder/worker.php >/dev/null 2>&1

直接从操作系统 shell 运行(* * * * * php /path/to/worker.php >/dev/null 2>&1)。彻底避免 HTTP 超时和 Web 负载均衡网关限制。

HTTP Web-Cron 回退(选项 B)
GET https://your-domain.com/cron.php?token=SECURE_TOKEN

对于没有 shell 访问权限的主机环境,通过外部监控调用 GET /cron.php?token=SECURE_TOKEN 可安全触发相同的队列处理。

非阻塞 flock Concurrency Guard

Worker 在启动时使用 flock(LOCK_EX | LOCK_NB) 锁定 storage/worker.lock。如果先前的任务仍在处理,后续调用将立即安全退出而不会产生竞态条件。

原子队列批次认领

通过带索引的状态查询以原子方式认领每批 50 个队列项。发送失败的邮件会经历指数退避重试,直至达到最大重试次数。

6.3 23 种原生语言、RTL 阿拉伯语与管理员安全架构

MarbleSend 专为全球可访问的独立自托管平台而设计。包含 23 种由人工校对的原生语言字典、针对阿拉伯语的自动从右至左(RTL)布局镜像、持久的主题定制以及严密的主机安全机制。

无外部依赖的 23 种原生语言

app/lang/*.php 中的语言文件均为纯 PHP 数组,能在亚毫秒级加载到内存中,无需 gettext 服务器二进制文件或外部翻译 API。

双向 RTL 布局镜像

选择阿拉伯语(ar)会自动将 dir='rtl' 注入 HTML 文档,并在整个界面中镜像导航侧边栏、表格列、抽屉和图标。

持久化三态主题引擎

在深色调色板、浅色调色板和系统偏好之间无缝切换。选择保存在 cookie(marblesend_theme)中,防止页面加载时的布局闪烁。

强化的单管理员安全保障

cm_settings.admin_user 中的管理员凭证经过 bcrypt(成本因子 12)哈希加密。登录时通过自动重新生成会话 ID 防止会话固定攻击。

6.3.1 双重身份验证(TOTP)与二维码设置

双重身份验证为管理员账户增加第二道锁:输入密码后,MarbleSend 会要求输入一个每 30 秒变化一次、只有您的手机才能生成的 6 位验证码。该功能为可选项,大约一分钟即可启用,并适用于任何标准的身份验证器应用,例如 Google Authenticator、Microsoft Authenticator、1Password、Bitwarden、Authy 或 Aegis。您可以在 Settings → 语言与账户 → 两步验证(TOTP) 中找到它。

工作原理

MarbleSend 使用开放的 TOTP 标准(RFC 6238:HMAC-SHA1、6 位数字、30 秒步长)。启用时会生成一个随机密钥,并仅与您的应用共享一次。此后登录需要先输入密码,再输入当前验证码。已使用过的验证码无法重复使用,第二步将在 5 分钟后过期。

逐步启用

1)打开 Settings → 语言与账户,点击“启用”。2)在身份验证器应用中选择“扫描二维码”,扫描屏幕上显示的方块图案。3)输入应用当前显示的 6 位验证码,然后点击“确认并启用”。4)保存只显示一次的八个恢复码:复制到密码管理器或打印出来。

二维码只停留在您的服务器上

二维码图像由您自己的安装程序以小型矢量图形绘制;密钥绝不会发送到在线二维码生成器或任何第三方。如果无法扫描(例如应用就在同一部手机上),请使用二维码下方显示的设置密钥或 otpauth 链接。与其他所有凭据一样,密钥使用您的 ENCRYPTION_KEY 加密(AES-256-GCM)后存储。

使用验证码登录

密码正确后,系统会要求输入 6 位验证码。错误的验证码会按账户限速,因此无法靠猜测破解。如果您输入正确的验证码仍被拒绝,请检查手机的日期和时间是否设为自动;时钟不准会生成错误的验证码。

恢复码

启用 2FA 时会生成八个一次性验证码。每个恢复码可在验证码输入框中使用一次,以代替 6 位验证码。它们仅以哈希形式存储,因此无法再次显示;使用“新的恢复码”(需要当前验证码)可替换整组恢复码,旧恢复码随即失效。

手机丢失且没有恢复码

忘记密码时通过邮件发送的链接不会绕过 2FA(这是有意设计),因此在这里没有帮助。请在服务器上运行“php tools/reset-admin.php”(SSH 或您的主机终端):它会重置管理员密码、清除锁定、结束所有会话并关闭 2FA,之后您可以用新设备重新启用。若要正常关闭,请在同一张卡片中使用“停用”(密码加当前验证码或恢复码)。

6.3.2 注册保护(Cloudflare Turnstile):获取您的免费密钥

Turnstile 是 Cloudflare 提供的免费、注重隐私的 CAPTCHA 替代方案。启用后,您的公开注册页面(/s/your-page 表单和 /subscribe)会在接受订阅之前验证访客是真人,从而防止机器人淹没您的名单和确认邮件。它在内置 honeypot 以及按 IP 和按地址的限制之上工作,并且是可选的,但在您通过 SES Relay 发送期间除外(见最后一条说明)。您需要来自您自己免费 Cloudflare 账户的两个密钥:Site key(公开)和 Secret key(私有);您的域名无需使用 Cloudflare 做 DNS。

1 创建或登录 Cloudflare 账户

前往 dash.cloudflare.com 注册(免费)或登录。使用 Turnstile 无需将您的网站添加到 Cloudflare,也无需更改 DNS。

2 打开 Turnstile 并添加小组件

在控制台菜单中打开“Turnstile”(或搜索它),然后点击“Add widget”(旧版控制台显示为“Add site”)。菜单名称偶尔会变化;请在 Application security 下查找 Turnstile。

3 为小组件命名并列出主机名

随意命名,例如“MarbleSend signup”。在 Hostname 下添加运行 MarbleSend 的域名,不带 https:// 和路径,例如 app.yourdomain.com。如果您的注册页面显示在其他域名上,也请添加。仅在自己的电脑上测试时才添加 localhost。

4 选择小组件模式

选择 Managed(推荐):大多数访问者无需任何验证题即可通过,只有访问看起来可疑时 Cloudflare 才会要求快速点击一次。Non-interactive 显示简短的进度条,无需点击;Invisible 则完全不显示任何内容。保持 pre-clearance 关闭,然后点击 Create。

5 复制两个密钥

Cloudflare 会显示 Site key(公开)和 Secret key(私密)。请把两者都复制下来。密钥仅由您的服务器用于向 Cloudflare 确认每位访问者,因此切勿粘贴到任何公开的地方。您之后可以在小组件设置中查看或轮换它。

6 粘贴到 MarbleSend

打开 Settings → 语言与账户 → 注册保护(Cloudflare Turnstile),粘贴 Site key 和 Secret key,然后点击“保存”。徽章将变为“保护已开启”。以后若要关闭,请清空两个字段并保存。已保存的密钥会加密存储且不再显示;将该字段留空即可保留它。

7 测试

在浏览器的隐私窗口中打开您的某个公开注册页面:Turnstile 小组件会出现在按钮上方。使用测试邮箱订阅,您应该会收到确认邮件。未通过检查的提交会被拒绝。

Cloudflare 无法访问时

如果您的服务器无法访问 Cloudflare 的验证服务(故障或出站连接被阻止),MarbleSend 通常会放行注册并记录该事件,而不是把所有访客拒之门外;honeypot 以及按 IP 和按地址的限制仍然生效。在您通过 SES Relay 发送期间则相反,会以关闭方式失败:注册将被拒绝,直到 Cloudflare 再次可访问。

开发用测试密钥

Cloudflare 公布了用于测试的虚拟密钥:Site key 1x00000000000000000000AA 搭配 Secret key 1x0000000000000000000000000000000AA 始终通过。它们绝不能保护真实网站,因此上线前请替换为您自己的密钥。

故障排除

小组件不显示:请检查页面的主机名是否已列在 Turnstile 小组件中,以及是否有浏览器扩展拦截了 challenges.cloudflare.com。“Invalid site key”:Site key 复制时带了空格,或属于另一个小组件。真实访问者被拒绝:请重新粘贴 Secret key;它必须与 Site key 属于同一个小组件。

使用 SES Relay 期间为必需

如果您通过 Managed Amazon SES Relay 发送,公开注册表单必须使用 Turnstile。在保存两个密钥之前,注册页面会显示“注册暂时不可用”,Settings → 语言与账户 会显示一条通知,并带有把您带到正确卡片的按钮。在此模式下,即使注册页面或 API 调用要求 single opt-in,每位新订阅者也必须通过电子邮件确认(double opt-in)。

6.4 限定范围的 REST API 密钥与开发者程序化访问

REST API 允许外部网站、落地页、移动应用程序以及官方 WordPress 插件 MarbleSend Forms 安全地与您的联系人数据库和发送引擎交互。API 密钥使用加密前缀、单向 SHA-256 存储和细粒度权限范围。

令牌生成与单次展示

密钥使用 ms_ 前缀并通过 random_bytes(24) 附加 32 个加密随机字节生成。原始机密令牌仅在创建时显示一次。

单向 SHA-256 哈希存储

仅在 cm_api_keys.key_hash 中保存 SHA-256 哈希值(hash('sha256', $rawKey))。即使数据库泄露,也无法解密出有效令牌。

细粒度权限范围

将密钥限制为特定功能:contacts:read、contacts:write、campaigns:read、campaigns:write、campaigns:send、schedules:read 和 schedules:write。

Bearer 认证与审计日志

传入请求通过 Authorization: Bearer ms_... 标头进行身份验证,并使用 hash_equals() 比对。每次调用均会记录精确的 last_used_at 时间戳。

6.5 出站事件 Webhook 与 HMAC-SHA256 加密分发

联系人事件(subscribed、confirmed、unsubscribed、suppressed)现在除 tags 外还带有由 {id, name} 组成的 groups 数组。

Webhook 向外部端点提供实时 HTTP 事件流,使 CRM、Slack 通知或自定义自动化程序能够对订阅者加入、Campaigns 发送、取消订阅和硬退信立即做出响应。

生命周期事件订阅

订阅关键事件:contact.created、contact.unsubscribed、campaign.sent、campaign.bounced 和 link.clicked,每个 webhook 均可单独切换开启。

HMAC-SHA256 签名标头

每个 webhook POST 请求都包含使用 hash_hmac('sha256', $payload, $secret) 生成的 X-MarbleSend-Signature: sha256=... 标头,以便接收服务器验证真实性。

断路器与重试机制

失败的 webhook 投递(HTTP 5xx 或超时)会触发指数退避重试。持续出错的端点将自动暂停,以避免对服务器造成负担。

投递审计历史与测试 Ping

Test Webhook 按钮可立即发送测试载荷。投递历史抽屉会清晰列出 HTTP 状态码、以毫秒为单位的执行延迟以及错误响应详情。

6.6 四大支柱送达率套件(SPF、DKIM、DMARC、BIMI)

送达率决定了您的邮件是进入收件箱还是沦落到垃圾箱。MarbleSend 内置 DNS 检查引擎,可直接向权威域名服务器发送四个连续的非阻塞查询,无需外部商业 API。

1. SPF(发送方策略框架)

检查根 TXT 记录的 v=spf1 语法。验证授权的 SMTP 主机机制,对 DNS 查询次数超限(>10 次查询会导致硬失败)发出警告,并分析限定符。

2. DKIM(域名密钥识别邮件)

查询 selector._domainkey.domain.com 以验证公共 RSA 或 Ed25519 密钥。确保出站邮件标头能够对照发件人域名进行加密验证。

3. DMARC 策略与对齐检查

检查 _dmarc.domain.com 的策略标签(p=none、p=quarantine 或 p=reject)。在 2026 年,Gmail 和 Yahoo 要求大批量发件人必须具备带 rua 报告的有效 DMARC 记录。

4. BIMI 品牌头像与 VMC 证书

查询 default._bimi.domain.com 中的 SVG Tiny P.S. 品牌徽标和验证标记证书(VMC),以直接在各大收件箱中显示通过验证的品牌官方头像。

6.7 双模式 AI 引擎:BYOK 服务商与 MarbleSend AI 额度

MarbleSend 为文案撰写、主题行生成和垃圾邮件评分审计提供了灵活的双模式 AI 引擎:(1) 自带密钥模式(BYOK),零加价直连主流大语言模型服务商;(2) MarbleSend AI 额度模式,无需申请开发者账户或管理 API 密钥,即开即用由官方精选的顶级优质模型。

BYOK 模式 1: BYOK(自带 API 密钥)

直接连接至 OpenAI、Anthropic Claude、Google Gemini、DeepSeek、月之暗面 (Moonshot)、OpenRouter 或本地私有部署的 Ollama。API 密钥在数据库中通过 AES-256-GCM 硬件级算法加密存储。请求直连官方节点,无中间商佣金或费率加成。

METERED 模式 2: MarbleSend AI 额度(官方精选模型)

直接通过 MarbleSend 统一管理的预付费 AI 积分。精选针对邮件营销转化率与送达率深度评测的高效模型。服务端统一动态调度最优模型与版本升级,单次生成仅原子扣减 1 点积分。

DYNAMIC Dynamic Edge Pricing & Instant Checkout

Official add-on pricing is retrieved dynamically from admin.marblesend.com. Purchase top-up credit packs via global and local payment gateways with instant real-time balance activation.

PRIVACY AES-256-GCM Key Vault & Strict Data Privacy

All BYOK credentials are encrypted at rest with hardware-accelerated AES-256-GCM using your installation's unique APP_KEY. No prompt contents, contact lists, or recipient emails are ever stored or logged by the license server.

6.7.1 默认模型选择与执行路由

定义 MarbleSend 在整个应用中如何路由 AI 文案撰写、主题建议和送达率审查。您可以在官方精选中继与自定义 BYOK 提供商之间自由切换。

MarbleSend AI (托管中继)

零配置即可使用专为邮件营销转化评测优选的精选模型。无需第三方开发者账号或管理 API 密钥。

BYOK (自带密钥)

直接在服务器与供应商之间通信,无中间加价。选择任意已配置的提供商和具体模型作为默认生成引擎。

统一生成流水线

模板工作室、AI 主题评分检查器和 AI 创作助手均自动依当前默认配置运行,积分不足时提供平滑提示。

系统状态持久化

当前选择持久化保存在 cm_settings.ai_provider_default 中,确保所有管理员会话和后台任务同步执行。

6.7.2 MarbleSend AI 积分与托管中继中心

MarbleSend AI 积分为邮件文案提供即用即付的无缝基础设施,免去处理第三方账单、配额或调用频率限制的麻烦。

免费新手积分配额

每个已激活的许可证均可从授权服务器动态获取免费新手 AI 积分,方便立即体验 AI 创作助手功能。

原子账本与幂等保障

每次生成请求通过 cm_addon_ledger 严格扣除 1 点积分。唯一的交易 UUID 杜绝网络重试中的重复扣费。

边缘动态价格目录与充值

积分包(如 ai_100)直接从官方边缘目录动态获取。付款由我们的支付服务商安全处理。

实时余额与一键同步

结账完成后 Webhook 事件即时更新账户余额。提供一键手动刷新按钮随时与服务器核对最新余额。

6.7.3 已配置提供商与 BYOK 基础架构

接入并统一编排多个外部大语言模型服务,具备加密密钥存储、双 API 协议支持和即时连通性诊断。

多供应商统一注册

同时保持与 OpenAI、Anthropic Claude、Google Gemini、DeepSeek、Moonshot、OpenRouter 或私有 Ollama 实例的连接。

双协议与自定义 Base URL

支持标准 OpenAI 兼容端点 (/chat/completions) 和 Anthropic 格式 (/v1/messages),并支持自定义代理 Base URL。

AES-256-GCM 硬件加密保管库

所有 BYOK API 密钥在静态存储时均通过硬件加速 AES-256-GCM 加密,绝不会在 HTML 响应或系统日志中泄露。

实时预检诊断

测试连接按钮会发送轻量探测请求以校验凭据并反馈往返延迟 (ms),确保模型在投入生产前正常运作。

主流提供商 API Key 获取全指南

MarbleSend 通过 BYOK 模式直接从您的服务器与 AI 提供商通信,无第三方中转代理。以下是主流提供商的控制台入口、获取步骤及模型文档:

OpenAI GPT-4o / o-series
Format: openai
Base URL: https://api.openai.com/v1
Steps: 登录 platform.openai.com → 打开控制台 → 在左侧导航栏点击 "API keys" → 点击 "+ Create new secret key" → 命名为 "MarbleSend" → 立即复制生成的密钥(以 sk-... 开头)。在 platform.openai.com/docs/models 查看最新模型 ID。
Anthropic Claude Claude 3.5 / 3.7 Sonnet
Format: anthropic
Base URL: https://api.anthropic.com/v1
Steps: 登录 console.anthropic.com → 进入 Settings → "API Keys" → 点击 "Create Key" → 命名为 "MarbleSend" → 复制密钥(以 sk-ant-... 开头)。在 docs.anthropic.com/en/docs/about-claude/models 查看最新 Claude 模型 ID。
Google Gemini Gemini 2.0 / 2.5 Flash
Format: gemini
Base URL: https://generativelanguage.googleapis.com/v1beta
Steps: 使用 Google 账号登录 aistudio.google.com → 点击导航栏中的 "Get API key" → 点击 "Create API key" → 复制密钥(以 AIzaSy... 开头)。在 ai.google.dev/gemini-api/docs/models/gemini 查看最新 Gemini 模型列表。
DeepSeek DeepSeek-V3 / R1
Format: openai
Base URL: https://api.deepseek.com
Steps: 登录 platform.deepseek.com → 点击左侧菜单中的 "API keys" → 点击 "Create API key" → 命名为 "MarbleSend" → 复制密钥(以 sk-... 开头)。在 api-docs.deepseek.com 查看最新模型列表(如 deepseek-chat 与 deepseek-reasoner)。
Kimi (Moonshot AI) Kimi k1.5 / Moonshot v1
Format: openai
Base URL: https://api.moonshot.cn/v1
Steps: 登录 platform.moonshot.cn → 进入控制台 → 选择 "API Key 管理" → 点击 "新建" → 复制生成的 token。访问 platform.moonshot.cn/docs 查看最新模型 ID(如 kimi-k3 与 moonshot-v1-128k)。
OpenRouter Aggregator (200+ Models)
Format: openai
Base URL: https://openrouter.ai/api/v1
Steps: 登录 openrouter.ai → 进入 Account → "Keys" → 点击 "Create Key" → 可选设置额度限制 → 复制密钥(以 sk-or-v1-... 开头)。访问 openrouter.ai/models 可一站式调用 100+ 主流与开源模型。
Ollama & Local / Groq Local LLM / Ultra-Fast LPU
Format: openai
Base URL: http://localhost:11434/v1 / https://api.groq.com/openai/v1
Steps:
本地自托管与备选提供商(Ollama、Groq、Mistral、GLM)

如需免费本地部署模型,可安装 Ollama (ollama.com),运行所选模型(例如 ollama run llama3.1),Base URL 填入 http://localhost:11434/v1,格式选 OpenAI 并勾选 "No Auth"。如需超高速云端推理,可注册 console.groq.com 获取免费 Groq 密钥。

在 Settings ➔ AI Providers 中的配置流程 (/settings)

获取 API Key 与目标模型 ID 后,只需通过以下几步即可在 MarbleSend 完成配置:

1 1. 进入 Settings ➔ AI Providers 标签页

在主侧边栏点击 Settings,然后切换至 "AI Providers" 标签页(或直接访问 /settings)。

2 2. 使用 Quick Add 预设或点击 "+ Add Provider"

点击 Quick Add 中的预设药丸按钮(OpenAI、DeepSeek、Gemini、Anthropic 等)一键自动填充,或点击 "+ Add Provider" 手动配置。

3 3. 确认协议格式与 Base URL

选择协议格式:"OpenAI format"(适用 OpenAI、DeepSeek、Gemini、Groq、Ollama)或 "Anthropic format"(适用 Claude),并确认 Base URL 无误。

4 4. 安全粘贴 API Key

将生成的 Secret Key 粘贴至输入框。MarbleSend 使用 Crypto.php 的 AES-256-GCM 强加密存储,数据库绝不明文暴露密钥。

5 5. 指定 Model ID 并点击 Test Connection

填入要使用的 Model ID 与 context window 上限,然后点击 "Test Connection" 执行在线握手与凭证验证,确认无误后保存。

6 6. 设定全局默认激活模型

在页面上方的 "Default AI Model" 卡片中,选择刚配置的 Provider 与 Model,点击 "Save Default" 即可全局生效!

6.8 加密 Ed25519 许可证授权令牌引擎

MarbleSend 通过 PHP 的原生 libsodium 扩展使用非对称 Ed25519 加密算法来验证产品真实性。在初次激活时颁发签名的 License Grant Token,并在本地离线验证,无需保持永久联网。

Ed25519 签名验证

使用 sodium_crypto_sign_verify_detached() 验证数字签名。对数据库记录的任何手动篡改都会立即破坏数学签名并触发校验告警。

域名与层级绑定

已签名的令牌包含受许可的域名主机名、许可层级(Regular 或 Extended)以及有效权限。域名迁移可直接在 Settings 中发起。

7 天离线宽限期

临时的网络故障或许可证服务器维护绝不会中断正在进行中的邮件投递或 cron 任务。MarbleSend 在实施任何限制前提供长达 7 天的宽限期。

软锁定(Soft-Lock)策略

如果许可证到期,MarbleSend 将执行软锁定:订阅者数据、Campaigns、分析报告和导出工具依然 100% 可用,仅暂停新的广播投递任务。

自动检查更新

worker 每天向许可证服务器询问一次是否有更新的版本。仅发送您的购买代码和已安装的版本,与手动检查相同。在此标签页中通过“版本更新”可将其关闭:关闭后不再检查,也不显示更新横幅。开发环境安装(APP_ENV=local)从不发起此调用。绝不会发送任何关于您的联系人或 Campaigns 的信息。

更新日志与更新邮件

“更新日志”(侧边栏,位于文档上方)按版本列出每个发布及其升级指南。出现更新的版本时,仪表板会显示横幅(安全更新会在每个页面显示红色横幅且无法关闭),“更新日志”旁会出现一个圆点,若已启用,还会通过默认 SMTP 配置文件向管理员地址为每个版本发送一封邮件。发布说明使用英文撰写。

支持减负手册

常见问题与诊断排查

针对最常见 shared-hosting 问题的即时解决方案。

7.1 Dashboard 与系统运维诊断

7.1.1 为什么 Dashboard 显示 "Worker Not Detected" 或处于非活动状态?

根本原因:

操作系统的 crontab 定时任务未触发、PHP CLI 路径配置错误,或者残留的 lock file 阻止了任务执行。

诊断与底层机制:

Worker 在每个周期内都会将 UTC 时间戳更新写入 cm_settings.worker_last_run。若间隔超过 180 秒,仪表盘即会标记为非活动。

实战排查方案与修复:

前往 Settings → System。复制准确的 crontab 命令。若 CLI 被主机禁用,请在 cron-job.org 中将 Web-Cron URL 配置为每 1 分钟请求一次。检查 storage/worker.lock。

7.1.2 为什么 Dashboard 的 KPI 打开率/点击率与外部 SMTP 服务商日志存在差异?

根本原因:

Apple Mail Privacy Protection (MPP) 预取、代理缓存、收件人客户端阻止图片加载,或者广告拦截插件过滤了 UTM 参数。

诊断与底层机制:

MarbleSend 会在发出的邮件中嵌入 1x1 透明跟踪 GIF 以记录 cm_email_logs.opened_at。收件人屏蔽图片时无法记录;而 Apple MPP 会在抵达苹果服务器时立即预取图片。

实战排查方案与修复:

请以独立点击率(CTR)作为核心互动评估指标。MarbleSend 会将模版内所有链接重定向至 public/click.php,确保点击记录精准防篡改。

7.2 Campaign 发送与 Preflight 预检诊断

7.2.1 为什么我的 campaign 广播在发送途中暂停或中断了?

根本原因:

在大规模广播发送期间,触及了 shared hosting 主机 PHP CLI 或 Web 服务器的执行时长上限(max_execution_time 30s/60s)。

诊断与底层机制:

MarbleSend 以每批 50 人的原子批次处理队列。当接近超时阈值时,worker 会平稳退出并将进度提交至 cm_email_queue,防止内存耗尽。

实战排查方案与修复:

无需人工干预!下一分钟的 cron 周期会自动从 cm_email_queue 中领取下一批 pending 记录继续发送,绝不会发出重复邮件。

7.2.2 为什么自动化的 6 点 Preflight 检查阻止了我的 campaign 发布?

根本原因:

缺少强制的 {{unsubscribe_link}} 占位符、主题行为空或违规、未选中有效联系人,或者 syntax 变量标签未闭合。

诊断与底层机制:

Preflight 引擎在允许将状态流转至 queued 或 sending 之前,会对 6 项核心合规性与 deliverability 指标展开严格评估。

实战排查方案与修复:

检查发布窗口内的红色警示徽章。务必包含 {{unsubscribe_link}}(RFC 8058 与 CAN-SPAM 法规要求),并确保选定标签能匹配到活跃 contacts。

7.2.3 "Resend to Non-openers" 何时可用,它是如何防止打扰订阅者的?

根本原因:

在广播正在发送过程中,或安全冷却时间尚未到达之前,Campaign 报告中的重发按钮会处于禁用状态。

诊断与底层机制:

MarbleSend 要求 campaign 处于 completed 状态,并建议至少等待 24 至 48 小时,以便让各时区的订阅者都有充裕时间查阅邮件。

实战排查方案与修复:

发送完成后点击 "Resend to Non-openers"。系统将自动派生一个新子任务,仅定向投递至 opened_at IS NULL 的 contacts,方便您测试替代主题行。

7.3 Contacts 管理、CSV 导入与退信排查

7.3.1 为什么 CSV 导入功能跳过了部分行或未能导入特定订阅者 record?

根本原因:

不符合 RFC 5322 的邮箱 syntax、开启 "Skip Duplicates" 时遇到重复邮箱、文件非 UTF-8 编码或联系人已被系统抑制拉黑。

诊断与底层机制:

MarbleSend 会逐行扫描,通过 filter_var(FILTER_VALIDATE_EMAIL) 校验 syntax,并对照 cm_contacts 校验,避免覆盖 unsubscribed 或 bounced 状态。

实战排查方案与修复:

请确保 CSV file 保存为不带 BOM 的 UTF-8 编码。检查列映射(email, name, tags)。在导入进度窗口中查看被跳过的具体行号。

7.3.2 MarbleSend 是如何区分软退信(Soft Bounce)与硬退信(Hard Bounce)的?

根本原因:

永久性投递失败(5xx SMTP 错误码:邮箱不存在)与暂时性投递故障(4xx SMTP 错误码:邮箱已满、限频)。

诊断与底层机制:

5xx 响应会立即将 contact 状态更新为 bounced。4xx 响应会在 cm_email_logs 中记录软退信重试,最多重试 3 次后方转为 bounced。

实战排查方案与修复:

切勿尝试重新激活硬退信(hard bounce)联系人。向无效地址强行发信将严重降低您在 Gmail 和 Yahoo 等平台的域名声誉。

7.4 Templates 渲染、Outlook 兼容与 Email-Safe 设计

7.4.1 为什么我的邮件模版在桌面版 Microsoft Outlook 中排版错乱或变形?

根本原因:

Windows 平台的 Microsoft Outlook 使用 Microsoft Word (MSO) 渲染引擎,完全不支持 CSS Flexbox、Grid、margin auto 及 HTML5 布局标签。

诊断与底层机制:

Word MSO 仅遵循传统的表格布局结构(nested <table>, <tr>, <td>),且要求明确指定像素宽度和内联样式。

实战排查方案与修复:

请使用 MarbleSend 内置的 8 款经过验证的 email-safe 预设布局。它们采用嵌套 HTML 表格与 MSO 条件注释(<!--[if mso]>),确保 Outlook 完美渲染。

7.4.2 为什么 Gmail 会在邮件底部显示 "[Message clipped] View entire message" 提示?

根本原因:

邮件原始 HTML 源码大小超过了 Gmail 严苛的 102 KB(104,448 字节)截断阈值。

诊断与底层机制:

一旦 HTML 源码超出 102 KB,Gmail 便会截断邮件后半部分,导致内容不完整,并屏蔽底部的退订链接与跟踪像素。

实战排查方案与修复:

请将图片托管于外部 HTTPS 服务器,避免嵌入 base64 图片长字符串。在 Templates Studio 中,点击 "Clean HTML" 格式化精简代码后再发送。

7.4.3 为什么我的邮件里 {{news_posts}} 是空的或缺失?

根本原因:

该占位符只会由内容来源为“新闻文章”的通讯计划填充。在手动 Campaign、RSS 计划或仅模板计划中,它会被替换为空文本。

诊断与底层机制:

当模板在没有新闻文章来源的情况下使用 {{news_posts}} 时,Campaign 预检会显示警告;“模板”→“文章”中的预览始终显示已填充的区块。

实战排查方案与修复:

通过设为“新闻文章”的通讯计划发送该模板,或从其他地方使用的模板中移除该占位符。

7.5 Schedules 周期调度、RSS 抓取与 Worker 节奏

7.5.1 为什么博客发布了新文章,自动化的 RSS 周期任务却没有发出邮件?

根本原因:

Feed URL 无法访问、Feed XML syntax 损坏,或者最新文章的 GUID 与 cm_schedules.last_rss_item_id 一致。

诊断与底层机制:

MarbleSend 会在 last_rss_item_id 中保存最新文章的 SHA-256 哈希。若未发现更新的 <item> 或 <entry>,worker 将直接跳过且不生成队列。

实战排查方案与修复:

在 /schedules 中打开该任务并点击 "Test Feed" 查看实时 XML 响应。确认 RSS 包含有效的 <pubDate> 和唯一的 <guid>。确认已到 next_run_at 时间。

7.5.2 如果服务器或 worker cron 离线数天,周期性 schedules 会发生什么?

根本原因:

在 worker 无法运行期间,错过了多个既定的预定触发时间点。

诊断与底层机制:

MarbleSend 在 SchedulerService 中执行严苛的 "Single Catch-Up Policy"。它不会把所有错过的批次同时塞进队列(否则会刷爆收件箱),而是仅补发最近的那一次。

实战排查方案与修复:

cron 恢复后,仅会编译并发出 1 封补偿广播。随后该任务的 next_run_at 会根据周期规则直接推进至未来的下一个常规时间点。

7.5.3 为什么新闻文章计划没有发送我的就绪文章?

根本原因:

文章在计划的新闻文章模式开启之前就已就绪、已被此计划投递过,或受众/模板阻止了此次运行。

诊断与底层机制:

打开计划历史:“no new posts”表示没有符合条件的内容,“no recipients”表示受众为空,“failed”表示模板缺失或缺少 {{news_posts}}。

实战排查方案与修复:

在计划创建之后把文章的一份副本标记为就绪,修复受众或模板,然后使用“立即运行”。

7.5.4 两个计划可以发送同一篇文章吗?

根本原因:

投递按计划跟踪,而不是按文章。

诊断与底层机制:

每个新闻文章计划都保存自己投递过哪些文章的记录,所以库中显示总计“已发送 N×”。

实战排查方案与修复:

可以——在两个计划都创建之后变为就绪的文章,会被每个计划各发送一次;两者都不会发送两次。

7.6 Settings 配置、Deliverability 送达率、Webhooks 与授权

7.6.1 如何排查 SMTP 报错 "535 Authentication Failed" 或 "550 Relay Access Denied"?

根本原因:

SMTP 凭据有误、端口与加密模式不匹配(587 端口 STARTTLS 对比 465 端口 SSL),或者发件人邮箱未经服务商认证。

诊断与底层机制:

Settings → SMTP 配置提供了实时 socket 测试工具,可直观查看 PHPMailer 与 SMTP 服务器之间的原始交互对话。

实战排查方案与修复:

绝大多数中继推荐使用 587 端口配 TLS。Gmail/Google Workspace 须生成 App Password。Amazon SES 须验证发信域名。cPanel 须使用完整邮箱地址作为用户名。

7.6.2 为什么 Deliverability Suite 会报告 SPF、DKIM 或 DMARC 验证错误?

根本原因:

发信域名缺少相应的 DNS 记录、SPF 超出了 10 次 DNS 查询上限,或者 DKIM 选择器前缀不匹配。

诊断与底层机制:

MarbleSend 会直接向权威域名服务器发起非阻塞 DNS 查询(dns_get_record),逐一核查 SPF(root TXT)、DKIM(selector._domainkey)和 DMARC(_dmarc)。

实战排查方案与修复:

在 SPF 记录中加入 SMTP 中继的 include 声明。核对 DKIM 选择器是否与服务商指引完全一致。确保 DMARC 记录中配置了有效的 rua 报告接收邮箱。

7.6.3 Webhooks 熔断机制(Circuit Breaker)是如何工作的,如何恢复被暂停的终端?

根本原因:

接收端接口持续返回 HTTP 5xx 错误、连接超时(超过 10 秒)或 404 Not Found 响应。

诊断与底层机制:

为防止服务器队列阻塞瘫痪,MarbleSend 会持续记录推送重试,并在发生多次连续失败后自动将该 webhook 挂起暂停(enabled = 0)。

实战排查方案与修复:

打开 Webhook 发送日志抽屉检查具体的 HTTP 状态码与报错载荷。待接收端修复后,点击 "Test Webhook" 测试验证 HMAC 签名无误,再重新开启即可。

7.6.4 Ed25519 授权验证是如何运作的,7 天离线宽限期(Grace Window)是什么意思?

根本原因:

网络波动断网、DNS 解析临时故障,或者上游授权服务器正在进行短期维护。

诊断与底层机制:

授权真实性在内存中通过 libsodium 的 sodium_crypto_sign_verify_detached() 本地校验。擅自修改数据库 record 将直接导致非对称签名失效。

实战排查方案与修复:

MarbleSend 提供 7 天离线宽限期(grace_until)。期间广播发送均正常运转。若最终过期,现有订阅者数据和统计报表在 soft-lock 保护下仍 100% 可读可用。

WordPress 插件与 REST API

WordPress 与第三方表单集成

在 WordPress 站点收集订阅者,并发送到 MarbleSend。配套插件自带订阅表单,并可连接 WPForms、Contact Form 7、Fluent Forms、Formidable Forms 和 Forminator。

表单集成检查器

选择一个组件,查看它的 hook、发送的内容以及设置提示。

Interactive Inspector
REST API

REST API 桥接

不共用数据库
WP-CRON

发送队列

Transient 存储
NATIVE

MarbleSend Form

Shortcode、Block 与 Widget
WPFORMS

WPForms hook

wpforms_process_complete
CF7

Contact Form 7 hook

wpcf7_mail_sent
FLUENT

Fluent Forms hook

submission_inserted
FORMIDABLE

Formidable Forms

frm_after_create_entry
FORMINATOR

Forminator hook

submit_before_set_fields
AUTOMATION

标签自动回复

标签与欢迎邮件

数据库影响:

技术支持团队专业提示:

先决条件

请先安装配套插件(marblesend-forms.zip)

MarbleSend 运行在自己的服务器上,所以 WordPress 需要一个小插件把订阅者发送过去。该插件负责内置的 MarbleSend 表单,并连接 WPForms、Contact Form 7、Fluent Forms、Formidable Forms 和 Forminator。它免费,需要 WordPress 6.3 或更高版本以及 PHP 7.4 或更高版本,并且只通过 REST API 与 MarbleSend 通信。

Settings 菜单在哪里?

激活插件后,WordPress 会在 wp-admin 的 Settings 下显示两个页面:MarbleSend Forms(连接 URL、API key、默认标签和失败日志)以及 MarbleSend Integrations(各表单插件的字段映射)。两者都在 WordPress 中,MarbleSend 控制台里没有。 你自己的表单及其分组、标签和垃圾信息防护,在侧边栏的 MarbleSend Forms 中管理。

1
1. 下载 marblesend-forms.zip

请在 MarbleSend 的 Settings → 授权许可 中下载 marblesend-forms.zip,或直接从 https://marblesend.com/download/marblesend-forms.zip 下载。它是可直接安装的 WordPress 插件 zip:请原样上传,无需解压。

2
2. 在 WordPress 中安装并激活

在 wp-admin 中依次进入 Plugins → Add New → Upload Plugin,选择 marblesend-forms.zip,点击 Install Now,再点击 Activate Plugin。以后更新时,用同样的方式上传新的 zip。WordPress 会提示替换已安装的版本,您的设置会保留。

3
3. 连接 API key(contacts:write)

在 MarbleSend 中打开 Settings → API 与 Webhook,创建带有 contacts:write scope 的 API key。在 WordPress 中打开 Settings → MarbleSend Forms,填入 MarbleSend Site URL 和该 key,保存后点击 Test Connection。应当显示 Connected 以及 scope contacts:write。 然后从 MarbleSend 加载的列表中选择 Default Group 和 Default Tags,或在那里创建新分组。

4
4. 映射您的表单

在 wp-admin 中打开 Settings → MarbleSend Integrations。每个已激活的表单插件都会连同它的表单一起显示。勾选 Enabled,填入邮箱字段,如果表单有姓名字段也一并填入,按需添加标签,然后保存。内置表单无需映射。

没有这个插件,wp-admin 中就没有 MarbleSend Integrations 页面,您的 WordPress 表单也无法把提交发送到 MarbleSend。

8.1 插件如何与 MarbleSend 通信

插件通过 HTTPS 调用 MarbleSend 的 REST API,所以 WordPress 和 MarbleSend 可以运行在不同的服务器上。它无法访问 MarbleSend 的数据库。

不共用数据库

WordPress 从不读取 MarbleSend 的数据表,MarbleSend 也从不读取 wp_posts 或 wp_users。两者可以运行在不同的主机上,使用各自的数据库。

范围受限的 API key

每个请求都带有来自 Settings → API 与 Webhook 的 Bearer API key。contacts:write scope 就足够,所以该 key 不能发送 Campaign,也不能更改计划。

连接测试

Settings → MarbleSend Forms 中的 Test Connection 会调用 GET /api/verify-key 并显示该 key 的 scope,URL 或 key 有误时可以立刻发现。

Upsert 与标签合并

每次提交都会发送到 POST /api/contacts。新的邮箱会成为联系人。已存在的联系人保留原有状态,并在现有标签之外加上新标签;只有表单发送了姓名时,姓名才会改变。开启 double opt-in 时,新联系人在确认之前保持 pending 状态。

API Ingestion Endpoint (cURL Example)
curl -X POST https://your-domain.com/api/contacts \
  -H "Authorization: Bearer ms_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{"email":"visitor@example.com","name":"John Doe","tags":["newsletter","source:wpforms"]}'

可选:添加 "group_ids":[1,2] 可将联系人放入指定分组(用 GET /api/groups 列出分组;省略则为 General)。GET /api/contacts 支持 group_id 按分组筛选。

8.2 发送队列与 WP-Cron

MarbleSend 缓慢或无法访问时,不应让访客的表单卡住,也不应丢失 lead。表单插件的提交会进入队列,并在后台发送。

访客的请求中没有任何缓慢环节

表单插件提交时,MarbleSend_Integration_Base::dispatch() 会清理字段并存入 WordPress transient(set_transient)。访客等待期间不会向 MarbleSend 发出任何请求。

由 WP-Cron 发送队列

一个 WP-Cron 事件 marblesend_forms_process_queue 会被安排在大约一分钟后,发送队列中的提交。

队列中每项只尝试一次

WP-Cron 对队列中的每一项只发送一次。内置表单先直接调用 MarbleSend,只有该调用失败时,才把提交放入队列,等待一次 WP-Cron 尝试。队列中的项目最多保留一小时。

失败会被记录

如果发送失败,或某一项在 WP-Cron 发送之前过期,插件会在 marblesend_forms_log 中添加一行(保留最近 50 条 records),并在 wp-admin 中显示管理员通知。Settings → MarbleSend Forms 会列出该日志和待处理项目的数量。

Transient Queue Enqueuing Snippet
// Non-blocking submission buffer in WordPress
set_transient('marblesend_forms_queue_' . wp_generate_uuid4(), $payload, 3600);
if (!wp_next_scheduled('marblesend_forms_process_queue')) {
    wp_schedule_single_event(time() + 5, 'marblesend_forms_process_queue');
}

8.3 内置订阅表单

插件自带订阅表单,所以您不需要表单构建器。可以用 shortcode、Gutenberg 区块或小工具添加,三者运行的是同一份代码。

Shortcode、区块或小工具

使用 [marblesend_form]、Gutenberg 区块 marblesend/subscribe-form,或 MarbleSend Subscribe Form 小工具。Shortcode 支持 tags、show_name(1 或 0)和 consent(必选复选框的文字)。区块和小工具提供相同的选项。 在 MarbleSend Forms → Add New Form 中创建自己的表单,并用 [marblesend_form id="12"] 嵌入。

防范机器人

屏幕外的 honeypot 字段(marblesend_hp)、在提交表单时才请求的 nonce(这样缓存的页面就不会提供过期的 nonce),以及每个 IP 每 60 秒最多 5 次提交的限制(IP 以哈希形式保存)。填写了 honeypot 或没有有效 nonce 的请求会收到看似正常的成功消息,并被丢弃。请求过多时会收到简短的“请稍候”提示。 在编辑器中创建的表单还可以使用 Cloudflare Turnstile 或 Google reCAPTCHA,在 Settings → MarbleSend Forms 中设置。

访客提交后立即发送

页面不会刷新。插件会立即将联系人发送到 MarbleSend(超时 5 秒)。如果无法连接 MarbleSend,或插件尚未配置,提交会进入队列,等待一次 WP-Cron 尝试,访客仍会看到成功消息。如果请求本身失败,表单会显示错误,并且可以重新提交。

姓名、标签与确认

访客只提供邮箱时,新联系人会以 @ 之前的部分作为姓名,因为 API 需要姓名。已存在的联系人保留自己的姓名。每个联系人都会获得标签 source:wp-form,以及表单和 Settings → MarbleSend Forms 中设置的标签。开启 double opt-in 时,访客会看到提示他们查收邮件的消息。 联系人会加入表单的分组,或 Settings → MarbleSend Forms 中的 Default Group。

Shortcode & Gutenberg Block Embed Syntax

[marblesend_form tags="newsletter,inbound" show_name="1" consent="I agree to receive email updates and accept the privacy policy."]




8.4 WPForms(Lite 与 Pro)

WPForms 是使用最广泛的表单构建器之一。插件在 WPForms 验证提交之后读取数据,因此不需要任何 WPForms 附加组件。

检测与 hook

插件用 function_exists('wpforms') 检测 WPForms,并监听 wpforms_process_complete 动作(优先级 10),该动作会收到已验证的字段。

字段 ID

WPForms 用编号识别字段。在构建器中选中一个字段,在字段选项顶部读取它的 ID,例如 Field ID #2,然后把这个数字填入映射。包含名和姓的姓名字段会被合并为一个姓名。

设置

1. 记下 Email 字段的 ID,以及(如果有)Name 字段的 ID。2. 打开 Settings → MarbleSend Integrations,找到 WPForms。3. 勾选 Enabled,填入 ID 和所需标签。4. 保存。

来源标签

每个来自 WPForms 的联系人除了您自己的标签外,还会获得标签 source:wpforms,因此您可以只向这一组发送 Campaign。

WPForms Complete Hook Architecture
add_action('wpforms_process_complete', function($fields, $entry, $form_data, $entry_id) {
    $email = $fields[1]['value'] ?? ''; // Numeric Field ID #1
    $name  = $fields[0]['value'] ?? ''; // Numeric Field ID #0
    MarbleSend_Integration_Base::dispatch('wpforms', $form_data['id'], $email, $name);
}, 10, 4);

8.5 Contact Form 7(CF7)

Contact Form 7 把字段定义为文本模板中的标签。插件在表单的邮件发出之后介入。

检测与 hook

插件用 class_exists('WPCF7_ContactForm') 检测 CF7,并监听 wpcf7_mail_sent(优先级 10)。只有当表单通过垃圾信息与验证检查、且 Contact Form 7 发出了自己的邮件之后,lead 才会被转发。如果您的主机无法发送邮件,则不会转发任何内容。

标签名称

CF7 在表单标签中为字段命名,例如 [email* your-email] 和 [text your-name]。把名称(your-email、your-name)填入 Email Field 和 Name Field 框。

读取提交内容

插件通过 WPCF7_Submission::get_instance()->get_posted_data() 读取提交的数据,可配合 CF7 的 AJAX 提交使用。

设置

1. 在 Contact → Contact Forms 中打开表单,记下标签名称。2. 在 Settings → MarbleSend Integrations 中找到 Contact Form 7。3. 勾选 Enabled,填入 your-email,如果表单有姓名字段也填入 your-name,并按需添加标签。4. 保存。

Contact Form 7 Mail Sent Hook
add_action('wpcf7_mail_sent', function($contact_form) {
    $submission = WPCF7_Submission::get_instance();
    $data = $submission ? $submission->get_posted_data() : [];
    $email = $data['your-email'] ?? '';
    $name  = $data['your-name'] ?? '';
    MarbleSend_Integration_Base::dispatch('cf7', $contact_form->id(), $email, $name);
}, 10, 1);

8.6 Fluent Forms(Free 与 Pro)

插件监听 Fluent Forms 在保存条目之后触发的动作。

检测与 hook

插件用 function_exists('wpFluent') 检测 Fluent Forms,并监听 fluentform/submission_inserted(优先级 10),它会收到 $entry_id、$form_data 和 $form。

Name Attribute

Fluent Forms 通过 Name Attribute 识别字段,例如邮箱用 email,姓名字段用 names(名和姓会合并)。可在字段设置的 Advanced Options 下找到。

表单列表

Integrations 页面通过读取 Fluent Forms 自己的表单数据表来列出您的表单,因此无需查找表单 ID。

设置

1. 检查邮箱字段和姓名字段的 Name Attribute。2. 在 Settings → MarbleSend Integrations 中为该表单勾选 Enabled,并填入这两个值。3. 添加标签并保存。新联系人会获得标签 source:fluentforms。

Fluent Forms Insertion Action
add_action('fluentform/submission_inserted', function($entryId, $formData, $form) {
    $email = $formData['email'] ?? '';
    $name  = is_array($formData['names'] ?? null) ? implode(' ', $formData['names']) : ($formData['first_name'] ?? '');
    MarbleSend_Integration_Base::dispatch('fluentforms', $form->id, $email, $name);
}, 10, 3);

8.7 Formidable Forms(Lite 与 Pro)

插件在 Formidable Forms 保存条目之后立即读取它。

检测与 hook

插件用 class_exists('FrmForm') 检测 Formidable,并监听 frm_after_create_entry(优先级 30),它会收到 $entry_id 和 $form_id。

Field ID

Formidable 会为每个字段分配一个数字 Field ID(例如 12)。请将其填入映射;不支持字段键。数据通过 FrmEntry::getOne($entry_id)->metas 提取。

仅限已保存的条目

插件在条目创建之后运行,所以只有通过 Formidable 验证的提交才会被转发。

分步配置流程

1. 在 Formidable 构建器中点击邮箱字段并记下其 Field ID。2. 在 Settings → MarbleSend Integrations 中启用该表单并填入 Field ID。3. 保存映射。导入的 lead 会获得标签 source:formidable。

Formidable Metas Extraction Hook
add_action('frm_after_create_entry', function($entryId, $formId) {
    $entry = FrmEntry::getOne($entryId, true);
    $email = $entry->metas[12] ?? $entry->metas['email-address'] ?? '';
    $name  = $entry->metas[11] ?? $entry->metas['full-name'] ?? '';
    MarbleSend_Integration_Base::dispatch('formidable', $formId, $email, $name);
}, 30, 2);

8.8 Forminator(Free 与 Pro)

插件监听 Forminator 在处理提交时触发的 hook。

检测与 hook

插件用 class_exists('Forminator_API') 检测 Forminator,并监听 forminator_custom_form_submit_before_set_fields(优先级 10),它会收到 $entry、$form_id 和 $field_data。

Element ID

Forminator 为每个字段分配一个 element ID,例如 email-1、name-1 或 text-1。把这些 ID 填入映射。表单编辑器会显示它们。

表单列表

Integrations 页面按名称列出您的 Forminator 表单,数据由 Forminator_API::get_forms() 读取。

设置

1. 打开 Forminator,记下 element ID(email-1、name-1)。2. 在 Settings → MarbleSend Integrations 中找到 Forminator 并填入这些 ID。3. 添加标签并保存。4. 发送一次测试提交,确认联系人带有标签 source:forminator。

Forminator Submission Pre-Field Hook
add_action('forminator_custom_form_submit_before_set_fields', function($formId, $response, $fieldData) {
    $fields = array_column($fieldData, 'value', 'name');
    $email  = $fields['email-1'] ?? '';
    $name   = $fields['name-1'] ?? '';
    MarbleSend_Integration_Base::dispatch('forminator', $formId, $email, $name);
}, 10, 3);

8.9 标签、分组与自动回复

来自 WordPress 插件的联系人会加入在 Settings → MarbleSend Forms(Default Group)或表单中选择的分组;未选择时进入 General。可用标签进行细分,或在 Contacts 中将其移入分组。

收集邮箱只是第一步。标签决定联系人接下来会发生什么。

来源标签

除了您自己的标签,每个联系人还会获得 source:<slug>:source:wp-form、source:wpforms、source:cf7、source:fluentforms、source:formidable 或 source:forminator。可以用它们向某一个表单插件的订阅者发送 Campaign。

欢迎邮件

在 /contacts → Autoresponders 中,为您分配给 WordPress 表单的标签创建一条规则。当联系人变为活跃(提交后立即,或确认 double opt-in 之后),MarbleSend 会用您选定的模板和 SMTP 配置将欢迎邮件加入队列。

中间没有自动化服务

插件把 lead 直接发送到您自己的 MarbleSend 安装。Zapier 或 Make 这样的服务不在这条路径上。

Double opt-in 与 consent record

开启 double opt-in 时,新联系人以 pending 状态保存,并带有 consent_source = 'api'。MarbleSend 会通过邮件发送确认链接({{confirm_link}})。联系人点击后,状态变为 active,并记录时间和 IP 地址以符合 GDPR。

Autoresponder Tag Structure (JSON Payload)
{
  "email": "lead@agency.com",
  "name": "Jane Smith",
  "tags": ["source:wpforms", "ebook-download", "vip-inbound"],
  "consent_source": "api"
}

8.10 故障排查

连接 WordPress 表单时的常见问题,包括原因、检查方法和解决办法。

为什么提交在 MarbleSend 中出现得很晚,或者根本没有出现?

根本原因:

WP-Cron 只在有人访问站点时运行。在访问量小的站点或 staging 站点上,队列中的提交要等到下一次访问。队列中的提交只保留一小时。如果 WP-Cron 在这段时间内没有运行,提交就会丢失,marblesend_forms_log 会记录有一条已过期(它无法指出访客是谁,因为存储的数据也已过期)。

诊断与底层机制:

在 wp-admin 中打开 Settings → MarbleSend Forms。待处理数量显示正在等待 marblesend_forms_process_queue 的项目。日志中如果有“队列中的提交已过期”的记录,说明 WP-Cron 超过一小时没有运行。

实战排查方案与修复:

打开 https://your-site.com/wp-cron.php?doing_wp_cron 运行一次,或设置真正的服务器 cron 任务(* * * * * wget -q -O - https://your-site.com/wp-cron.php >/dev/null 2>&1)。

为什么日志里写着“Skipped: no valid email in form submission”?

根本原因:

映射中的邮箱字段有拼写错误,或访客提交了空的或无效的地址,被 sanitize_email() 拒绝。

诊断与底层机制:

每当已启用的表单没有产生有效邮箱时,MarbleSend_Integration_Base::log_skip() 就会在 marblesend_forms_log 中写入一条记录。

实战排查方案与修复:

检查您的表单构建器使用的标识:WPForms 和 Formidable Forms 用数字(例如 2),Contact Form 7 用标签名称(your-email),Fluent Forms 用 Name Attribute(email),Forminator 用 element ID(email-1)。

为什么 WordPress 提示 API key 无效或缺少 scope?

根本原因:

WordPress 中的 key 已被撤销、已过期、已在 MarbleSend 中删除,或创建时没有 contacts:write scope。

诊断与底层机制:

Test Connection 会调用 GET /api/verify-key。返回 HTTP 401 或 403 表示认证失败。

实战排查方案与修复:

在 MarbleSend 中打开 Settings → API 与 Webhook,创建带有 contacts:write scope(或 admin)的新 key。把以 ms_ 开头的令牌复制到 WordPress 的 Settings → MarbleSend Forms 中。

为什么表单显示错误时,Contact Form 7 的 lead 会丢失?

根本原因:

插件只在 Contact Form 7 发出自己的邮件之后才转发 lead。邮件发送失败时,CF7 会显示它的错误消息,lead 不会被转发。

诊断与底层机制:

自己提交一次表单。如果看到“There was an error trying to send your message”,说明 CF7 无法发出邮件。

实战排查方案与修复:

修复您 WordPress 站点的邮件发送,例如使用 SMTP 插件。CF7 能发出邮件之后,lead 就会到达 MarbleSend。

为什么联系人的姓名是它的邮箱地址?

根本原因:

表单没有姓名字段,或没有映射姓名字段。MarbleSend 的 API 要求提供姓名,所以新联系人会取邮箱中 @ 之前的部分。

诊断与底层机制:

查看 Settings → MarbleSend Integrations 中该表单的那一行:Name Field 框是空的。已经存在的联系人不受影响,因为它保留自己的姓名。

实战排查方案与修复:

给表单添加姓名字段,并填入映射。已存在的联系人保留当前姓名;如有需要,可在 /contacts 中修改。