Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions email.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
"strings"
"time"
"unicode"

"golang.org/x/text/encoding/htmlindex"
"golang.org/x/text/transform"
)

const (
Expand Down Expand Up @@ -90,7 +93,7 @@ func handleAddressList(v []string) []string {
for _, a := range v {
w := strings.Split(a, ",")
for _, addr := range w {
decodedAddr, err := (&mime.WordDecoder{}).DecodeHeader(strings.TrimSpace(addr))
decodedAddr, err := wordDecoder.DecodeHeader(strings.TrimSpace(addr))
if err == nil {
res = append(res, decodedAddr)
} else {
Expand Down Expand Up @@ -118,7 +121,7 @@ func NewEmailFromReader(r io.Reader) (*Email, error) {
switch h {
case "Subject":
e.Subject = v[0]
subj, err := (&mime.WordDecoder{}).DecodeHeader(e.Subject)
subj, err := wordDecoder.DecodeHeader(e.Subject)
if err == nil && len(subj) > 0 {
e.Subject = subj
}
Expand All @@ -137,7 +140,7 @@ func NewEmailFromReader(r io.Reader) (*Email, error) {
delete(hdrs, h)
case "From":
e.From = v[0]
fr, err := (&mime.WordDecoder{}).DecodeHeader(e.From)
fr, err := wordDecoder.DecodeHeader(e.From)
if err == nil && len(fr) > 0 {
e.From = fr
}
Expand Down Expand Up @@ -216,7 +219,7 @@ func parseMIMEParts(hs textproto.MIMEHeader, b io.Reader) ([]*part, error) {
if _, ok := p.Header["Content-Type"]; !ok {
p.Header.Set("Content-Type", defaultContentType)
}
subct, _, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
subct, subps, err := mime.ParseMediaType(p.Header.Get("Content-Type"))
if err != nil {
return ps, err
}
Expand All @@ -227,12 +230,23 @@ func parseMIMEParts(hs textproto.MIMEHeader, b io.Reader) ([]*part, error) {
}
ps = append(ps, sps...)
} else {
var reader io.Reader
reader = p
var reader io.Reader = p

const cte = "Content-Transfer-Encoding"
if p.Header.Get(cte) == "base64" {
switch p.Header.Get(cte) {
case "quoted-printable":
reader = quotedprintable.NewReader(reader)
case "base64":
reader = base64.NewDecoder(base64.StdEncoding, reader)
}

if strings.HasPrefix(subct, "text") && subps["charset"] != "" {
transReader, err := wordDecoder.CharsetReader(subps["charset"], reader)
if err == nil {
reader = transReader
}
}

// Otherwise, just append the part to the list
// Copy the part data into the buffer
if _, err := io.Copy(&buf, reader); err != nil {
Expand Down Expand Up @@ -807,3 +821,13 @@ func generateMessageID() (string, error) {
msgid := fmt.Sprintf("<%d.%d.%d@%s>", t, pid, rint, h)
return msgid, nil
}

var wordDecoder = &mime.WordDecoder{
CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
encoding, err := htmlindex.Get(charset)
if err != nil {
return nil, err
}
return transform.NewReader(input, encoding.NewDecoder()), nil
},
}