diff --git a/example_test.go b/example_test.go
index 8d9c6c2..e37298a 100644
--- a/example_test.go
+++ b/example_test.go
@@ -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))
+}
diff --git a/message.go b/message.go
index 7fbfc3f..4a3fd0e 100644
--- a/message.go
+++ b/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
- copier func(io.Writer) error
+ 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)
- return err
- },
- })
+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 {
diff --git a/message_test.go b/message_test.go
index 04c987e..40e44f2 100644
--- a/message_test.go
+++ b/message_test.go
@@ -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", "¡Hola, señor!")
+
+ 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=A1Hola, se=C3=B1or!\r\n" +
+ "--_BOUNDARY_1_--\r\n",
+ }
+
+ testMessage(t, m, 1, want)
+}
+
func TestBodyWriter(t *testing.T) {
m := NewMessage()
m.SetHeader("From", "from@example.com")
diff --git a/writeto.go b/writeto.go
index 0031bde..490f3b1 100644
--- a/writeto.go
+++ b/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 {