Used the new quotedprintable package from the standard library
This commit is contained in:
parent
11b919ab49
commit
a7fe250544
59
export.go
59
export.go
|
@ -5,10 +5,9 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
|
"mime/quotedprintable"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/alexcesaro/quotedprintable.v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Export converts the message into a net/mail.Message.
|
// 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 {
|
} else if enc == Unencoded {
|
||||||
subWriter.Write(body)
|
subWriter.Write(body)
|
||||||
} else {
|
} else {
|
||||||
writer := quotedprintable.NewEncoder(newQpLineWriter(subWriter))
|
writer := quotedprintable.NewWriter(subWriter)
|
||||||
writer.Write(body)
|
writer.Write(body)
|
||||||
|
writer.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,56 +207,3 @@ func (w *base64LineWriter) Write(p []byte) (int, error) {
|
||||||
|
|
||||||
return n + len(p), nil
|
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
|
|
||||||
}
|
|
||||||
|
|
33
gomail.go
33
gomail.go
|
@ -11,8 +11,6 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/alexcesaro/quotedprintable.v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Message represents an email.
|
// Message represents an email.
|
||||||
|
@ -23,7 +21,7 @@ type Message struct {
|
||||||
embedded []*File
|
embedded []*File
|
||||||
charset string
|
charset string
|
||||||
encoding Encoding
|
encoding Encoding
|
||||||
hEncoder *quotedprintable.HeaderEncoder
|
hEncoder mime.WordEncoder
|
||||||
}
|
}
|
||||||
|
|
||||||
type header map[string][]string
|
type header map[string][]string
|
||||||
|
@ -44,13 +42,11 @@ func NewMessage(settings ...MessageSetting) *Message {
|
||||||
|
|
||||||
msg.applySettings(settings)
|
msg.applySettings(settings)
|
||||||
|
|
||||||
var e quotedprintable.Encoding
|
|
||||||
if msg.encoding == Base64 {
|
if msg.encoding == Base64 {
|
||||||
e = quotedprintable.B
|
msg.hEncoder = mime.BEncoding
|
||||||
} else {
|
} else {
|
||||||
e = quotedprintable.Q
|
msg.hEncoder = mime.QEncoding
|
||||||
}
|
}
|
||||||
msg.hEncoder = e.NewHeaderEncoder(msg.charset)
|
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
@ -104,7 +100,7 @@ const (
|
||||||
// SetHeader sets a value to the given header field.
|
// SetHeader sets a value to the given header field.
|
||||||
func (msg *Message) SetHeader(field string, value ...string) {
|
func (msg *Message) SetHeader(field string, value ...string) {
|
||||||
for i := range value {
|
for i := range value {
|
||||||
value[i] = encodeHeader(msg.hEncoder, value[i])
|
value[i] = msg.encodeHeader(value[i])
|
||||||
}
|
}
|
||||||
msg.header[field] = value
|
msg.header[field] = value
|
||||||
}
|
}
|
||||||
|
@ -134,16 +130,13 @@ func (msg *Message) FormatAddress(address, name string) string {
|
||||||
buf := getBuffer()
|
buf := getBuffer()
|
||||||
defer putBuffer(buf)
|
defer putBuffer(buf)
|
||||||
|
|
||||||
if !quotedprintable.NeedsEncoding(name) {
|
enc := msg.encodeHeader(name)
|
||||||
|
if enc == name {
|
||||||
quote(buf, name)
|
quote(buf, name)
|
||||||
|
} else if hasSpecials(name) {
|
||||||
|
buf.WriteString(mime.BEncoding.Encode(msg.charset, name))
|
||||||
} else {
|
} else {
|
||||||
var n string
|
buf.WriteString(enc)
|
||||||
if hasSpecials(name) {
|
|
||||||
n = encodeHeader(quotedprintable.B.NewHeaderEncoder(msg.charset), name)
|
|
||||||
} else {
|
|
||||||
n = encodeHeader(msg.hEncoder, name)
|
|
||||||
}
|
|
||||||
buf.WriteString(n)
|
|
||||||
}
|
}
|
||||||
buf.WriteString(" <")
|
buf.WriteString(" <")
|
||||||
buf.WriteString(address)
|
buf.WriteString(address)
|
||||||
|
@ -307,12 +300,8 @@ func hasSpecials(text string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeHeader(enc *quotedprintable.HeaderEncoder, value string) string {
|
func (msg *Message) encodeHeader(value string) string {
|
||||||
if !quotedprintable.NeedsEncoding(value) {
|
return msg.hEncoder.Encode(msg.charset, value)
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
return enc.Encode(value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var bufPool = sync.Pool{
|
var bufPool = sync.Pool{
|
||||||
|
|
|
@ -38,14 +38,14 @@ func TestMessage(t *testing.T) {
|
||||||
"tobis@example.com",
|
"tobis@example.com",
|
||||||
"cc@example.com",
|
"cc@example.com",
|
||||||
},
|
},
|
||||||
content: "From: =?UTF-8?Q?Se=C3=B1or_From?= <from@example.com>\r\n" +
|
content: "From: =?UTF-8?q?Se=C3=B1or_From?= <from@example.com>\r\n" +
|
||||||
"To: =?UTF-8?Q?Se=C3=B1or_To?= <to@example.com>, tobis@example.com\r\n" +
|
"To: =?UTF-8?q?Se=C3=B1or_To?= <to@example.com>, tobis@example.com\r\n" +
|
||||||
"Cc: \"A, B\" <cc@example.com>\r\n" +
|
"Cc: \"A, B\" <cc@example.com>\r\n" +
|
||||||
"X-To: =?UTF-8?B?w6AsIGI=?= <ccbis@example.com>\r\n" +
|
"X-To: =?UTF-8?b?w6AsIGI=?= <ccbis@example.com>\r\n" +
|
||||||
"X-Date: Wed, 25 Jun 2014 17:46:00 +0000\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-Date-2: Wed, 25 Jun 2014 17:46:00 +0000\r\n" +
|
||||||
"X-Headers: Test, =?UTF-8?Q?Caf=C3=A9?=\r\n" +
|
"X-Headers: Test, =?UTF-8?q?Caf=C3=A9?=\r\n" +
|
||||||
"Subject: =?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=\r\n" +
|
"Subject: =?UTF-8?q?=C2=A1Hola,_se=C3=B1or!?=\r\n" +
|
||||||
"Content-Type: text/plain; charset=UTF-8\r\n" +
|
"Content-Type: text/plain; charset=UTF-8\r\n" +
|
||||||
"Content-Transfer-Encoding: quoted-printable\r\n" +
|
"Content-Transfer-Encoding: quoted-printable\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
|
@ -90,7 +90,7 @@ func TestCustomMessage(t *testing.T) {
|
||||||
to: []string{"to@example.com"},
|
to: []string{"to@example.com"},
|
||||||
content: "From: from@example.com\r\n" +
|
content: "From: from@example.com\r\n" +
|
||||||
"To: to@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-Type: text/html; charset=ISO-8859-1\r\n" +
|
||||||
"Content-Transfer-Encoding: base64\r\n" +
|
"Content-Transfer-Encoding: base64\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
|
@ -114,7 +114,7 @@ func TestUnencodedMessage(t *testing.T) {
|
||||||
to: []string{"to@example.com"},
|
to: []string{"to@example.com"},
|
||||||
content: "From: from@example.com\r\n" +
|
content: "From: from@example.com\r\n" +
|
||||||
"To: to@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-Type: text/html; charset=UTF-8\r\n" +
|
||||||
"Content-Transfer-Encoding: 8bit\r\n" +
|
"Content-Transfer-Encoding: 8bit\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
|
@ -439,13 +439,13 @@ func TestQpLineLength(t *testing.T) {
|
||||||
msg.SetHeader("From", "from@example.com")
|
msg.SetHeader("From", "from@example.com")
|
||||||
msg.SetHeader("To", "to@example.com")
|
msg.SetHeader("To", "to@example.com")
|
||||||
msg.SetBody("text/plain",
|
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", 75)+"à\r\n"+
|
||||||
strings.Repeat("0", 74)+"à\r\n"+
|
strings.Repeat("0", 74)+"à\r\n"+
|
||||||
strings.Repeat("0", 73)+"à\r\n"+
|
strings.Repeat("0", 73)+"à\r\n"+
|
||||||
strings.Repeat("0", 76)+"\r\n"+
|
strings.Repeat("0", 72)+"à\r\n"+
|
||||||
strings.Repeat("0", 77)+"\n")
|
strings.Repeat("0", 75)+"\r\n"+
|
||||||
|
strings.Repeat("0", 76)+"\n")
|
||||||
|
|
||||||
want := message{
|
want := message{
|
||||||
from: "from@example.com",
|
from: "from@example.com",
|
||||||
|
@ -455,13 +455,13 @@ func TestQpLineLength(t *testing.T) {
|
||||||
"Content-Type: text/plain; charset=UTF-8\r\n" +
|
"Content-Type: text/plain; charset=UTF-8\r\n" +
|
||||||
"Content-Transfer-Encoding: quoted-printable\r\n" +
|
"Content-Transfer-Encoding: quoted-printable\r\n" +
|
||||||
"\r\n" +
|
"\r\n" +
|
||||||
strings.Repeat("0", 76) + "=\r\n0\r\n" +
|
strings.Repeat("0", 75) + "=\r\n0\r\n" +
|
||||||
strings.Repeat("0", 76) + "=\r\n=C3=A0\r\n" +
|
|
||||||
strings.Repeat("0", 75) + "=\r\n=C3=A0\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", 74) + "=\r\n=C3=A0\r\n" +
|
||||||
strings.Repeat("0", 73) + "=C3=\r\n=A0\r\n" +
|
strings.Repeat("0", 73) + "=\r\n=C3=A0\r\n" +
|
||||||
strings.Repeat("0", 76) + "\r\n" +
|
strings.Repeat("0", 72) + "=C3=\r\n=A0\r\n" +
|
||||||
strings.Repeat("0", 76) + "=\r\n0\n",
|
strings.Repeat("0", 75) + "\r\n" +
|
||||||
|
strings.Repeat("0", 75) + "=\r\n0\r\n",
|
||||||
}
|
}
|
||||||
|
|
||||||
testMessage(t, msg, 0, want)
|
testMessage(t, msg, 0, want)
|
||||||
|
|
Loading…
Reference in New Issue