From a80feb00b82ff6d7c2e7dbe2914564dc13e05e5f Mon Sep 17 00:00:00 2001 From: miraclesu Date: Mon, 25 Jan 2016 18:11:50 +0800 Subject: [PATCH 1/5] Fix utils mail from field can't including Chinese bug --- utils/mail.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/utils/mail.go b/utils/mail.go index 1d80a039..bebce610 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -231,11 +231,10 @@ func (e *Email) Send() error { if e.From == "" || len(to) == 0 { return errors.New("Must specify at least one From address and one To address") } - from, err := mail.ParseAddress(e.From) + from, err := mail.ParseAddress(e.Username) if err != nil { return err } - e.From = from.String() raw, err := e.Bytes() if err != nil { return err From 4de91f675da1c4a68360e1298ab362c91b8c4068 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Mon, 25 Jan 2016 22:29:45 +0800 Subject: [PATCH 2/5] show from when Config from is empty --- utils/mail.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/utils/mail.go b/utils/mail.go index bebce610..07043149 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -74,9 +74,6 @@ func NewEMail(config string) *Email { if err != nil { return nil } - if e.From == "" { - e.From = e.Username - } return e } @@ -228,13 +225,19 @@ func (e *Email) Send() error { to := make([]string, 0, len(e.To)+len(e.Cc)+len(e.Bcc)) to = append(append(append(to, e.To...), e.Cc...), e.Bcc...) // Check to make sure there is at least one recipient and one "From" address - if e.From == "" || len(to) == 0 { - return errors.New("Must specify at least one From address and one To address") + if len(to) == 0 { + return errors.New("Must specify at least one To address") } + from, err := mail.ParseAddress(e.Username) if err != nil { return err } + + if len(e.From) == 0 { + e.From = from.String() + } + raw, err := e.Bytes() if err != nil { return err From 5930f27da7d776c2ddf23b53287a1967dbb85a4e Mon Sep 17 00:00:00 2001 From: miraclesu Date: Mon, 25 Jan 2016 22:55:40 +0800 Subject: [PATCH 3/5] Fix mail Chinese subject garbled bug --- utils/mail.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/utils/mail.go b/utils/mail.go index 07043149..125fddd5 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -237,6 +237,9 @@ func (e *Email) Send() error { if len(e.From) == 0 { e.From = from.String() } + // use mail's RFC 5322 to encode any string + sub := mail.Address{e.Subject, ""} + e.Subject = strings.Trim(sub.String(), " <@>") raw, err := e.Bytes() if err != nil { From f26d360ec9b82d58389799dfa3ee1d2383894c6a Mon Sep 17 00:00:00 2001 From: miraclesu Date: Tue, 26 Jan 2016 10:33:48 +0800 Subject: [PATCH 4/5] Fix vet fail --- utils/mail.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/utils/mail.go b/utils/mail.go index 125fddd5..0a961204 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -235,11 +235,11 @@ func (e *Email) Send() error { } if len(e.From) == 0 { - e.From = from.String() + e.From = e.Username } - // use mail's RFC 5322 to encode any string - sub := mail.Address{e.Subject, ""} - e.Subject = strings.Trim(sub.String(), " <@>") + // use mail's RFC 2047 to encode any string + sub := mail.Address{Name: e.Subject, Address: ""} + e.Subject = strings.TrimRight(sub.String(), " <@>") raw, err := e.Bytes() if err != nil { From bf870eb9a26af47b5bdfee9e3cb2ded180e80247 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Tue, 26 Jan 2016 20:50:03 +0800 Subject: [PATCH 5/5] mv mime.QEncoding.Encode logic to mail it is named qEncode --- utils/mail.go | 76 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/utils/mail.go b/utils/mail.go index 0a961204..10555a0a 100644 --- a/utils/mail.go +++ b/utils/mail.go @@ -31,10 +31,13 @@ import ( "path/filepath" "strconv" "strings" + "sync" ) const ( maxLineLength = 76 + + upperhex = "0123456789ABCDEF" ) // Email is the type used for email messages @@ -238,8 +241,7 @@ func (e *Email) Send() error { e.From = e.Username } // use mail's RFC 2047 to encode any string - sub := mail.Address{Name: e.Subject, Address: ""} - e.Subject = strings.TrimRight(sub.String(), " <@>") + e.Subject = qEncode("utf-8", e.Subject) raw, err := e.Bytes() if err != nil { @@ -347,3 +349,73 @@ func base64Wrap(w io.Writer, b []byte) { w.Write(out) } } + +// Encode returns the encoded-word form of s. If s is ASCII without special +// characters, it is returned unchanged. The provided charset is the IANA +// charset name of s. It is case insensitive. +// RFC 2047 encoded-word +func qEncode(charset, s string) string { + if !needsEncoding(s) { + return s + } + return encodeWord(charset, s) +} + +func needsEncoding(s string) bool { + for _, b := range s { + if (b < ' ' || b > '~') && b != '\t' { + return true + } + } + return false +} + +// encodeWord encodes a string into an encoded-word. +func encodeWord(charset, s string) string { + buf := getBuffer() + + buf.WriteString("=?") + buf.WriteString(charset) + buf.WriteByte('?') + buf.WriteByte('q') + buf.WriteByte('?') + + enc := make([]byte, 3) + for i := 0; i < len(s); i++ { + b := s[i] + switch { + case b == ' ': + buf.WriteByte('_') + case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_': + buf.WriteByte(b) + default: + enc[0] = '=' + enc[1] = upperhex[b>>4] + enc[2] = upperhex[b&0x0f] + buf.Write(enc) + } + } + buf.WriteString("?=") + + es := buf.String() + putBuffer(buf) + return es +} + +var bufPool = sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + +func getBuffer() *bytes.Buffer { + return bufPool.Get().(*bytes.Buffer) +} + +func putBuffer(buf *bytes.Buffer) { + if buf.Len() > 1024 { + return + } + buf.Reset() + bufPool.Put(buf) +}