Skip to content

Commit

Permalink
feat: add more lenient address list parsing for MySQL lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
d--j committed Apr 17, 2023
1 parent d00494f commit 53ded4f
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 43 deletions.
32 changes: 32 additions & 0 deletions addr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package srsmilter

import (
"net/mail"
"strings"
"unicode"
)

func split(email string) (string, Domain) {
at := strings.LastIndexByte(email, '@')
if at < 0 {
return email, ""
}
return email[:at], ToDomain(email[at+1:])
}

func parseAddressList(in string) (list []*mail.Address, err error) {
parts := strings.FieldsFunc(in, func(r rune) bool {
return r == ',' || unicode.IsSpace(r) || r == '\r' || r == '\n'
})
for _, p := range parts {
if len(p) == 0 {
continue
}
if a, err := mail.ParseAddress(p); err != nil {
return nil, err
} else {
list = append(list, a)
}
}
return list, nil
}
59 changes: 59 additions & 0 deletions addr_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package srsmilter

import (
"net/mail"
"reflect"
"testing"
)

func Test_split(t *testing.T) {
tests := []struct {
name string
email string
wantLocal string
wantDomain Domain
}{
{"empty", "", "", ""},
{"without domain", "root", "root", ""},
{"with domain", "root@localhost", "root", ToDomain("localhost")},
{"with two ats", "root@crazy@localhost", "root@crazy", ToDomain("localhost")},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotLocal, gotDomain := split(tt.email)
if gotLocal != tt.wantLocal {
t.Errorf("split() gotLocal = %v, want %v", gotLocal, tt.wantLocal)
}
if gotDomain != tt.wantDomain {
t.Errorf("split() gotDomain = %v, want %v", gotDomain, tt.wantDomain)
}
})
}
}

func Test_parseAddressList(t *testing.T) {
tests := []struct {
name string
in string
wantList []*mail.Address
wantErr bool
}{
{"empty", "", nil, false},
{"one", "root@localhost", []*mail.Address{{Address: "root@localhost"}}, false},
{"padded", " ,,,root@localhost\n,", []*mail.Address{{Address: "root@localhost"}}, false},
{"two", " ,,,root@localhost\n,second@example.com\r\r\n", []*mail.Address{{Address: "root@localhost"}, {Address: "second@example.com"}}, false},
{"broken", " ,,,root@localhost\n,second@example.com\rbroken\r\n", nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotList, err := parseAddressList(tt.in)
if (err != nil) != tt.wantErr {
t.Errorf("parseAddressList() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotList, tt.wantList) {
t.Errorf("parseAddressList() gotList = %v, want %v", gotList, tt.wantList)
}
})
}
}
5 changes: 2 additions & 3 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"database/sql"
"fmt"
"net"
"net/mail"
"strings"

"github.com/d--j/go-milter/mailfilter/addr"
Expand Down Expand Up @@ -97,9 +96,9 @@ func (c *Configuration) ResolveForward(email *addr.RcptTo) (emails []*addr.RcptT
Log.Warn("scan error looking up forwards", "email", email.Addr, "err", err)
return []*addr.RcptTo{email}
}
addresses, err := mail.ParseAddressList(dest)
addresses, err := parseAddressList(dest)
if err != nil {
Log.Warn("parse error looking up forwards", "email", email.Addr, "err", err)
Log.Warn("parse error looking up forwards", "email", email.Addr, "dest", dest, "err", err)
return []*addr.RcptTo{email}
}
for _, a := range addresses {
Expand Down
12 changes: 0 additions & 12 deletions socketmap.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package srsmilter

import (
"strings"
)

func Socketmap(config *Configuration, lookup, key string) (result string, found bool, err error) {
logger := Log.New("sub", "socketmap", "lookup", lookup, "key", key)
if lookup != "decode" {
Expand All @@ -23,11 +19,3 @@ func Socketmap(config *Configuration, lookup, key string) (result string, found
logger.Debug("decoded", "result", email)
return email, true, nil
}

func split(email string) (string, Domain) {
at := strings.LastIndexByte(email, '@')
if at < 0 {
return email, ""
}
return email[:at], ToDomain(email[at+1:])
}
28 changes: 0 additions & 28 deletions socketmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,31 +48,3 @@ func TestSocketmap(t *testing.T) {
})
}
}

func Test_split(t *testing.T) {
type args struct {
email string
}
tests := []struct {
name string
email string
wantLocal string
wantDomain Domain
}{
{"empty", "", "", ""},
{"without domain", "root", "root", ""},
{"with domain", "root@localhost", "root", ToDomain("localhost")},
{"with two ats", "root@crazy@localhost", "root@crazy", ToDomain("localhost")},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotLocal, gotDomain := split(tt.email)
if gotLocal != tt.wantLocal {
t.Errorf("split() gotLocal = %v, want %v", gotLocal, tt.wantLocal)
}
if gotDomain != tt.wantDomain {
t.Errorf("split() gotDomain = %v, want %v", gotDomain, tt.wantDomain)
}
})
}
}

0 comments on commit 53ded4f

Please sign in to comment.