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 {
contentType string
body *bytes.Buffer
copier func(io.Writer) error
}
// 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{
part{
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
// compatibility.
//
@ -189,29 +192,30 @@ func (msg *Message) AddAlternative(contentType, body string) {
msg.parts = append(msg.parts,
part{
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
// the templates from packages text/template or html/template.
// AddAlternativeWriter adds an alternative part to the message. It can be
// useful with the text/template and html/template packages.
//
// Example:
//
// w := msg.GetBodyWriter("text/plain")
// t := template.Must(template.New("example").Parse("Hello {{.}}!"))
// t.Execute(w, "Bob")
func (msg *Message) GetBodyWriter(contentType string) io.Writer {
buf := new(bytes.Buffer)
msg.parts = append(msg.parts,
// msg.AddAlternativeWriter("text/plain", func(w io.Writer) error {
// return t.Execute(w, "Bob")
// })
func (msg *Message) AddAlternativeWriter(contentType string, f func(io.Writer) error) {
msg.parts = []part{
part{
contentType: contentType,
body: buf,
copier: f,
},
)
return buf
}
}
// 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.SetHeader("From", "from@example.com")
msg.SetHeader("To", "to@example.com")
w := msg.GetBodyWriter("text/plain")
w.Write([]byte("Test message"))
msg.AddAlternativeWriter("text/plain", func(w io.Writer) error {
_, err := w.Write([]byte("Test message"))
return err
})
want := &message{
from: "from@example.com",

View File

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