diff --git a/message.go b/message.go index 58e464b..8b3d6c6 100644 --- a/message.go +++ b/message.go @@ -5,8 +5,10 @@ import ( "crypto/rand" "encoding/base64" "io" + "io/ioutil" "log" "mime" + "net/mail" "strings" "time" ) @@ -283,39 +285,23 @@ func PathFromString(path string) *Path { // ContentFromString parses SMTP content into separate headers and body func ContentFromString(data string) *Content { logf("Parsing Content from string: '%s'", data) - x := strings.SplitN(data, "\r\n\r\n", 2) - h := make(map[string][]string, 0) - - // FIXME this fails if the message content has no headers - specifically, - // if it doesn't contain \r\n\r\n - - if len(x) == 2 { - headers, body := x[0], x[1] - hdrs := strings.Split(headers, "\r\n") - var lastHdr = "" - for _, hdr := range hdrs { - if lastHdr != "" && (strings.HasPrefix(hdr, " ") || strings.HasPrefix(hdr, "\t")) { - h[lastHdr][len(h[lastHdr])-1] = h[lastHdr][len(h[lastHdr])-1] + hdr - } else if strings.Contains(hdr, ": ") { - y := strings.SplitN(hdr, ": ", 2) - key, value := y[0], y[1] - // TODO multiple header fields - h[key] = []string{value} - lastHdr = key - } else if len(hdr) > 0 { - logf("Found invalid header: '%s'", hdr) - } - } - return &Content{ - Size: len(data), - Headers: h, - Body: body, - } + + email, err := mail.ReadMessage(strings.NewReader(data)) + if err != nil { + logf(err.Error()) + return nil } + + body, err := ioutil.ReadAll(email.Body) + if err != nil { + logf(err.Error()) + return nil + } + return &Content{ Size: len(data), - Headers: h, - Body: x[0], + Headers: email.Header, + Body: string(body), } } diff --git a/message_test.go b/message_test.go index 32794a7..6a868ba 100644 --- a/message_test.go +++ b/message_test.go @@ -1,9 +1,36 @@ package data import ( + "reflect" "testing" ) +func TestContentFromString(t *testing.T) { + // Long headers can be folded across multiple lines. + get := ContentFromString( + "To: foo@bar.com\r\n" + + "X-Foo-Digest:\r\n" + + " f71324948a11ad59c9f52aa27a1f194391968da6b7623186fedd0d190fd2f484\r\n" + + "\r\n" + + "body\r\n", + ) + + expect := &Content{ + Body: "body\r\n", + Headers: map[string][]string{ + "To": []string{"foo@bar.com"}, + "X-Foo-Digest": []string{ + "f71324948a11ad59c9f52aa27a1f194391968da6b7623186fedd0d190fd2f484", + }, + }, + Size: 107, + } + + if !reflect.DeepEqual(get, expect) { + t.Fatal("ContentFromString expect", expect, "but get", get) + } +} + func TestExtractBoundary(t *testing.T) { contents := []struct { content string