Repository: jhillyerd/enmime
Pull request #239 (2022-03-14 17:13:16)

fix: use extended parser after fixing address list
Use extended parser for parsing "fixed" address list


Patch:
diff --git a/header.go b/header.go
index d1d7845..52591ed 100644
--- a/header.go
+++ b/header.go
@@ -85,7 +85,7 @@ func ParseAddressList(list string) ([]*mail.Address, error) {
 		switch err.Error() {
 		case "mail: expected comma":
 			// Attempt to add commas and parse again.
-			return mail.ParseAddressList(stringutil.EnsureCommaDelimitedAddresses(list))
+			return parser.ParseList(stringutil.EnsureCommaDelimitedAddresses(list))
 		case "mail: no address":
 			return nil, mail.ErrHeaderNotPresent
 		}
diff --git a/internal/stringutil/addr.go b/internal/stringutil/addr.go
index 660aba6..c3eaa42 100644
--- a/internal/stringutil/addr.go
+++ b/internal/stringutil/addr.go
@@ -35,7 +35,7 @@ func EnsureCommaDelimitedAddresses(s string) string {
 	inDomain := false
 	escapeSequence := false
 	sb := strings.Builder{}
-	for _, r := range s {
+	for i, r := range s {
 		if escapeSequence {
 			escapeSequence = false
 			sb.WriteRune(r)
@@ -60,8 +60,14 @@ func EnsureCommaDelimitedAddresses(s string) string {
 			}
 			if inDomain {
 				if r == ';' {
-					sb.WriteRune(r)
-					break
+					inDomain = false
+					if i == len(s)-1 {
+						// omit trailing semicolon
+						continue
+					}
+
+					sb.WriteRune(',')
+					continue
 				}
 				if r == ',' {
 					inDomain = false


Test patch:
diff --git a/envelope_test.go b/envelope_test.go
index 0854807..8d9d4f5 100644
--- a/envelope_test.go
+++ b/envelope_test.go
@@ -789,6 +789,20 @@ Message body
 				Address: "marczak@inbucket.com",
 			}},
 		},
+		{
+			"a@example.com;b@example.com",
+			[]*mail.Address{
+				{Name: "", Address: "a@example.com"},
+				{Name: "", Address: "b@example.com"},
+			},
+		},
+		{
+			`"Joe @ Company" <joe@company.com>;<other@company.com>`,
+			[]*mail.Address{
+				{Name: "Joe @ Company", Address: "joe@company.com"},
+				{Name: "", Address: "other@company.com"},
+			},
+		},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.input, func(t *testing.T) {
diff --git a/header_test.go b/header_test.go
index 322e8e9..e31234b 100644
--- a/header_test.go
+++ b/header_test.go
@@ -102,6 +102,19 @@ func TestParseAddressListResult(t *testing.T) {
 				},
 			},
 		},
+		{
+			`=?big5?Q?ext-encoding-without-comma?= <ext-encoding-wo-comma@example.com> <other@example.com>`,
+			[]*mail.Address{
+				{
+					Name:    "ext-encoding-without-comma",
+					Address: "ext-encoding-wo-comma@example.com",
+				},
+				{
+					Name:    "",
+					Address: "other@example.com",
+				},
+			},
+		},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.input, func(t *testing.T) {
diff --git a/internal/stringutil/addr_test.go b/internal/stringutil/addr_test.go
index b886fec..dcff316 100644
--- a/internal/stringutil/addr_test.go
+++ b/internal/stringutil/addr_test.go
@@ -62,11 +62,11 @@ func TestCommaDelimitedAddressLists(t *testing.T) {
 		},
 		{
 			have: `Joe Company:Joey <joe@company.com> John <other@company.com>;`,
-			want: `Joe Company:Joey <joe@company.com>, John <other@company.com>;`,
+			want: `Joe Company:Joey <joe@company.com>, John <other@company.com>`,
 		},
 		{
 			have: `Joe Company:Joey <joe@company.com> John <other@company.com>; Jimmy John <jimmy.john@company.com>`,
-			want: `Joe Company:Joey <joe@company.com>, John <other@company.com>;`,
+			want: `Joe Company:Joey <joe@company.com>, John <other@company.com>, Jimmy John <jimmy.john@company.com>`,
 		},
 		{
 			have: `Joe Company <joe@company.com> John Company <other@company.com>`,
@@ -94,17 +94,27 @@ func TestCommaDelimitedAddressLists(t *testing.T) {
 		},
 		{
 			have: `A Group:Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;`,
-			want: `A Group:Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;`,
+			want: `A Group:Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>`,
 		},
 		{
 			have: `A Group:Ed Jones <c@a.test> joe@where.test John <jdoe@one.test>;`,
-			want: `A Group:Ed Jones <c@a.test>, joe@where.test, John <jdoe@one.test>;`,
+			want: `A Group:Ed Jones <c@a.test>, joe@where.test, John <jdoe@one.test>`,
+		},
+		{
+			have: "a@example.com;b@example.com",
+			want: "a@example.com,b@example.com",
+		},
+		{
+			have: `"Joe @ Company" <joe@company.com>;<other@company.com>`,
+			want: `"Joe @ Company" <joe@company.com>,<other@company.com>`,
 		},
 	}
-	for i := range testData {
-		v := stringutil.EnsureCommaDelimitedAddresses(testData[i].have)
-		if testData[i].want != v {
-			t.Errorf("got: %q\nwant: %q", v, testData[i].want)
-		}
+	for _, tt := range testData {
+		t.Run(tt.have, func(t *testing.T) {
+			v := stringutil.EnsureCommaDelimitedAddresses(tt.have)
+			if tt.want != v {
+				t.Errorf("got: %q\nwant: %q", v, tt.want)
+			}
+		})
 	}
 }