# storlead-mail 子模块说明 邮件服务拆为四个 Maven 子模块,避免 CRM 与营销业务混在一起,调度统一编排。 ## 模块 | 模块 | Artifact | 职责 | |------|----------|------| | common | `storlead-mail-common` | 账户、SMTP/IMAP、公共投递、`MailReceiveEngine` 收信引擎、`MailSceneEnum` | | crm | `storlead-mail-crm` | CRM 个人邮箱:`emails` / `client_sent_emails`、收信、文件夹、CRM 集成任务 | | mkt | `storlead-mail-mkt` | 营销投递:`mkt_mail_message` / `mkt_mail_attachment`、草稿、附件、延时、打开追踪 | | dispatch | `storlead-mail-dispatch` | **统一调度**:定时发送(CRM+MKT)、CRM 收信拉取、服务器邮件延迟删除 | 依赖方向: ``` crm → common mkt → common dispatch → crm + mkt api → dispatch ``` **crm 与 mkt 互不依赖**;调度放在 dispatch,避免任务只挂在 crm 里。 ## 包名 - `com.storlead.sales.mail.common.*` - `com.storlead.sales.mail.crm.*` - `com.storlead.sales.mail.mkt.*` - `com.storlead.sales.mail.dispatch.*` API: - `com.storlead.mail.common` — 账户配置 - `com.storlead.mail.crm` — CRM 邮件接口(原 `/mail/**`) - `com.storlead.mail.mkt` — 营销接口(`/mail/mkt/**`) - `POST /mail/mkt/receive_mail?accountId=` — 异步收信(INBOX+Sent Items → `mkt_mail_message.folder`,`reply_msg_id` 绑定原信) - `POST /mail/mkt/file/cache_mail_file` — 上传临时附件(`scene=MKT`,需 `accountId`) - `POST /mail/mkt/file/list` — 按邮件查正式附件 `mkt_mail_attachment` - `POST /mail/mkt/file/download` — 下载正式附件 - `POST /mail/mkt/file/download_temp` — 下载临时附件 - `POST /mail/mkt/save_draft` — 保存草稿(`status=-2`,绑定 `fileIds`/`oldFileIds`) - `POST /mail/mkt/send` — 发送(CID 内嵌图、附件、延时、追踪像素;`isTrack=1` 需配置 `storlead.mail.track-base-url`) - `POST /mail/mkt/page_list` — 分页(支持 `opened` / `isTrack` / `bizBatchNo`) - `POST /mail/mkt/detail` — 详情(草稿带临时附件,成功带正式附件) - `POST /mail/mkt/open_stats?bizRef=` — 按业务单号汇总打开情况 - `GET /mail/mkt/track/{token}` — 打开追踪像素(免登录,白名单) ### 打开追踪说明 1. 发信 `isTrack=1` → 生成 `track_token`,HTML 注入 1x1 像素 2. 收件端加载图片 → `opened=1`,`first_open_time`,`open_count++` 3. 可实现 `MktMailOpenCallback` 做业务侧「客户已打开」通知 4. 像素仅为弱信号(网关预取/禁图会导致偏差) 临时附件共用 `mail_temp_attachment`(`scene` 默认 `CRM`);正式附件 CRM/MKT 分表。 ## 调度任务 | Job | 覆盖范围 | |-----|----------| | `DelaySendEmailTaskJob` | CRM 延时发信 + 营销延时发信 | | `EmailPullHeadContentTaskJob` | 仅 CRM 收信(营销账户默认不收) | | `DelayDeleteServerEmailTaskJob` | 仅 CRM IMAP 服务器删除 | ## 库表变更 执行:`storlead-mail-common/src/main/resources/sql/mail_scene_and_mkt.sql` 状态表:`storlead-mail-common/src/main/resources/sql/mkt_mail_status.sql` 黑名单:`storlead-mail-common/src/main/resources/sql/mkt_mail_blacklist.sql` - `smtp_pop_settings` 增加 `scene` / `account_scope` / `org_id` 等 - 新建 `mkt_mail_message`、`mkt_mail_attachment`、`mkt_mail_status`、`mkt_mail_blacklist` - `mail_temp_attachment` 增加 `scene`(默认 `CRM`) ### 营销黑名单 | 能力 | 说明 | |------|------| | 发信拦截 | `/mkt/send` 校验 TO/CC/BCC,命中则返回「无法发送 + 黑名单理由」 | | 退信入黑 | INBOX 识别 mailer-daemon/undeliverable 等,提取失败地址写入黑名单 | | SMTP 失败入黑 | `SendFailedException`/550 将收件人写入黑名单 | | 管理接口 | `POST /mkt/blacklist/page_list`、`/save`、`/deleteIds`、`/enabled` | ### mkt_mail_status 埋点 | 事件 | 更新字段 | |------|----------| | 草稿/发送落库 | `ensureStatus` 初始化行,`status_updated_at=now`,`synced_at=null` | | SMTP 成功/失败 | `send_status` = 1 / 2,刷新 `status_updated_at` | | 像素打开 | `opened=1`,`open_count+1`,`first_open_time`(仅首次),`last_open_time=now`,同步 `is_read` / `first_read_time`,刷新 `status_updated_at` | | 收信绑定回复 | 原信 `replied` / `first_reply_time`,刷新 `status_updated_at` | | 业务同步完成 | 回写 `synced_at=now`(不改 `status_updated_at`) | - `status_updated_at`:业务状态变更时间(打开/回复/发送态等) - `synced_at`:业务侧最后同步时间 - 待同步条件:`synced_at IS NULL OR synced_at < status_updated_at` 存量升级执行:`storlead-mail-common/src/main/resources/sql/mkt_mail_status_add_synced_at.sql`