迁移 0033:邮箱账号 / 入站 / 投递 / 出站四张表;mail store 与跨进程租约(两连接对抢 20 轮每轮一个赢)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TM4kUBvekALu9qqmp7D3wr
This commit is contained in:
xcs
2026-08-26 00:49:24 +08:00
co-authored by Claude Fable 5
parent 8d7e56aa92
commit 5f1e64b4d4
7 changed files with 737 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
-- 邮件收发(ADR-013):账号(配置 + 密封凭证 + 游标 + 跨进程租约)、入站留痕、逐订阅方投递留痕、出站留痕。
--
-- 腾讯企业邮箱两条接入路(IMAP/SMTP · 企业微信邮件 API)都没有带内容的推送,只能轮询拉:
-- 两个后端连同一个库时,一个信箱同一时刻只许一个进程在拉 —— `polling_until` 与
-- `sys.task.advancing_until` 同款(一条 SQL 判 + 占,带过期时间,进程崩了不锁死)。
-- 入站两把唯一键:重复拉到(时钟偏 / UIDVALIDITY 重锚 / wecom 十分钟重叠窗)一律静默跳过。
-- 入站 / 出站表对账号**不设外键**:账号删了留痕还在。
create table if not exists sys.mail_account (
id text primary key,
name text not null,
kind text not null check (kind in ('imap-smtp', 'wecom')),
address text not null default '',
display_name text not null default '',
enabled boolean not null default true,
is_default boolean not null default false,
poll_interval_sec integer not null default 30 check (poll_interval_sec between 10 and 3600),
channel_id text,
backfill_from timestamptz,
settings jsonb not null default '{}'::jsonb,
secret_cipher text,
cursor jsonb,
last_polled_at timestamptz,
last_poll_error text,
last_inbound_at timestamptz,
polling_until timestamptz,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create unique index if not exists mail_account_name_key on sys.mail_account (name);
-- 默认发件账号至多一个 —— 用例先把别的置 false,这道索引兜底
create unique index if not exists mail_account_one_default on sys.mail_account ((true)) where is_default;
create index if not exists mail_account_due_idx on sys.mail_account (enabled, last_polled_at);
create table if not exists sys.mail_inbound (
id text primary key,
account_id text not null,
message_id text not null,
provider_ref text not null,
in_reply_to text,
reference_ids jsonb not null default '[]'::jsonb,
from_addr text not null default '',
from_name text not null default '',
to_list jsonb not null default '[]'::jsonb,
cc_list jsonb not null default '[]'::jsonb,
subject text not null default '',
text_body text,
html_body text,
sent_at timestamptz,
received_at timestamptz not null,
attachments jsonb not null default '[]'::jsonb,
raw bytea,
raw_note text not null default '',
size integer not null default 0,
created_at timestamptz not null default now()
);
create unique index if not exists mail_inbound_message_key on sys.mail_inbound (account_id, message_id);
create unique index if not exists mail_inbound_provider_key on sys.mail_inbound (account_id, provider_ref);
create index if not exists mail_inbound_time_idx on sys.mail_inbound (received_at desc);
create table if not exists sys.mail_inbound_delivery (
mail_id text not null references sys.mail_inbound(id) on delete cascade,
subscriber text not null,
state text not null check (state in ('dispatching', 'done', 'failed', 'skipped')),
error text,
started_at timestamptz not null default now(),
finished_at timestamptz,
primary key (mail_id, subscriber)
);
create table if not exists sys.mail_outbound (
id text primary key,
account_id text not null,
message_id text not null,
idempotency_key text,
to_list jsonb not null,
cc_list jsonb not null default '[]'::jsonb,
bcc_list jsonb not null default '[]'::jsonb,
subject text not null,
text_body text,
html_body text,
in_reply_to text,
reference_ids jsonb not null default '[]'::jsonb,
attachments jsonb not null default '[]'::jsonb,
state text not null check (state in ('sending', 'sent', 'failed')),
error text,
provider_ref text,
requested_by jsonb not null default '{}'::jsonb,
created_at timestamptz not null default now(),
sent_at timestamptz
);
create unique index if not exists mail_outbound_idem_key on sys.mail_outbound (idempotency_key) where idempotency_key is not null;
create index if not exists mail_outbound_time_idx on sys.mail_outbound (created_at desc);
+7
View File
@@ -232,6 +232,13 @@
"when": 1785130120180,
"tag": "0032_keycloak_identity",
"breakpoints": true
},
{
"idx": 33,
"version": "7",
"when": 1785130120181,
"tag": "0033_mail",
"breakpoints": true
}
]
}