Archived
mail 接线两处收紧:入站线程取根不取最近一跳(否则跑一个来回①级归属就落空);附件没给 uploadRef 当场判 invalid,不静默丢掉
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TM4kUBvekALu9qqmp7D3wr
This commit is contained in:
@@ -18,9 +18,18 @@ import {
|
||||
} from '@modules/mail';
|
||||
import type { ToolHandler } from '@modules/toolbox';
|
||||
|
||||
/** mail 的入站详情 → channel 的 InboundMail:只带存下来的附件;线程 = In-Reply-To ⊃ References 末项 */
|
||||
/**
|
||||
* mail 的入站详情 → channel 的 InboundMail:只带存下来的附件。
|
||||
*
|
||||
* **线程取的是根,不是最近一跳**:我方出站登记的 threadId 恒是这一串的**首封**
|
||||
* (`channelTransport` 回的是 `input.threadId ?? messageId`,channel 据此 `recordOutbound`),
|
||||
* 而归属解析①级是精确等值比对。若这里取 `inReplyTo`(最近一跳),跑一个来回就漂:
|
||||
* 我方 M1 → 客户回 M1(命中)→ 我方再回(实际 M2、仍记在 M1 名下)→ 客户回 M2 →
|
||||
* 取到 M2,而库里从没记过 M2 ⇒ ①级落空,退到③地址+时间窗。
|
||||
* `references[0]` 才稳定:客户端续链时首项恒是首封;客户端只给 In-Reply-To 时退回它。
|
||||
*/
|
||||
export function toInboundMail(mail: MailInboundDetail): InboundMail {
|
||||
const threadId = mail.inReplyTo ?? mail.references.at(-1);
|
||||
const threadId = mail.references[0] ?? mail.inReplyTo ?? undefined;
|
||||
return {
|
||||
messageId: mail.messageId,
|
||||
...(threadId === undefined ? {} : { threadId }),
|
||||
@@ -80,7 +89,8 @@ function attachmentsOf(value: unknown): MailSendInput['attachments'] {
|
||||
if (typeof v !== 'object' || v === null) return [];
|
||||
const a = v as Record<string, unknown>;
|
||||
const uploadRef = typeof a['uploadRef'] === 'string' && a['uploadRef'] !== '' ? a['uploadRef'] : undefined;
|
||||
if (uploadRef === undefined) return [];
|
||||
// 没给 uploadRef 的附件**不静默丢掉**:活动说「带上 q.pdf」,信发了附件没了还回 queued:true,是界面撒谎
|
||||
if (uploadRef === undefined) throw new MailSendInvalidError([`附件 ${String(a['name'] ?? '(无名)')} 没给 uploadRef`]);
|
||||
const name = typeof a['name'] === 'string' && a['name'] !== '' ? a['name'] : uploadRef;
|
||||
return [{ name, contentType: 'application/octet-stream', uploadRef }];
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user