Changed body content type from []byte to func(io.Writer) error

It allows streaming the message body when sending an email instead
of buffering it to memory.
This commit is contained in:
Alexandre Cesaro 2015-07-08 00:26:19 +02:00
parent ac067c1594
commit 66c8b9ae4c
3 changed files with 32 additions and 23 deletions

View File

@ -28,7 +28,7 @@ type header map[string][]string
type part struct { type part struct {
contentType string contentType string
body *bytes.Buffer copier func(io.Writer) error
} }
// NewMessage creates a new message. It uses UTF-8 and quoted-printable encoding // NewMessage creates a new message. It uses UTF-8 and quoted-printable encoding
@ -170,12 +170,15 @@ func (msg *Message) SetBody(contentType, body string) {
msg.parts = []part{ msg.parts = []part{
part{ part{
contentType: contentType, contentType: contentType,
body: bytes.NewBufferString(body), copier: func(w io.Writer) error {
_, err := io.WriteString(w, body)
return err
},
}, },
} }
} }
// AddAlternative adds an alternative body to the message. Commonly used to // AddAlternative adds an alternative part to the message. Commonly used to
// send HTML emails that default to the plain text version for backward // send HTML emails that default to the plain text version for backward
// compatibility. // compatibility.
// //
@ -189,29 +192,30 @@ func (msg *Message) AddAlternative(contentType, body string) {
msg.parts = append(msg.parts, msg.parts = append(msg.parts,
part{ part{
contentType: contentType, contentType: contentType,
body: bytes.NewBufferString(body), copier: func(w io.Writer) error {
_, err := io.WriteString(w, body)
return err
},
}, },
) )
} }
// GetBodyWriter gets a writer that writes to the body. It can be useful with // AddAlternativeWriter adds an alternative part to the message. It can be
// the templates from packages text/template or html/template. // useful with the text/template and html/template packages.
// //
// Example: // Example:
// //
// w := msg.GetBodyWriter("text/plain")
// t := template.Must(template.New("example").Parse("Hello {{.}}!")) // t := template.Must(template.New("example").Parse("Hello {{.}}!"))
// t.Execute(w, "Bob") // msg.AddAlternativeWriter("text/plain", func(w io.Writer) error {
func (msg *Message) GetBodyWriter(contentType string) io.Writer { // return t.Execute(w, "Bob")
buf := new(bytes.Buffer) // })
msg.parts = append(msg.parts, func (msg *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error) {
msg.parts = []part{
part{ part{
contentType: contentType, contentType: contentType,
body: buf, copier: f,
}, },
) }
return buf
} }
// A File represents a file that can be attached or embedded in an email. // A File represents a file that can be attached or embedded in an email.

View File

@ -66,8 +66,10 @@ func TestBodyWriter(t *testing.T) {
msg := NewMessage() msg := NewMessage()
msg.SetHeader("From", "from@example.com") msg.SetHeader("From", "from@example.com")
msg.SetHeader("To", "to@example.com") msg.SetHeader("To", "to@example.com")
w := msg.GetBodyWriter("text/plain") msg.AddAlternativeWriter("text/plain", func(w io.Writer) error {
w.Write([]byte("Test message")) _, err := w.Write([]byte("Test message"))
return err
})
want := &message{ want := &message{
from: "from@example.com", from: "from@example.com",

View File

@ -42,7 +42,7 @@ func (w *messageWriter) writeMessage(msg *Message) {
"Content-Type": []string{contentType}, "Content-Type": []string{contentType},
"Content-Transfer-Encoding": []string{string(msg.encoding)}, "Content-Transfer-Encoding": []string{string(msg.encoding)},
}) })
w.writeBody(part.body.Bytes(), msg.encoding) w.writeBody(part.copier, msg.encoding)
} }
if msg.hasAlternativePart() { if msg.hasAlternativePart() {
w.closeMultipart() w.closeMultipart()
@ -123,7 +123,10 @@ func (w *messageWriter) addFiles(files []*File, isAttachment bool) {
} }
} }
w.writeHeaders(h) w.writeHeaders(h)
w.writeBody(f.Content, Base64) w.writeBody(func(w io.Writer) error {
_, err := w.Write(f.Content)
return err
}, Base64)
} }
} }
@ -175,7 +178,7 @@ func (w *messageWriter) writeHeaders(h map[string][]string) {
} }
} }
func (w *messageWriter) writeBody(body []byte, enc Encoding) { func (w *messageWriter) writeBody(f func(io.Writer) error, enc Encoding) {
var subWriter io.Writer var subWriter io.Writer
if w.depth == 0 { if w.depth == 0 {
w.writeString("\r\n") w.writeString("\r\n")
@ -186,13 +189,13 @@ func (w *messageWriter) writeBody(body []byte, enc Encoding) {
if enc == Base64 { if enc == Base64 {
wc := base64.NewEncoder(base64.StdEncoding, newBase64LineWriter(subWriter)) wc := base64.NewEncoder(base64.StdEncoding, newBase64LineWriter(subWriter))
wc.Write(body) w.err = f(wc)
wc.Close() wc.Close()
} else if enc == Unencoded { } else if enc == Unencoded {
subWriter.Write(body) w.err = f(subWriter)
} else { } else {
wc := quotedprintable.NewWriter(subWriter) wc := quotedprintable.NewWriter(subWriter)
wc.Write(body) w.err = f(wc)
wc.Close() wc.Close()
} }
} }