diff --git a/packages/contracts/src/__tests__/mail.test.ts b/packages/contracts/src/__tests__/mail.test.ts index 22a4d78..ccef494 100644 --- a/packages/contracts/src/__tests__/mail.test.ts +++ b/packages/contracts/src/__tests__/mail.test.ts @@ -37,9 +37,11 @@ describe('mailAccountInputSchema', () => { expect(mailAccountInputSchema.safeParse({ kind: 'wecom', name: 'x', settings: {} }).success).toBe(false); }); - it('轮询间隔下限 10 秒;地址必须是邮箱;kind 只认两种', () => { - expect(mailAccountInputSchema.safeParse({ kind: 'imap-smtp', name: 'a', address: 'a@b.c', pollIntervalSec: 5 }).success).toBe(false); + it('轮询间隔下限 10 秒;地址必须是带 TLD 的邮箱;kind 只认两种', () => { + expect(mailAccountInputSchema.safeParse({ kind: 'imap-smtp', name: 'a', address: 'a@b.com', pollIntervalSec: 5 }).success).toBe(false); expect(mailAccountInputSchema.safeParse({ kind: 'imap-smtp', name: 'a', address: 'not-mail' }).success).toBe(false); + // 漏了 TLD 的地址(sales@corp)是打字错误,在 API 边界就拦下 —— 别拖到 SMTP 才炸 + expect(mailAccountInputSchema.safeParse({ kind: 'imap-smtp', name: 'a', address: 'sales@corp' }).success).toBe(false); expect(mailAccountInputSchema.safeParse({ kind: 'pop3', name: 'a' }).success).toBe(false); expect(MAIL_ACCOUNT_KINDS).toEqual(['imap-smtp', 'wecom']); }); @@ -55,10 +57,10 @@ describe('mailAccountViewSchema', () => { describe('mailSendInputSchema', () => { it('收件人至少一个、主题必填;附件默认空数组;requestedBy 必带 kind', () => { - const ok = mailSendInputSchema.safeParse({ to: ['a@b.c'], subject: 'hi', text: 'x', requestedBy: { kind: 'ops' } }); + const ok = mailSendInputSchema.safeParse({ to: ['a@b.com'], subject: 'hi', text: 'x', requestedBy: { kind: 'ops' } }); expect(ok.success).toBe(true); if (ok.success) expect(ok.data.attachments).toEqual([]); expect(mailSendInputSchema.safeParse({ to: [], subject: 'hi', text: 'x', requestedBy: { kind: 'ops' } }).success).toBe(false); - expect(mailSendInputSchema.safeParse({ to: ['a@b.c'], subject: 'hi', text: 'x' }).success).toBe(false); + expect(mailSendInputSchema.safeParse({ to: ['a@b.com'], subject: 'hi', text: 'x' }).success).toBe(false); }); }); diff --git a/packages/contracts/src/mail.ts b/packages/contracts/src/mail.ts index 1231f82..f1a552b 100644 --- a/packages/contracts/src/mail.ts +++ b/packages/contracts/src/mail.ts @@ -55,8 +55,7 @@ const accountCommon = { export const mailAccountInputSchema = z.discriminatedUnion('kind', [ z.object({ kind: z.literal('imap-smtp'), - /** zod 默认 email 正则要求顶级域至少两个字母(`.c` 会被拒);邮箱地址理应更宽 —— 改用 html5Email 正则 */ - address: z.email({ pattern: z.regexes.html5Email }), + address: z.email(), ...accountCommon, settings: imapSmtpSettingsSchema.prefault({}), /** 只写不读:缺省 = 不改(与 LLM 密钥同款) */ @@ -179,9 +178,9 @@ export const mailSendInputSchema = z.object({ accountId: z.string().optional(), /** 指定发件地址(channel 用):必须对上一个已启用账号,不静默回落 */ from: z.string().optional(), - to: z.array(z.email({ pattern: z.regexes.html5Email })).min(1), - cc: z.array(z.email({ pattern: z.regexes.html5Email })).default([]), - bcc: z.array(z.email({ pattern: z.regexes.html5Email })).default([]), + to: z.array(z.email()).min(1), + cc: z.array(z.email()).default([]), + bcc: z.array(z.email()).default([]), subject: z.string().min(1), text: z.string().optional(), html: z.string().optional(),