feat(mail): implement resolveThreadID with References fallback
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -283,6 +283,42 @@ func (w *IMAPWatcher) fetchUnseen(c *imapclient.Client) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveThreadID determines the thread_id for a message.
|
||||
// It tries In-Reply-To first, then falls back to References (last-to-first).
|
||||
// Returns the message's own ID if no parent is found.
|
||||
func resolveThreadID(messageID, inReplyTo, references string, lookup func(string) (*database.Task, error)) string {
|
||||
if inReplyTo != "" {
|
||||
if parent, err := lookup(inReplyTo); err == nil && parent != nil {
|
||||
return parent.ThreadID
|
||||
}
|
||||
}
|
||||
|
||||
for _, refID := range parseReferences(references) {
|
||||
if parent, err := lookup(refID); err == nil && parent != nil {
|
||||
return parent.ThreadID
|
||||
}
|
||||
}
|
||||
|
||||
return messageID
|
||||
}
|
||||
|
||||
// parseReferences splits a References header value into individual message IDs,
|
||||
// returned in reverse order (most recent first).
|
||||
func parseReferences(header string) []string {
|
||||
if header == "" {
|
||||
return nil
|
||||
}
|
||||
raw := strings.Fields(header)
|
||||
for i := range raw {
|
||||
raw[i] = strings.TrimSpace(raw[i])
|
||||
}
|
||||
// Reverse: last (most recent) first.
|
||||
for i, j := 0, len(raw)-1; i < j; i, j = i+1, j-1 {
|
||||
raw[i], raw[j] = raw[j], raw[i]
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
||||
// processMessage handles a single fetched email message.
|
||||
func (w *IMAPWatcher) processMessage(c *imapclient.Client, buf *imapclient.FetchMessageBuffer, bodySection *imap.FetchItemBodySection) {
|
||||
env := buf.Envelope
|
||||
|
||||
Reference in New Issue
Block a user