mirror of
https://github.com/wneessen/go-mail.git
synced 2024-12-22 10:40:39 +01:00
Merge pull request #15 from wneessen/13-template-attachments
Template attachments
This commit is contained in:
commit
8fbcb076af
4 changed files with 505 additions and 10 deletions
|
@ -35,6 +35,7 @@ Some of the features of this library:
|
|||
* [X] Support for different encodings
|
||||
* [X] Support sending mails via a local sendmail command
|
||||
* [X] Message object satisfies `io.WriteTo` and `io.Reader` interfaces
|
||||
* [X] Support for Go's `html/template` and `text/template` (as message body, alternative part or attachment/emebed)
|
||||
|
||||
go-mail works like a programatic email client and provides lots of methods and functionalities you would consider
|
||||
standard in a MUA.
|
||||
|
|
2
doc.go
2
doc.go
|
@ -2,4 +2,4 @@
|
|||
package mail
|
||||
|
||||
// VERSION is used in the default user agent string
|
||||
const VERSION = "0.1.9"
|
||||
const VERSION = "0.2.2"
|
||||
|
|
150
msg.go
150
msg.go
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
ht "html/template"
|
||||
"io"
|
||||
"math/rand"
|
||||
"mime"
|
||||
|
@ -13,6 +14,7 @@ import (
|
|||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
tt "text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -389,10 +391,7 @@ func (m *Msg) GetRecipients() ([]string, error) {
|
|||
// SetBodyString sets the body of the message.
|
||||
func (m *Msg) SetBodyString(ct ContentType, b string, o ...PartOption) {
|
||||
buf := bytes.NewBufferString(b)
|
||||
w := func(w io.Writer) (int64, error) {
|
||||
nb, err := w.Write(buf.Bytes())
|
||||
return int64(nb), err
|
||||
}
|
||||
w := writeFuncFromBuffer(buf)
|
||||
m.SetBodyWriter(ct, w, o...)
|
||||
}
|
||||
|
||||
|
@ -403,13 +402,40 @@ func (m *Msg) SetBodyWriter(ct ContentType, w func(io.Writer) (int64, error), o
|
|||
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 {
|
||||
if t == nil {
|
||||
return fmt.Errorf("template pointer is nil")
|
||||
}
|
||||
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 {
|
||||
if t == nil {
|
||||
return fmt.Errorf("template pointer is nil")
|
||||
}
|
||||
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.
|
||||
func (m *Msg) AddAlternativeString(ct ContentType, b string, o ...PartOption) {
|
||||
buf := bytes.NewBufferString(b)
|
||||
w := func(w io.Writer) (int64, error) {
|
||||
nb, err := w.Write(buf.Bytes())
|
||||
return int64(nb), err
|
||||
}
|
||||
w := writeFuncFromBuffer(buf)
|
||||
m.AddAlternativeWriter(ct, w, o...)
|
||||
}
|
||||
|
||||
|
@ -420,6 +446,36 @@ func (m *Msg) AddAlternativeWriter(ct ContentType, w func(io.Writer) (int64, err
|
|||
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 {
|
||||
if t == nil {
|
||||
return fmt.Errorf("template pointer is nil")
|
||||
}
|
||||
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 {
|
||||
if t == nil {
|
||||
return fmt.Errorf("template pointer is nil")
|
||||
}
|
||||
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
|
||||
func (m *Msg) AttachFile(n string, o ...FileOption) {
|
||||
f := fileFromFS(n)
|
||||
|
@ -435,6 +491,26 @@ func (m *Msg) AttachReader(n string, r io.Reader, o ...FileOption) {
|
|||
m.attachments = m.appendFile(m.attachments, f, o...)
|
||||
}
|
||||
|
||||
// AttachHTMLTemplate adds the output of a html/template.Template pointer as File attachment to the Msg
|
||||
func (m *Msg) AttachHTMLTemplate(n string, t *ht.Template, d interface{}, o ...FileOption) error {
|
||||
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 {
|
||||
return fmt.Errorf("failed to attach template: %w", err)
|
||||
}
|
||||
m.attachments = m.appendFile(m.attachments, f, o...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmbedFile adds an embedded File to the Msg
|
||||
func (m *Msg) EmbedFile(n string, o ...FileOption) {
|
||||
f := fileFromFS(n)
|
||||
|
@ -450,6 +526,26 @@ func (m *Msg) EmbedReader(n string, r io.Reader, o ...FileOption) {
|
|||
m.embeds = m.appendFile(m.embeds, f, o...)
|
||||
}
|
||||
|
||||
// EmbedHTMLTemplate adds the output of a html/template.Template pointer as embedded File to the Msg
|
||||
func (m *Msg) EmbedHTMLTemplate(n string, t *ht.Template, d interface{}, o ...FileOption) error {
|
||||
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 {
|
||||
return fmt.Errorf("failed to embed template: %w", err)
|
||||
}
|
||||
m.embeds = m.appendFile(m.embeds, f, o...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reset resets all headers, body parts and attachments/embeds of the Msg
|
||||
// It leaves already set encodings, charsets, boundaries, etc. as is
|
||||
func (m *Msg) Reset() {
|
||||
|
@ -467,7 +563,7 @@ func (m *Msg) WriteTo(w io.Writer) (int64, error) {
|
|||
return mw.n, mw.err
|
||||
}
|
||||
|
||||
// Write is an alias method to WriteTo due to compatiblity reasons
|
||||
// Write is an alias method to WriteTo due to compatibility reasons
|
||||
func (m *Msg) Write(w io.Writer) (int64, error) {
|
||||
return m.WriteTo(w)
|
||||
}
|
||||
|
@ -668,6 +764,32 @@ func fileFromReader(n string, r io.Reader) *File {
|
|||
}
|
||||
}
|
||||
|
||||
// fileFromHTMLTemplate returns a File pointer form a given html/template.Template
|
||||
func fileFromHTMLTemplate(n string, t *ht.Template, d interface{}) (*File, error) {
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("template pointer is nil")
|
||||
}
|
||||
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) {
|
||||
if t == nil {
|
||||
return nil, fmt.Errorf("template pointer is nil")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// getEncoder creates a new mime.WordEncoder based on the encoding setting of the message
|
||||
func getEncoder(e Encoding) mime.WordEncoder {
|
||||
switch e {
|
||||
|
@ -679,3 +801,13 @@ func getEncoder(e Encoding) mime.WordEncoder {
|
|||
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
|
||||
}
|
||||
|
|
362
msg_test.go
362
msg_test.go
|
@ -4,10 +4,12 @@ import (
|
|||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
htpl "html/template"
|
||||
"io"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"testing"
|
||||
ttpl "text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -1338,3 +1340,363 @@ func TestMsg_Read_ioCopy(t *testing.T) {
|
|||
t.Errorf("message content of WriteTo and io.Copy differ")
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_SetBodyTextTemplate tests the Msg.SetBodyTextTemplate method
|
||||
func TestMsg_SetBodyTextTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
sf bool
|
||||
}{
|
||||
{"normal text", "This is a {{.Placeholder}}", "TemplateTest", false},
|
||||
{"invalid tpl", "This is a {{ foo .Placeholder}}", "TemplateTest", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := ttpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
if err := m.SetBodyTextTemplate(tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to set template as body: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ph) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_SetBodyHTMLTemplate tests the Msg.SetBodyHTMLTemplate method
|
||||
func TestMsg_SetBodyHTMLTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
ex string
|
||||
sf bool
|
||||
}{
|
||||
{"normal HTML", "<p>This is a {{.Placeholder}}</p>", "TemplateTest", "TemplateTest", false},
|
||||
{"HTML with HTML", "<p>This is a {{.Placeholder}}</p>", "<script>alert(1)</script>",
|
||||
"<script>alert(1)</script>", false},
|
||||
{"invalid tpl", "<p>This is a {{ foo .Placeholder}}</p>", "TemplateTest", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := htpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
if err := m.SetBodyHTMLTemplate(tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to set template as body: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ex) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_AddAlternativeTextTemplate tests the Msg.AddAlternativeTextTemplate method
|
||||
func TestMsg_AddAlternativeTextTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
sf bool
|
||||
}{
|
||||
{"normal text", "This is a {{.Placeholder}}", "TemplateTest", false},
|
||||
{"invalid tpl", "This is a {{ foo .Placeholder}}", "TemplateTest", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := ttpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextHTML, "")
|
||||
if err := m.AddAlternativeTextTemplate(tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to set template as alternative part: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ph) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_AddAlternativeHTMLTemplate tests the Msg.AddAlternativeHTMLTemplate method
|
||||
func TestMsg_AddAlternativeHTMLTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
ex string
|
||||
sf bool
|
||||
}{
|
||||
{"normal HTML", "<p>This is a {{.Placeholder}}</p>", "TemplateTest", "TemplateTest", false},
|
||||
{"HTML with HTML", "<p>This is a {{.Placeholder}}</p>", "<script>alert(1)</script>",
|
||||
"<script>alert(1)</script>", false},
|
||||
{"invalid tpl", "<p>This is a {{ foo .Placeholder}}</p>", "TemplateTest", "", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := htpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "")
|
||||
if err := m.AddAlternativeHTMLTemplate(tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to set template as alternative part: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ex) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_AttachTextTemplate tests the Msg.AttachTextTemplate method
|
||||
func TestMsg_AttachTextTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
ex string
|
||||
ac int
|
||||
sf bool
|
||||
}{
|
||||
{"normal text", "This is a {{.Placeholder}}", "TemplateTest",
|
||||
"VGhpcyBpcyBhIFRlbXBsYXRlVGVzdA==", 1, false},
|
||||
{"invalid tpl", "This is a {{ foo .Placeholder}}", "TemplateTest", "", 0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := ttpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "This is the body")
|
||||
if err := m.AttachTextTemplate("attachment.txt", tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to attach template: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ex) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
if len(m.attachments) != tt.ac {
|
||||
t.Errorf("wrong number of attachments. Expected: %d, got: %d", tt.ac, len(m.attachments))
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_AttachHTMLTemplate tests the Msg.AttachHTMLTemplate method
|
||||
func TestMsg_AttachHTMLTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
ex string
|
||||
ac int
|
||||
sf bool
|
||||
}{
|
||||
{"normal HTML", "<p>This is a {{.Placeholder}}</p>", "TemplateTest",
|
||||
"PHA+VGhpcyBpcyBhIFRlbXBsYXRlVGVzdDwvcD4=", 1, false},
|
||||
{"HTML with HTML", "<p>This is a {{.Placeholder}}</p>", "<script>alert(1)</script>",
|
||||
"PHA+VGhpcyBpcyBhICZsdDtzY3JpcHQmZ3Q7YWxlcnQoMSkmbHQ7L3NjcmlwdCZndDs8L3A+", 1, false},
|
||||
{"invalid tpl", "<p>This is a {{ foo .Placeholder}}</p>", "TemplateTest", "", 0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := htpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "")
|
||||
if err := m.AttachHTMLTemplate("attachment.html", tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to set template as alternative part: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ex) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
if len(m.attachments) != tt.ac {
|
||||
t.Errorf("wrong number of attachments. Expected: %d, got: %d", tt.ac, len(m.attachments))
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_EmbedTextTemplate tests the Msg.EmbedTextTemplate method
|
||||
func TestMsg_EmbedTextTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
ex string
|
||||
ec int
|
||||
sf bool
|
||||
}{
|
||||
{"normal text", "This is a {{.Placeholder}}", "TemplateTest",
|
||||
"VGhpcyBpcyBhIFRlbXBsYXRlVGVzdA==", 1, false},
|
||||
{"invalid tpl", "This is a {{ foo .Placeholder}}", "TemplateTest", "", 0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := ttpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "This is the body")
|
||||
if err := m.EmbedTextTemplate("attachment.txt", tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to attach template: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ex) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
if len(m.embeds) != tt.ec {
|
||||
t.Errorf("wrong number of attachments. Expected: %d, got: %d", tt.ec, len(m.attachments))
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_EmbedHTMLTemplate tests the Msg.EmbedHTMLTemplate method
|
||||
func TestMsg_EmbedHTMLTemplate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
ph string
|
||||
ex string
|
||||
ec int
|
||||
sf bool
|
||||
}{
|
||||
{"normal HTML", "<p>This is a {{.Placeholder}}</p>", "TemplateTest",
|
||||
"PHA+VGhpcyBpcyBhIFRlbXBsYXRlVGVzdDwvcD4=", 1, false},
|
||||
{"HTML with HTML", "<p>This is a {{.Placeholder}}</p>", "<script>alert(1)</script>",
|
||||
"PHA+VGhpcyBpcyBhICZsdDtzY3JpcHQmZ3Q7YWxlcnQoMSkmbHQ7L3NjcmlwdCZndDs8L3A+", 1, false},
|
||||
{"invalid tpl", "<p>This is a {{ foo .Placeholder}}</p>", "TemplateTest", "", 0, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
data := struct {
|
||||
Placeholder string
|
||||
}{Placeholder: tt.ph}
|
||||
tpl, err := htpl.New("test").Parse(tt.tpl)
|
||||
if err != nil && !tt.sf {
|
||||
t.Errorf("failed to render template: %s", err)
|
||||
return
|
||||
}
|
||||
m := NewMsg()
|
||||
m.SetBodyString(TypeTextPlain, "")
|
||||
if err := m.EmbedHTMLTemplate("attachment.html", tpl, data); err != nil && !tt.sf {
|
||||
t.Errorf("failed to set template as alternative part: %s", err)
|
||||
}
|
||||
|
||||
wbuf := bytes.Buffer{}
|
||||
_, err = m.WriteTo(&wbuf)
|
||||
if err != nil {
|
||||
t.Errorf("failed to write body to buffer: %s", err)
|
||||
}
|
||||
if !strings.Contains(wbuf.String(), tt.ex) && !tt.sf {
|
||||
t.Errorf("SetBodyTextTemplate failed: Body does not contain the expected tpl placeholder: %s", tt.ph)
|
||||
}
|
||||
if len(m.embeds) != tt.ec {
|
||||
t.Errorf("wrong number of attachments. Expected: %d, got: %d", tt.ec, len(m.attachments))
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue