diff --git a/helpers/inbound/go.mod b/helpers/inbound/go.mod new file mode 100644 index 00000000..ab6b0451 --- /dev/null +++ b/helpers/inbound/go.mod @@ -0,0 +1,11 @@ +module inbound + +go 1.19 + +require github.com/stretchr/testify v1.8.4 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/helpers/inbound/go.sum b/helpers/inbound/go.sum new file mode 100644 index 00000000..fa4b6e68 --- /dev/null +++ b/helpers/inbound/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers/inbound/inbound.go b/helpers/inbound/inbound.go index ba7f0b89..ab991880 100644 --- a/helpers/inbound/inbound.go +++ b/helpers/inbound/inbound.go @@ -6,6 +6,7 @@ import ( "io" "mime" "mime/multipart" + "mime/quotedprintable" "net/http" "strings" ) @@ -167,10 +168,34 @@ func (email *ParsedEmail) parseRawEmail(rawEmail string) error { return err } + // if Content-Type is not multipart just set the whole email + if raw == nil { + if len(sections) < 2 { + return nil + } + + wholeEmail := sections[1] + // decode if needed + if email.Headers["Content-Transfer-Encoding"] == "quoted-printable" { + decoded, err := io.ReadAll(quotedprintable.NewReader(strings.NewReader(wholeEmail))) + if err != nil { + return err + } + wholeEmail = string(decoded) + } + + email.Body[email.Headers["Content-Type"]] = wholeEmail + return nil + } + for { emailPart, err := raw.NextPart() - if err == io.EOF { - return nil + // Check for both io.EOF and the wrapped multipart: NextPart: EOF + if err == io.EOF || (err != nil && err.Error() == "multipart: NextPart: EOF") { + break + } + if err != nil { + return err } rawEmailBody, err := parseMultipart(emailPart, emailPart.Header.Get("Content-Type")) if err != nil { @@ -179,9 +204,13 @@ func (email *ParsedEmail) parseRawEmail(rawEmail string) error { if rawEmailBody != nil { for { emailBodyPart, err := rawEmailBody.NextPart() - if err == io.EOF { + // Check for both io.EOF and the wrapped multipart: NextPart: EOF + if err == io.EOF || (err != nil && err.Error() == "multipart: NextPart: EOF") { break } + if err != nil { + return err + } header := emailBodyPart.Header.Get("Content-Type") b, err := io.ReadAll(emailPart) if err != nil { @@ -206,6 +235,7 @@ func (email *ParsedEmail) parseRawEmail(rawEmail string) error { email.Body[header] = string(b) } } + return nil } func parseMultipart(body io.Reader, contentType string) (*multipart.Reader, error) {