diff --git a/export.go b/export.go index 1f56cd3..65f60fc 100644 --- a/export.go +++ b/export.go @@ -5,10 +5,9 @@ import ( "encoding/base64" "io" "mime/multipart" + "mime/quotedprintable" "net/mail" "time" - - "gopkg.in/alexcesaro/quotedprintable.v2" ) // Export converts the message into a net/mail.Message. @@ -169,8 +168,9 @@ func (w *messageWriter) writeBody(body []byte, enc Encoding) { } else if enc == Unencoded { subWriter.Write(body) } else { - writer := quotedprintable.NewEncoder(newQpLineWriter(subWriter)) + writer := quotedprintable.NewWriter(subWriter) writer.Write(body) + writer.Close() } } @@ -207,56 +207,3 @@ func (w *base64LineWriter) Write(p []byte) (int, error) { return n + len(p), nil } - -// qpLineWriter limits text encoded in quoted-printable to 76 characters per -// line -type qpLineWriter struct { - w io.Writer - lineLen int -} - -func newQpLineWriter(w io.Writer) *qpLineWriter { - return &qpLineWriter{w: w} -} - -func (w *qpLineWriter) Write(p []byte) (int, error) { - n := 0 - for len(p) > 0 { - // If the text is not over the limit, write everything - if len(p) < maxLineLen-w.lineLen { - w.w.Write(p) - w.lineLen += len(p) - return n + len(p), nil - } - - i := bytes.IndexAny(p[:maxLineLen-w.lineLen+2], "\n") - // If there is a newline before the limit, write the end of the line - if i != -1 && (i != maxLineLen-w.lineLen+1 || p[i-1] == '\r') { - w.w.Write(p[:i+1]) - p = p[i+1:] - n += i + 1 - w.lineLen = 0 - continue - } - - // Quoted-printable text must not be cut between an equal sign and the - // two following characters - var toWrite int - if maxLineLen-w.lineLen-2 >= 0 && p[maxLineLen-w.lineLen-2] == '=' { - toWrite = maxLineLen - w.lineLen - 2 - } else if p[maxLineLen-w.lineLen-1] == '=' { - toWrite = maxLineLen - w.lineLen - 1 - } else { - toWrite = maxLineLen - w.lineLen - } - - // Insert the newline where it is needed - w.w.Write(p[:toWrite]) - w.w.Write([]byte("=\r\n")) - p = p[toWrite:] - n += toWrite - w.lineLen = 0 - } - - return n, nil -} diff --git a/gomail.go b/gomail.go index 734d881..6612e97 100644 --- a/gomail.go +++ b/gomail.go @@ -11,8 +11,6 @@ import ( "path/filepath" "sync" "time" - - "gopkg.in/alexcesaro/quotedprintable.v2" ) // Message represents an email. @@ -23,7 +21,7 @@ type Message struct { embedded []*File charset string encoding Encoding - hEncoder *quotedprintable.HeaderEncoder + hEncoder mime.WordEncoder } type header map[string][]string @@ -44,13 +42,11 @@ func NewMessage(settings ...MessageSetting) *Message { msg.applySettings(settings) - var e quotedprintable.Encoding if msg.encoding == Base64 { - e = quotedprintable.B + msg.hEncoder = mime.BEncoding } else { - e = quotedprintable.Q + msg.hEncoder = mime.QEncoding } - msg.hEncoder = e.NewHeaderEncoder(msg.charset) return msg } @@ -104,7 +100,7 @@ const ( // SetHeader sets a value to the given header field. func (msg *Message) SetHeader(field string, value ...string) { for i := range value { - value[i] = encodeHeader(msg.hEncoder, value[i]) + value[i] = msg.encodeHeader(value[i]) } msg.header[field] = value } @@ -134,16 +130,13 @@ func (msg *Message) FormatAddress(address, name string) string { buf := getBuffer() defer putBuffer(buf) - if !quotedprintable.NeedsEncoding(name) { + enc := msg.encodeHeader(name) + if enc == name { quote(buf, name) + } else if hasSpecials(name) { + buf.WriteString(mime.BEncoding.Encode(msg.charset, name)) } else { - var n string - if hasSpecials(name) { - n = encodeHeader(quotedprintable.B.NewHeaderEncoder(msg.charset), name) - } else { - n = encodeHeader(msg.hEncoder, name) - } - buf.WriteString(n) + buf.WriteString(enc) } buf.WriteString(" <") buf.WriteString(address) @@ -307,12 +300,8 @@ func hasSpecials(text string) bool { return false } -func encodeHeader(enc *quotedprintable.HeaderEncoder, value string) string { - if !quotedprintable.NeedsEncoding(value) { - return value - } - - return enc.Encode(value) +func (msg *Message) encodeHeader(value string) string { + return msg.hEncoder.Encode(msg.charset, value) } var bufPool = sync.Pool{ diff --git a/gomail_test.go b/gomail_test.go index 087b7c9..30d0eeb 100644 --- a/gomail_test.go +++ b/gomail_test.go @@ -38,14 +38,14 @@ func TestMessage(t *testing.T) { "tobis@example.com", "cc@example.com", }, - content: "From: =?UTF-8?Q?Se=C3=B1or_From?= \r\n" + - "To: =?UTF-8?Q?Se=C3=B1or_To?= , tobis@example.com\r\n" + + content: "From: =?UTF-8?q?Se=C3=B1or_From?= \r\n" + + "To: =?UTF-8?q?Se=C3=B1or_To?= , tobis@example.com\r\n" + "Cc: \"A, B\" \r\n" + - "X-To: =?UTF-8?B?w6AsIGI=?= \r\n" + + "X-To: =?UTF-8?b?w6AsIGI=?= \r\n" + "X-Date: Wed, 25 Jun 2014 17:46:00 +0000\r\n" + "X-Date-2: Wed, 25 Jun 2014 17:46:00 +0000\r\n" + - "X-Headers: Test, =?UTF-8?Q?Caf=C3=A9?=\r\n" + - "Subject: =?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=\r\n" + + "X-Headers: Test, =?UTF-8?q?Caf=C3=A9?=\r\n" + + "Subject: =?UTF-8?q?=C2=A1Hola,_se=C3=B1or!?=\r\n" + "Content-Type: text/plain; charset=UTF-8\r\n" + "Content-Transfer-Encoding: quoted-printable\r\n" + "\r\n" + @@ -90,7 +90,7 @@ func TestCustomMessage(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Subject: =?ISO-8859-1?B?Q2Fmw6k=?=\r\n" + + "Subject: =?ISO-8859-1?b?Q2Fmw6k=?=\r\n" + "Content-Type: text/html; charset=ISO-8859-1\r\n" + "Content-Transfer-Encoding: base64\r\n" + "\r\n" + @@ -114,7 +114,7 @@ func TestUnencodedMessage(t *testing.T) { to: []string{"to@example.com"}, content: "From: from@example.com\r\n" + "To: to@example.com\r\n" + - "Subject: =?UTF-8?Q?Caf=C3=A9?=\r\n" + + "Subject: =?UTF-8?q?Caf=C3=A9?=\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Content-Transfer-Encoding: 8bit\r\n" + "\r\n" + @@ -439,13 +439,13 @@ func TestQpLineLength(t *testing.T) { msg.SetHeader("From", "from@example.com") msg.SetHeader("To", "to@example.com") msg.SetBody("text/plain", - strings.Repeat("0", 77)+"\r\n"+ - strings.Repeat("0", 76)+"à\r\n"+ + strings.Repeat("0", 76)+"\r\n"+ strings.Repeat("0", 75)+"à\r\n"+ strings.Repeat("0", 74)+"à\r\n"+ strings.Repeat("0", 73)+"à\r\n"+ - strings.Repeat("0", 76)+"\r\n"+ - strings.Repeat("0", 77)+"\n") + strings.Repeat("0", 72)+"à\r\n"+ + strings.Repeat("0", 75)+"\r\n"+ + strings.Repeat("0", 76)+"\n") want := message{ from: "from@example.com", @@ -455,13 +455,13 @@ func TestQpLineLength(t *testing.T) { "Content-Type: text/plain; charset=UTF-8\r\n" + "Content-Transfer-Encoding: quoted-printable\r\n" + "\r\n" + - strings.Repeat("0", 76) + "=\r\n0\r\n" + - strings.Repeat("0", 76) + "=\r\n=C3=A0\r\n" + + strings.Repeat("0", 75) + "=\r\n0\r\n" + strings.Repeat("0", 75) + "=\r\n=C3=A0\r\n" + strings.Repeat("0", 74) + "=\r\n=C3=A0\r\n" + - strings.Repeat("0", 73) + "=C3=\r\n=A0\r\n" + - strings.Repeat("0", 76) + "\r\n" + - strings.Repeat("0", 76) + "=\r\n0\n", + strings.Repeat("0", 73) + "=\r\n=C3=A0\r\n" + + strings.Repeat("0", 72) + "=C3=\r\n=A0\r\n" + + strings.Repeat("0", 75) + "\r\n" + + strings.Repeat("0", 75) + "=\r\n0\r\n", } testMessage(t, msg, 0, want)