Provided a way to specify the encoding of a message part
This commit introduces a minor backward-compatibility break: Message.SetBody, Message.AddAlternative and Message.AddAlternativeWriter now accept a new variadic argument. Since this argument is optional, in almost all cases there is nothing to change. That is why Gomail version number wasn't bumped. Fixes #47
This commit is contained in:
parent
19acfc29a0
commit
db70192787
|
@ -213,3 +213,7 @@ func ExampleSetCharset() {
|
|||
func ExampleSetEncoding() {
|
||||
m = gomail.NewMessage(gomail.SetEncoding(gomail.Base64))
|
||||
}
|
||||
|
||||
func ExampleWithEncoding() {
|
||||
m.SetBody("text/plain", "Hello!", gomail.SetPartEncoding(gomail.Unencoded))
|
||||
}
|
||||
|
|
67
message.go
67
message.go
|
@ -11,7 +11,7 @@ import (
|
|||
// Message represents an email.
|
||||
type Message struct {
|
||||
header header
|
||||
parts []part
|
||||
parts []*part
|
||||
attachments []*file
|
||||
embedded []*file
|
||||
charset string
|
||||
|
@ -23,8 +23,9 @@ type Message struct {
|
|||
type header map[string][]string
|
||||
|
||||
type part struct {
|
||||
header header
|
||||
contentType string
|
||||
copier func(io.Writer) error
|
||||
encoding Encoding
|
||||
}
|
||||
|
||||
// NewMessage creates a new message. It uses UTF-8 and quoted-printable encoding
|
||||
|
@ -179,16 +180,8 @@ func (m *Message) GetHeader(field string) []string {
|
|||
|
||||
// SetBody sets the body of the message. It replaces any content previously set
|
||||
// by SetBody, AddAlternative or AddAlternativeWriter.
|
||||
func (m *Message) SetBody(contentType, body string) {
|
||||
m.parts = []part{
|
||||
{
|
||||
header: m.getPartHeader(contentType),
|
||||
copier: func(w io.Writer) error {
|
||||
_, err := io.WriteString(w, body)
|
||||
return err
|
||||
},
|
||||
},
|
||||
}
|
||||
func (m *Message) SetBody(contentType, body string, settings ...PartSetting) {
|
||||
m.parts = []*part{m.newPart(contentType, newCopier(body), settings)}
|
||||
}
|
||||
|
||||
// AddAlternative adds an alternative part to the message.
|
||||
|
@ -197,30 +190,48 @@ func (m *Message) SetBody(contentType, body string) {
|
|||
// version for backward compatibility. AddAlternative appends the new part to
|
||||
// the end of the message. So the plain text part should be added before the
|
||||
// HTML part. See http://en.wikipedia.org/wiki/MIME#Alternative
|
||||
func (m *Message) AddAlternative(contentType, body string) {
|
||||
m.parts = append(m.parts, part{
|
||||
header: m.getPartHeader(contentType),
|
||||
copier: func(w io.Writer) error {
|
||||
_, err := io.WriteString(w, body)
|
||||
func (m *Message) AddAlternative(contentType, body string, settings ...PartSetting) {
|
||||
m.AddAlternativeWriter(contentType, newCopier(body), settings...)
|
||||
}
|
||||
|
||||
func newCopier(s string) func(io.Writer) error {
|
||||
return func(w io.Writer) error {
|
||||
_, err := io.WriteString(w, s)
|
||||
return err
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// AddAlternativeWriter adds an alternative part to the message. It can be
|
||||
// useful with the text/template or html/template packages.
|
||||
func (m *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error) {
|
||||
m.parts = append(m.parts, part{
|
||||
header: m.getPartHeader(contentType),
|
||||
copier: f,
|
||||
})
|
||||
func (m *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error, settings ...PartSetting) {
|
||||
m.parts = append(m.parts, m.newPart(contentType, f, settings))
|
||||
}
|
||||
|
||||
func (m *Message) getPartHeader(contentType string) header {
|
||||
return map[string][]string{
|
||||
"Content-Type": {contentType + "; charset=" + m.charset},
|
||||
"Content-Transfer-Encoding": {string(m.encoding)},
|
||||
func (m *Message) newPart(contentType string, f func(io.Writer) error, settings []PartSetting) *part {
|
||||
p := &part{
|
||||
contentType: contentType,
|
||||
copier: f,
|
||||
encoding: m.encoding,
|
||||
}
|
||||
|
||||
for _, s := range settings {
|
||||
s(p)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// A PartSetting can be used as an argument in Message.SetBody,
|
||||
// Message.AddAlternative or Message.AddAlternativeWriter to configure the part
|
||||
// added to a message.
|
||||
type PartSetting func(*part)
|
||||
|
||||
// SetPartEncoding sets the encoding of the part added to the message. By
|
||||
// default, parts use the same encoding than the message.
|
||||
func SetPartEncoding(e Encoding) PartSetting {
|
||||
return PartSetting(func(p *part) {
|
||||
p.encoding = e
|
||||
})
|
||||
}
|
||||
|
||||
type file struct {
|
||||
|
|
|
@ -168,6 +168,36 @@ func TestAlternative(t *testing.T) {
|
|||
testMessage(t, m, 1, want)
|
||||
}
|
||||
|
||||
func TestPartSetting(t *testing.T) {
|
||||
m := NewMessage()
|
||||
m.SetHeader("From", "from@example.com")
|
||||
m.SetHeader("To", "to@example.com")
|
||||
m.SetBody("text/plain; format=flowed", "¡Hola, señor!", SetPartEncoding(Unencoded))
|
||||
m.AddAlternative("text/html", "¡<b>Hola</b>, <i>señor</i>!</h1>")
|
||||
|
||||
want := &message{
|
||||
from: "from@example.com",
|
||||
to: []string{"to@example.com"},
|
||||
content: "From: from@example.com\r\n" +
|
||||
"To: to@example.com\r\n" +
|
||||
"Content-Type: multipart/alternative; boundary=_BOUNDARY_1_\r\n" +
|
||||
"\r\n" +
|
||||
"--_BOUNDARY_1_\r\n" +
|
||||
"Content-Type: text/plain; format=flowed; charset=UTF-8\r\n" +
|
||||
"Content-Transfer-Encoding: 8bit\r\n" +
|
||||
"\r\n" +
|
||||
"¡Hola, señor!\r\n" +
|
||||
"--_BOUNDARY_1_\r\n" +
|
||||
"Content-Type: text/html; charset=UTF-8\r\n" +
|
||||
"Content-Transfer-Encoding: quoted-printable\r\n" +
|
||||
"\r\n" +
|
||||
"=C2=A1<b>Hola</b>, <i>se=C3=B1or</i>!</h1>\r\n" +
|
||||
"--_BOUNDARY_1_--\r\n",
|
||||
}
|
||||
|
||||
testMessage(t, m, 1, want)
|
||||
}
|
||||
|
||||
func TestBodyWriter(t *testing.T) {
|
||||
m := NewMessage()
|
||||
m.SetHeader("From", "from@example.com")
|
||||
|
|
11
writeto.go
11
writeto.go
|
@ -38,8 +38,7 @@ func (w *messageWriter) writeMessage(m *Message) {
|
|||
w.openMultipart("alternative")
|
||||
}
|
||||
for _, part := range m.parts {
|
||||
w.writeHeaders(part.header)
|
||||
w.writeBody(part.copier, m.encoding)
|
||||
w.writePart(part, m.charset)
|
||||
}
|
||||
if m.hasAlternativePart() {
|
||||
w.closeMultipart()
|
||||
|
@ -104,6 +103,14 @@ func (w *messageWriter) closeMultipart() {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *messageWriter) writePart(p *part, charset string) {
|
||||
w.writeHeaders(map[string][]string{
|
||||
"Content-Type": {p.contentType + "; charset=" + charset},
|
||||
"Content-Transfer-Encoding": {string(p.encoding)},
|
||||
})
|
||||
w.writeBody(p.copier, p.encoding)
|
||||
}
|
||||
|
||||
func (w *messageWriter) addFiles(files []*file, isAttachment bool) {
|
||||
for _, f := range files {
|
||||
if _, ok := f.Header["Content-Type"]; !ok {
|
||||
|
|
Loading…
Reference in New Issue