mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-12 17:02:55 +01:00
#13: Both html/template and text/template support added
- Switched the previous implementation to support text/template as well as html/template - Added SetBody*Template() methods to use a template directly as message body - Added AddAlternative*Template() methods to use a template directly as alternative message part
This commit is contained in:
parent
f24a86a4c6
commit
8919d64ca1
1 changed files with 100 additions and 17 deletions
117
msg.go
117
msg.go
|
@ -5,7 +5,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
ht "html/template"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"mime"
|
"mime"
|
||||||
|
@ -14,6 +14,7 @@ import (
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
tt "text/template"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -390,10 +391,7 @@ func (m *Msg) GetRecipients() ([]string, error) {
|
||||||
// SetBodyString sets the body of the message.
|
// SetBodyString sets the body of the message.
|
||||||
func (m *Msg) SetBodyString(ct ContentType, b string, o ...PartOption) {
|
func (m *Msg) SetBodyString(ct ContentType, b string, o ...PartOption) {
|
||||||
buf := bytes.NewBufferString(b)
|
buf := bytes.NewBufferString(b)
|
||||||
w := func(w io.Writer) (int64, error) {
|
w := writeFuncFromBuffer(buf)
|
||||||
nb, err := w.Write(buf.Bytes())
|
|
||||||
return int64(nb), err
|
|
||||||
}
|
|
||||||
m.SetBodyWriter(ct, w, o...)
|
m.SetBodyWriter(ct, w, o...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,13 +402,34 @@ func (m *Msg) SetBodyWriter(ct ContentType, w func(io.Writer) (int64, error), o
|
||||||
m.parts = []*Part{p}
|
m.parts = []*Part{p}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetBodyHTMLTemplate sets the body of the message from a given html/template.Template pointer
|
||||||
|
// The content type will be set to text/html automatically
|
||||||
|
func (m *Msg) SetBodyHTMLTemplate(t *ht.Template, d interface{}, o ...PartOption) error {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := t.Execute(&buf, d); err != nil {
|
||||||
|
return fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
}
|
||||||
|
w := writeFuncFromBuffer(&buf)
|
||||||
|
m.SetBodyWriter(TypeTextHTML, w, o...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBodyTextTemplate sets the body of the message from a given text/template.Template pointer
|
||||||
|
// The content type will be set to text/plain automatically
|
||||||
|
func (m *Msg) SetBodyTextTemplate(t *tt.Template, d interface{}, o ...PartOption) error {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := t.Execute(&buf, d); err != nil {
|
||||||
|
return fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
}
|
||||||
|
w := writeFuncFromBuffer(&buf)
|
||||||
|
m.SetBodyWriter(TypeTextPlain, w, o...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AddAlternativeString sets the alternative body of the message.
|
// AddAlternativeString sets the alternative body of the message.
|
||||||
func (m *Msg) AddAlternativeString(ct ContentType, b string, o ...PartOption) {
|
func (m *Msg) AddAlternativeString(ct ContentType, b string, o ...PartOption) {
|
||||||
buf := bytes.NewBufferString(b)
|
buf := bytes.NewBufferString(b)
|
||||||
w := func(w io.Writer) (int64, error) {
|
w := writeFuncFromBuffer(buf)
|
||||||
nb, err := w.Write(buf.Bytes())
|
|
||||||
return int64(nb), err
|
|
||||||
}
|
|
||||||
m.AddAlternativeWriter(ct, w, o...)
|
m.AddAlternativeWriter(ct, w, o...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,6 +440,30 @@ func (m *Msg) AddAlternativeWriter(ct ContentType, w func(io.Writer) (int64, err
|
||||||
m.parts = append(m.parts, p)
|
m.parts = append(m.parts, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddAlternativeHTMLTemplate sets the alternative body of the message to a html/template.Template output
|
||||||
|
// The content type will be set to text/html automatically
|
||||||
|
func (m *Msg) AddAlternativeHTMLTemplate(t *ht.Template, d interface{}, o ...PartOption) error {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := t.Execute(&buf, d); err != nil {
|
||||||
|
return fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
}
|
||||||
|
w := writeFuncFromBuffer(&buf)
|
||||||
|
m.AddAlternativeWriter(TypeTextHTML, w, o...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAlternativeTextTemplate sets the alternative body of the message to a text/template.Template output
|
||||||
|
// The content type will be set to text/plain automatically
|
||||||
|
func (m *Msg) AddAlternativeTextTemplate(t *tt.Template, d interface{}, o ...PartOption) error {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := t.Execute(&buf, d); err != nil {
|
||||||
|
return fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
}
|
||||||
|
w := writeFuncFromBuffer(&buf)
|
||||||
|
m.AddAlternativeWriter(TypeTextPlain, w, o...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AttachFile adds an attachment File to the Msg
|
// AttachFile adds an attachment File to the Msg
|
||||||
func (m *Msg) AttachFile(n string, o ...FileOption) {
|
func (m *Msg) AttachFile(n string, o ...FileOption) {
|
||||||
f := fileFromFS(n)
|
f := fileFromFS(n)
|
||||||
|
@ -436,9 +479,19 @@ func (m *Msg) AttachReader(n string, r io.Reader, o ...FileOption) {
|
||||||
m.attachments = m.appendFile(m.attachments, f, o...)
|
m.attachments = m.appendFile(m.attachments, f, o...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AttachTemplate adds the output of a template.Template pointer as File attachment to the Msg
|
// AttachHTMLTemplate adds the output of a html/template.Template pointer as File attachment to the Msg
|
||||||
func (m *Msg) AttachTemplate(n string, t *template.Template, d interface{}, o ...FileOption) error {
|
func (m *Msg) AttachHTMLTemplate(n string, t *ht.Template, d interface{}, o ...FileOption) error {
|
||||||
f, err := fileFromTemplate(n, t, d)
|
f, err := fileFromHTMLTemplate(n, t, d)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to attach template: %w", err)
|
||||||
|
}
|
||||||
|
m.attachments = m.appendFile(m.attachments, f, o...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AttachTextTemplate adds the output of a text/template.Template pointer as File attachment to the Msg
|
||||||
|
func (m *Msg) AttachTextTemplate(n string, t *tt.Template, d interface{}, o ...FileOption) error {
|
||||||
|
f, err := fileFromTextTemplate(n, t, d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to attach template: %w", err)
|
return fmt.Errorf("failed to attach template: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -461,9 +514,19 @@ func (m *Msg) EmbedReader(n string, r io.Reader, o ...FileOption) {
|
||||||
m.embeds = m.appendFile(m.embeds, f, o...)
|
m.embeds = m.appendFile(m.embeds, f, o...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmbedTemplate adds the output of a template.Template pointer as embedded File to the Msg
|
// EmbedHTMLTemplate adds the output of a html/template.Template pointer as embedded File to the Msg
|
||||||
func (m *Msg) EmbedTemplate(n string, t *template.Template, d interface{}, o ...FileOption) error {
|
func (m *Msg) EmbedHTMLTemplate(n string, t *ht.Template, d interface{}, o ...FileOption) error {
|
||||||
f, err := fileFromTemplate(n, t, d)
|
f, err := fileFromHTMLTemplate(n, t, d)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to embed template: %w", err)
|
||||||
|
}
|
||||||
|
m.embeds = m.appendFile(m.embeds, f, o...)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmbedTextTemplate adds the output of a text/template.Template pointer as embedded File to the Msg
|
||||||
|
func (m *Msg) EmbedTextTemplate(n string, t *tt.Template, d interface{}, o ...FileOption) error {
|
||||||
|
f, err := fileFromTextTemplate(n, t, d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to embed template: %w", err)
|
return fmt.Errorf("failed to embed template: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -689,8 +752,18 @@ func fileFromReader(n string, r io.Reader) *File {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileFromTemplate returns a File pointer form a given template.Template
|
// fileFromHTMLTemplate returns a File pointer form a given html/template.Template
|
||||||
func fileFromTemplate(n string, t *template.Template, d interface{}) (*File, error) {
|
func fileFromHTMLTemplate(n string, t *ht.Template, d interface{}) (*File, error) {
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
if err := t.Execute(&buf, d); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
}
|
||||||
|
f := fileFromReader(n, &buf)
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileFromTextTemplate returns a File pointer form a given text/template.Template
|
||||||
|
func fileFromTextTemplate(n string, t *tt.Template, d interface{}) (*File, error) {
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
if err := t.Execute(&buf, d); err != nil {
|
if err := t.Execute(&buf, d); err != nil {
|
||||||
return nil, fmt.Errorf("failed to execute template: %w", err)
|
return nil, fmt.Errorf("failed to execute template: %w", err)
|
||||||
|
@ -710,3 +783,13 @@ func getEncoder(e Encoding) mime.WordEncoder {
|
||||||
return mime.QEncoding
|
return mime.QEncoding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeFuncFromBuffer is a common method to convert a byte buffer into a writeFunc as
|
||||||
|
// often required by this library
|
||||||
|
func writeFuncFromBuffer(buf *bytes.Buffer) func(io.Writer) (int64, error) {
|
||||||
|
w := func(w io.Writer) (int64, error) {
|
||||||
|
nb, err := w.Write(buf.Bytes())
|
||||||
|
return int64(nb), err
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue