# 通用 EDM 业务流程说明 更新时间:2026-05-26 ## 1. 文档目标 本文用于新的 EDM 子系统设计或重构,目标是在功能保持一致的前提下,将现有 EDM 业务抽象成通用流程,便于后续拆分服务、设计数据模型、规划 Kafka 消费链路、接入邮件发送通道和处理邮件客服工单。 ## 2. 业务范围 通用 EDM 子系统建议分为三条业务线: | 业务线 | 说明 | | --- | --- | | 批量营销邮件 | 管理后台创建邮件任务,按标签、站点、产品、用户状态筛选目标用户,生成待发送邮件记录,通过队列异步发送 | | 自动 / 实时策略邮件 | 根据用户注册、访问、在线、站点、产品、行为、无消息等规则自动筛选用户,并生成策略邮件 | | 邮件工单 | 用户来信、表单提交或外部收信服务进入后台后,生成或更新邮件工单,由客服处理、回复、转发、关闭 | 如果新系统还需要普通邮箱功能,可以作为独立模块处理。普通邮箱收发不一定进入 EDM 工单链路,是否合并需要单独确认。 ## 3. 总体架构 ```mermaid flowchart TD A["管理后台"] --> B["EDM 任务服务"] B --> C["目标用户筛选服务"] C --> D["邮件记录生成服务"] D --> E["Kafka / 队列"] E --> F["邮件发送消费者"] F --> G["外部发送通道"] G --> H["AWS SES / SMTP / Gmail / Microsoft"] H --> I["事件回调"] I --> J["事件处理服务"] J --> K["统计与黑名单"] L["用户来信 / 表单提交"] --> M["入站接收服务"] M --> N["Kafka / 入站队列"] N --> O["EDM 工单服务"] O --> P["客服工作台"] P --> E ``` 核心组件职责: | 组件 | 职责 | | --- | --- | | 管理后台 | 创建邮件任务、审核任务、查看统计、处理邮件工单 | | 任务服务 | 保存任务配置、正文、模板、发送时间、审核状态 | | 用户筛选服务 | 根据标签、站点、产品、黑名单、订阅状态、发送频率等规则筛选目标用户 | | 邮件记录服务 | 按用户生成单封待发送邮件记录和正文快照 | | Kafka / 队列 | 解耦任务生成、邮件发送、入站消息、事件统计 | | 发送消费者 | 消费待发送邮件,调用外部发送通道,并保存发送结果 | | 入站接收服务 | 接收表单、用户来信或外部邮件服务回调,写入入站队列 | | 工单服务 | 根据来信生成或更新邮件工单,维护状态、负责人、未读数和处理记录 | | 事件处理服务 | 处理送达、打开、点击、退信、投诉、拒信等邮件事件 | | Redis / 缓存 | 保存并发锁、游标、限流计数、近期任务统计、临时筛选集合 | ## 4. 核心数据模型 新子系统建议至少抽象以下对象: | 对象 | 说明 | | --- | --- | | 邮件任务 EmailTask | 批量营销或策略邮件任务,保存任务名称、类型、发送时间、审核状态、目标条件 | | 邮件内容 EmailContent | 任务级正文、标题、模板、发件人、回复地址、附件配置 | | 目标用户 TaskRecipient | 任务命中的用户关系,便于统计和去重 | | 单封邮件 EmailMessage | 最终发送或接收的一封邮件记录,包含方向、收件人、发件人、状态、message_id、工单 ID | | 邮件正文 EmailBody | 单封邮件正文快照,避免模板后续变化影响历史邮件 | | 工单 EmailTicket | 用户来信或客服主动发起的一次处理过程 | | 分配记录 Assignment | 工单分配、移交、释放、代班等操作记录 | | 节点日志 NodeLog | 创建、分配、首次回复、关闭、未解决、转化中等关键节点 | | 发送事件 EmailEvent | 送达、打开、点击、退信、投诉、拒信、渲染失败等事件 | | 黑名单 / 退订名单 Suppression | 退信、投诉、退订、风险用户等不可发送或需谨慎发送的人群 | ## 5. 批量营销邮件流程 ```mermaid flowchart TD A["后台创建邮件任务"] --> B["校验任务配置"] B --> C["写入任务、内容、标签条件"] C --> D["进入待审核"] D --> E{"审核结果"} E -->|通过| F["进入待执行"] E -->|驳回| G["记录驳回原因并结束"] F --> H["到达发送时间"] H --> I["筛选目标用户"] I --> J["生成单封待发送邮件记录"] J --> K["投递 Kafka"] K --> L["发送消费者调用外部邮件通道"] L --> M["更新发送状态和 message_id"] ``` 创建任务时建议校验: 1. 任务名称不能重复。 2. 邮件模板或正文必须存在。 3. 发件邮箱必须存在并可用。 4. 发件域名必须在允许范围内。 5. 必须选择目标人群或策略条件。 6. 发送时间必须符合业务规则。 7. 如果绑定活动,发送时间需要满足活动时间约束。 8. 目标人数需要预估,避免误发全量用户。 目标用户筛选建议包含: 1. 标签包含和标签排除。 2. 站点、产品、品牌、语言、地区。 3. 订阅状态、退订状态、黑名单、投诉用户、永久退信用户。 4. 近期发送频率限制,避免短时间重复触达。 5. 任务级去重,避免同一用户重复生成同一任务邮件。 ## 6. 自动 / 实时策略邮件流程 ```mermaid flowchart TD A["策略配置"] --> B["定时任务生成当日策略任务"] B --> C["实时策略扫描"] C --> D["按用户行为和条件筛选"] D --> E["应用黑名单、退订、频率控制"] E --> F["生成待发送邮件"] F --> G["投递发送队列"] G --> H["发送消费者调用邮件通道"] H --> I["事件回调更新统计"] ``` 策略邮件与批量邮件的区别: 1. 批量邮件通常由运营手动创建,发送时间明确。 2. 策略邮件通常由系统按规则自动生成,可能按分钟或按天扫描。 3. 策略邮件更依赖幂等和频率控制,避免同一用户在同一策略下反复触发。 4. 策略邮件应记录策略 ID、触发原因、触发时间,便于归因。 建议策略执行时做并发锁,避免多个任务实例重复生成邮件。 ## 7. 邮件发送链路 通用发送链路: ```mermaid flowchart TD A["待发送邮件记录"] --> B["写入 Kafka"] B --> C["发送消费者"] C --> D["读取发件通道配置"] D --> E{"发送通道"} E -->|批量营销| F["AWS SES 或批量发送通道"] E -->|客服回复| G["SMTP / Gmail / Microsoft"] F --> H["保存发送结果"] G --> H H --> I["通知前端或更新统计"] ``` 发送消费者需要处理: 1. 队列消息反序列化。 2. 邮件正文、标题、收件人、发件人、回复地址、附件组装。 3. 发送通道选择。 4. 调用外部服务。 5. 成功后保存 `message_id`、发送时间和成功状态。 6. 失败后保存错误信息、失败状态和重试次数。 发送通道建议按场景区分: | 场景 | 推荐处理 | | --- | --- | | 批量营销邮件 | 走支持批量和事件回调的邮件服务,例如 AWS SES | | 策略邮件 | 可复用批量发送通道,但必须做频率和幂等控制 | | 工单客服回复 | 按发件邮箱配置选择 SMTP、Gmail API 或 Microsoft Graph | | 普通邮箱回复 | 可独立于工单链路,同步或异步发送均可 | ## 8. 邮件事件回调与统计 邮件发送后,外部服务会产生事件。通用事件包括: | 事件 | 处理建议 | | --- | --- | | Delivery / 送达 | 标记邮件已送达,记录送达时间和发送 IP | | Bounce / 退信 | 区分永久退信和临时退信,更新任务统计;永久退信可加入黑名单 | | Open / 打开 | 标记打开时间,更新任务打开统计 | | Click / 点击 | 记录点击链接和点击时间,更新点击统计 | | Complaint / 投诉 | 记录投诉,加入抑制名单或黑名单 | | Subscription / 订阅变更 | 更新订阅或退订状态 | | Reject / 拒信 | 记录拒信原因,更新失败统计 | | Rendering Failure / 渲染失败 | 记录模板或内容渲染失败 | | DeliveryDelay / 延迟 | 可记录延迟事件,是否统计需业务确认 | 事件处理要点: 1. 事件必须通过 `message_id` 或自定义追踪 ID 关联到本地邮件记录。 2. 同一事件可能重复回调,需要幂等处理。 3. 打开和点击事件存在图片加载、隐私保护、客户端屏蔽等不确定性,统计只能作为参考指标。 4. 投诉、退订、永久退信应优先进入发送抑制规则。 ## 9. 入站邮件 / 表单进入工单流程 入站来源可以有多种: 1. 网站表单提交。 2. 用户真实邮件来信。 3. 外部收信服务回调。 4. IM 或其他渠道转入邮件客服。 通用流程: ```mermaid flowchart TD A["用户来信或表单提交"] --> B["入站接收服务"] B --> C["写入 Kafka 入站队列"] C --> D["EDM 工单消费者"] D --> E["保存入站邮件和正文"] E --> F{"是否存在未关闭工单"} F -->|否| G["创建新工单"] F -->|是| H["绑定到原工单并更新未读数"] G --> I["写入节点日志"] H --> I I --> J["通知客服工作台"] ``` 创建或更新工单时建议: 1. 以发件邮箱、收件邮箱、业务用户 ID、会话标识等组合判断是否复用未关闭工单。 2. 新工单记录来源、用户邮箱、发件邮箱、团队、状态、未读数、最后来信时间。 3. 已有工单更新最后来信时间、未读数、用户来信数。 4. 如果当前客服离线,可以释放负责人,让工单重新进入分配池。 5. 入站正文应保存原始内容和清洗后的展示内容。 ## 10. 工单客服处理流程 ### 10.1 工单状态 通用状态建议: | 状态 | 说明 | | --- | --- | | 待处理 | 新入站邮件或表单生成工单,等待客服处理 | | 服务中 | 客服已接手并正在处理 | | 未解决 | 客服标记暂未解决,需要后续跟进 | | 转化中 | 进入销售或转化跟进阶段 | | 已关闭 | 本次邮件工单处理结束 | 状态值可以由新系统自行定义,但需要保证列表筛选、统计、自动关闭和权限校验口径统一。 ### 10.2 自动分配 自动分配建议流程: 1. 找到待处理且未分配的工单。 2. 根据收件邮箱、团队、站点、语言或业务线确定可服务团队。 3. 获取在线客服。 4. 按接单上限、当前处理数、最近分配时间选择客服。 5. 更新工单负责人。 6. 写入分配记录和节点日志。 7. 通知客服工作台。 ### 10.3 客服回复 ```mermaid flowchart TD A["客服点击发送"] --> B["校验客服在线、权限、工单状态"] B --> C["写入待发送邮件记录和正文"] C --> D["更新工单未读数、首次响应、回复耗时"] D --> E["投递客服回复队列"] E --> F["发送消费者选择 SMTP / Gmail / Microsoft"] F --> G["保存发送成功或失败结果"] G --> H["通知客服工作台"] ``` 发送前建议校验: 1. 客服必须在线。 2. 工单必须存在且未关闭。 3. 当前客服必须是工单处理人,或具备接手权限。 4. 工单必须属于当前客服可处理团队。 5. 主题、正文、收件人、回复地址必须合法。 6. 附件大小、类型、数量需要符合业务规则和发送通道限制。 ### 10.4 转发和主动开工单 转发: 1. 需要填写新的收件人。 2. 转发邮件可以不绑定到原工单作为普通回复。 3. 原邮件和转发邮件需要建立关联,方便追溯。 4. 发送链路仍可复用客服回复队列。 主动开工单: 1. 客服选择发件邮箱和目标用户邮箱。 2. 系统校验发件邮箱归属团队。 3. 如果同一发件邮箱和用户邮箱已有未关闭工单,应拒绝重复创建或要求接手原工单。 4. 创建服务中工单,负责人为当前客服。 5. 写入节点日志和分配记录。 6. 发送第一封邮件。 ## 11. 工单辅助任务 新子系统可按需要保留以下后台任务: | 任务 | 说明 | | --- | --- | | 自动分配 | 将未分配待处理工单分配给在线客服 | | 自动移交 | 当前负责人离线且有新来信时,按代班或团队规则重新分配 | | DDL 释放 | 工单分配后超过配置时间未处理,释放为未分配 | | 未回复提醒 | 用户新来信超过配置时间未回复,提醒负责人 | | 自动关闭 | 服务中工单超过配置时间无新用户来信时自动关闭 | | 未分配告警 | 未分配工单数量超过阈值时通知团队管理员 | | 统计同步 | 定时刷新任务发送数、回复数、打开数、点击数等统计 | 具体调度频率和启用范围需要按新系统 SLA 确认。 ## 12. 通用限制与风控点 ### 12.1 任务和发送限制 建议配置化管理: 1. 单任务最大目标人数。 2. 单轮投递队列数量。 3. 单发件邮箱每分钟、每小时、每天发送上限。 4. 单用户每天或一段时间内最大触达次数。 5. 单域名发送上限。 6. 批量邮件和客服回复是否共享额度。 ### 12.2 内容限制 建议校验: 1. 邮件主题最大长度。 2. 正文最小和最大长度。 3. 附件大小、类型、数量。 4. 发件邮箱和回复邮箱格式。 5. 链接合法性和追踪参数。 6. 必要的退订入口和合规声明。 ### 12.3 人群抑制 发送前应排除: 1. 退订用户。 2. 投诉用户。 3. 永久退信用户。 4. 风险用户。 5. 明确不允许触达的用户。 6. 已达到频率上限的用户。 ### 12.4 幂等和重试 需要幂等的场景: 1. 任务生成邮件记录。 2. 邮件记录投递 Kafka。 3. Kafka 消费发送。 4. 外部事件回调。 5. 入站邮件生成工单。 失败重试建议区分: 1. 可重试:网络超时、临时服务不可用、临时退信、限流。 2. 不可重试:邮箱格式错误、发件权限错误、账号不存在、永久退信、投诉抑制。 ## 13. 可观测性 建议至少记录以下指标: | 指标 | 说明 | | --- | --- | | 任务创建数 | 按类型、状态统计 | | 目标用户数 | 预估人数、实际生成邮件数、过滤人数 | | 队列积压 | 批量发送队列、客服回复队列、入站队列 | | 发送成功率 | 按通道、发件邮箱、任务统计 | | 失败原因分布 | 发送失败、退信、拒信、限流 | | 送达率、打开率、点击率 | 以事件回调统计,注意打开和点击有误差 | | 投诉率、退订率 | 作为发送风控核心指标 | | 工单响应时长 | 首次响应、最近响应、关闭时长 | | 未分配工单数 | 用于团队容量和告警 | ## 14. 参考代码位置 以下为现有项目中可参考的代码位置,重构时可按新架构重新命名和拆分: | 模块 | 现有参考 | | --- | --- | | 邮件任务后台入口 | `app/admin/controller/MailTaskController.php` | | 邮件任务服务 | `app/service/MailTaskService.php` | | 批量邮件生成与投递参考 | `app/service/UserService.php` | | 批量邮件发送消费者 | `app/command/kafkaConsumer/BatchMailCommand.php` | | 工单后台入口 | `app/admin/controller/EdmChatController.php` | | 工单服务 | `app/service/EdmChatService.php` | | 客服回复消费者 | `app/command/kafkaConsumer/MailSendCommand.php` | | 表单数据消费者 | `app/command/kafkaConsumer/QaForm.php` | | 表单创建工单 | `app/service/WebFormDataService.php` | | 邮件事件回调 | `app/controller/AmazonEmailController.php` | | 普通邮箱服务 | `app/admin/controller/MailboxController.php`、`app/service/MailboxService.php` | | 邮件发送封装 | `app/service/Mail.php` | | Microsoft 邮件服务 | `app/service/MicrosoftService.php` | | 策略邮件命令 | `app/command/EdmDoRealTimeStrategy.php`、`app/command/EdmSendRealTimeStrategy.php`、`app/command/EdmDayCurrentTask.php` | | 工单辅助命令 | `app/command/EdmAllocate.php`、`app/command/EdmMove.php`、`app/command/EdmDealLine.php`、`app/command/EdmTimeout.php`、`app/command/EdmWorkOrderAutoClose.php` |