feat(imapx): message dedup key (Message-ID + header fallback)
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
package imapx
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-imap/v2"
|
||||
)
|
||||
|
||||
func MessageKey(env *imap.Envelope, size int64) string {
|
||||
if env != nil && env.MessageID != "" {
|
||||
return env.MessageID
|
||||
}
|
||||
var b strings.Builder
|
||||
if env != nil {
|
||||
b.WriteString(addrList(env.From))
|
||||
b.WriteByte('|')
|
||||
b.WriteString(addrList(env.To))
|
||||
b.WriteByte('|')
|
||||
b.WriteString(env.Subject)
|
||||
b.WriteByte('|')
|
||||
b.WriteString(env.Date.UTC().Format("2006-01-02T15:04:05Z"))
|
||||
}
|
||||
b.WriteByte('|')
|
||||
fmt.Fprintf(&b, "%d", size)
|
||||
sum := md5.Sum([]byte(b.String()))
|
||||
return fmt.Sprintf("h:%x", sum)
|
||||
}
|
||||
|
||||
func addrList(addrs []imap.Address) string {
|
||||
parts := make([]string, 0, len(addrs))
|
||||
for _, a := range addrs {
|
||||
parts = append(parts, a.Mailbox+"@"+a.Host)
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package imapx
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-imap/v2"
|
||||
)
|
||||
|
||||
func TestMessageKeyPrefersMessageID(t *testing.T) {
|
||||
env := &imap.Envelope{MessageID: "<abc@host>"}
|
||||
if got := MessageKey(env, 100); got != "<abc@host>" {
|
||||
t.Fatalf("got %q, want <abc@host>", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageKeyFallbackStable(t *testing.T) {
|
||||
env := &imap.Envelope{
|
||||
Subject: "Hi",
|
||||
Date: time.Unix(1700000000, 0).UTC(),
|
||||
From: []imap.Address{{Mailbox: "a", Host: "x.com"}},
|
||||
To: []imap.Address{{Mailbox: "b", Host: "y.com"}},
|
||||
}
|
||||
k1 := MessageKey(env, 42)
|
||||
k2 := MessageKey(env, 42)
|
||||
if k1 != k2 {
|
||||
t.Fatal("fallback key must be deterministic")
|
||||
}
|
||||
if MessageKey(env, 43) == k1 {
|
||||
t.Fatal("different size must change key")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user