PROJ-92: forwarded_via in Suchtreffern, Detail und Threads; Badge im Portal. PROJ-93: archivmail imap-verify gleicht Message-IDs im IMAP-Postfach mit dem Archiv ab (strikt lesend, nur Zahlen und Ordner:UID). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
136 lines
3.5 KiB
Go
136 lines
3.5 KiB
Go
package mailparser_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"archivmail/pkg/mailparser"
|
|
)
|
|
|
|
func parseRaw(t *testing.T, headers string) *mailparser.ParsedMail {
|
|
t.Helper()
|
|
pm, err := mailparser.Parse([]byte(headers + "Subject: test\r\n\r\nbody\r\n"))
|
|
if err != nil {
|
|
t.Fatalf("Parse: %v", err)
|
|
}
|
|
return pm
|
|
}
|
|
|
|
func TestForwardedVia(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
headers string
|
|
want string
|
|
}{
|
|
{
|
|
name: "forward via cc",
|
|
headers: "Return-Path: <fwd@example.com>\r\n" +
|
|
"From: Carol <carol@example.org>\r\n" +
|
|
"To: dave@example.org\r\n" +
|
|
"Cc: Fwd <fwd@example.com>\r\n",
|
|
want: "fwd@example.com",
|
|
},
|
|
{
|
|
name: "forward via envelope-to",
|
|
headers: "Return-Path: <fwd@example.com>\r\n" +
|
|
"Envelope-To: fwd@example.com\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: dave@example.org\r\n",
|
|
want: "fwd@example.com",
|
|
},
|
|
{
|
|
name: "forward via delivered-to",
|
|
headers: "Return-Path: <fwd@example.com>\r\n" +
|
|
"Delivered-To: fwd@example.com\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: dave@example.org\r\n",
|
|
want: "fwd@example.com",
|
|
},
|
|
{
|
|
name: "forward via bcc",
|
|
headers: "Return-Path: <fwd@example.com>\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: dave@example.org\r\n" +
|
|
"Bcc: fwd@example.com\r\n",
|
|
want: "fwd@example.com",
|
|
},
|
|
{
|
|
name: "return-path equals from",
|
|
headers: "Return-Path: <carol@example.org>\r\n" +
|
|
"From: Carol <carol@example.org>\r\n" +
|
|
"To: dave@example.org, carol@example.org\r\n",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "return-path equals from case-insensitive",
|
|
headers: "Return-Path: <Carol@Example.ORG>\r\n" +
|
|
"From: CAROL@example.org\r\n" +
|
|
"To: carol@example.org\r\n",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "newsletter bounce address not a recipient",
|
|
headers: "Return-Path: <bounce-123@mailer.example.net>\r\n" +
|
|
"From: news@example.net\r\n" +
|
|
"To: dave@example.org\r\n",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "no return-path",
|
|
headers: "From: carol@example.org\r\n" +
|
|
"To: dave@example.org\r\n",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "null return-path",
|
|
headers: "Return-Path: <>\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: dave@example.org\r\n",
|
|
want: "",
|
|
},
|
|
{
|
|
name: "mixed case recipient",
|
|
headers: "Return-Path: <Fwd@Example.COM>\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: FWD@example.com\r\n",
|
|
want: "fwd@example.com",
|
|
},
|
|
{
|
|
name: "multiple recipients",
|
|
headers: "Return-Path: <fwd@example.com>\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: dave@example.org, Erin <erin@example.org>, fwd@example.com\r\n" +
|
|
"Cc: frank@example.org\r\n",
|
|
want: "fwd@example.com",
|
|
},
|
|
{
|
|
name: "multiple recipients without match",
|
|
headers: "Return-Path: <fwd@example.com>\r\n" +
|
|
"From: carol@example.org\r\n" +
|
|
"To: dave@example.org, erin@example.org\r\n" +
|
|
"Cc: frank@example.org\r\n",
|
|
want: "",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := mailparser.ForwardedVia(parseRaw(t, tt.headers)); got != tt.want {
|
|
t.Errorf("ForwardedVia = %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestForwardedViaDirectFields(t *testing.T) {
|
|
if got := mailparser.ForwardedVia(nil); got != "" {
|
|
t.Errorf("nil: got %q", got)
|
|
}
|
|
pm := &mailparser.ParsedMail{
|
|
From: "carol@example.org",
|
|
ReturnPath: "fwd@example.com",
|
|
DeliveryAddresses: []string{"fwd@example.com"},
|
|
}
|
|
if got := mailparser.ForwardedVia(pm); got != "fwd@example.com" {
|
|
t.Errorf("delivery address: got %q", got)
|
|
}
|
|
}
|