mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-21 21:30:50 +01:00
Closes #29: Allow attaching/embedding from embed.FS
- Added `EmbedFromEmbedFS()` to allow embedding from embed.FS - Added `AttachFromEmbedFS()` to allow attaching from embed.FS - Added `fileFromEmbedFS()` as internal method for both other m methods to attach/embed the embed.FS file
This commit is contained in:
parent
4fcd42dfad
commit
192627f6a5
2 changed files with 143 additions and 0 deletions
51
msg.go
51
msg.go
|
@ -7,6 +7,7 @@ package mail
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
ht "html/template"
|
||||
|
@ -539,6 +540,19 @@ func (m *Msg) AttachTextTemplate(n string, t *tt.Template, d interface{}, o ...F
|
|||
return nil
|
||||
}
|
||||
|
||||
// AttachFromEmbedFS adds an attachment File from an embed.FS to the Msg
|
||||
func (m *Msg) AttachFromEmbedFS(n string, f *embed.FS, o ...FileOption) error {
|
||||
if f == nil {
|
||||
return fmt.Errorf("embed.FS must not be nil")
|
||||
}
|
||||
ef, err := fileFromEmbedFS(n, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.attachments = m.appendFile(m.attachments, ef, o...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// EmbedFile adds an embedded File to the Msg
|
||||
func (m *Msg) EmbedFile(n string, o ...FileOption) {
|
||||
f := fileFromFS(n)
|
||||
|
@ -574,6 +588,19 @@ func (m *Msg) EmbedTextTemplate(n string, t *tt.Template, d interface{}, o ...Fi
|
|||
return nil
|
||||
}
|
||||
|
||||
// EmbedFromEmbedFS adds an embedded File from an embed.FS to the Msg
|
||||
func (m *Msg) EmbedFromEmbedFS(n string, f *embed.FS, o ...FileOption) error {
|
||||
if f == nil {
|
||||
return fmt.Errorf("embed.FS must not be nil")
|
||||
}
|
||||
ef, err := fileFromEmbedFS(n, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.embeds = m.appendFile(m.embeds, ef, 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() {
|
||||
|
@ -767,6 +794,30 @@ func (m *Msg) addDefaultHeader() {
|
|||
m.SetHeader(HeaderMIMEVersion, string(m.mimever))
|
||||
}
|
||||
|
||||
// fileFromEmbedFS returns a File pointer from a given file in the provided embed.FS
|
||||
func fileFromEmbedFS(n string, f *embed.FS) (*File, error) {
|
||||
_, err := f.Open(n)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file from embed.FS: %w", err)
|
||||
}
|
||||
return &File{
|
||||
Name: filepath.Base(n),
|
||||
Header: make(map[string][]string),
|
||||
Writer: func(w io.Writer) (int64, error) {
|
||||
h, err := f.Open(n)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
nb, err := io.Copy(w, h)
|
||||
if err != nil {
|
||||
_ = h.Close()
|
||||
return nb, fmt.Errorf("failed to copy file to io.Writer: %w", err)
|
||||
}
|
||||
return nb, h.Close()
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// fileFromFS returns a File pointer from a given file in the system's file system
|
||||
func fileFromFS(n string) *File {
|
||||
_, err := os.Stat(n)
|
||||
|
|
92
msg_test.go
92
msg_test.go
|
@ -7,6 +7,7 @@ package mail
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
htpl "html/template"
|
||||
"io"
|
||||
|
@ -18,6 +19,9 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
//go:embed README.md
|
||||
var efs embed.FS
|
||||
|
||||
// TestNewMsg tests the NewMsg method
|
||||
func TestNewMsg(t *testing.T) {
|
||||
m := NewMsg()
|
||||
|
@ -1029,6 +1033,50 @@ func TestMsg_AttachFile(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestMsg_AttachFromEmbedFS tests the Msg.AttachFromEmbedFS and the WithFilename FileOption method
|
||||
func TestMsg_AttachFromEmbedFS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
file string
|
||||
fn string
|
||||
sf bool
|
||||
}{
|
||||
{"File: README.md", "README.md", "README.md", false},
|
||||
{"File: nonexisting", "", "invalid.file", true},
|
||||
}
|
||||
m := NewMsg()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := m.AttachFromEmbedFS(tt.file, &efs, WithFileName(tt.fn)); err != nil && !tt.sf {
|
||||
t.Errorf("AttachFromEmbedFS() failed: %s", err)
|
||||
return
|
||||
}
|
||||
if len(m.attachments) != 1 && !tt.sf {
|
||||
t.Errorf("AttachFile() failed. Number of attachments expected: %d, got: %d", 1,
|
||||
len(m.attachments))
|
||||
return
|
||||
}
|
||||
if !tt.sf {
|
||||
file := m.attachments[0]
|
||||
if file == nil {
|
||||
t.Errorf("AttachFile() failed. Attachment file pointer is nil")
|
||||
return
|
||||
}
|
||||
if file.Name != tt.fn {
|
||||
t.Errorf("AttachFile() failed. Filename of attachment expected: %s, got: %s", tt.fn,
|
||||
file.Name)
|
||||
}
|
||||
buf := bytes.Buffer{}
|
||||
if _, err := file.Writer(&buf); err != nil {
|
||||
t.Errorf("failed to execute WriterFunc: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_AttachFileBrokenFunc tests WriterFunc of the Msg.AttachFile method
|
||||
func TestMsg_AttachFileBrokenFunc(t *testing.T) {
|
||||
m := NewMsg()
|
||||
|
@ -1125,6 +1173,50 @@ func TestMsg_EmbedFile(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestMsg_EmbedFromEmbedFS tests the Msg.EmbedFromEmbedFS and the WithFilename FileOption method
|
||||
func TestMsg_EmbedFromEmbedFS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
file string
|
||||
fn string
|
||||
sf bool
|
||||
}{
|
||||
{"File: README.md", "README.md", "README.md", false},
|
||||
{"File: nonexisting", "", "invalid.file", true},
|
||||
}
|
||||
m := NewMsg()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := m.EmbedFromEmbedFS(tt.file, &efs, WithFileName(tt.fn)); err != nil && !tt.sf {
|
||||
t.Errorf("EmbedFromEmbedFS() failed: %s", err)
|
||||
return
|
||||
}
|
||||
if len(m.embeds) != 1 && !tt.sf {
|
||||
t.Errorf("EmbedFile() failed. Number of embeds expected: %d, got: %d", 1,
|
||||
len(m.embeds))
|
||||
return
|
||||
}
|
||||
if !tt.sf {
|
||||
file := m.embeds[0]
|
||||
if file == nil {
|
||||
t.Errorf("EmbedFile() failed. Embedded file pointer is nil")
|
||||
return
|
||||
}
|
||||
if file.Name != tt.fn {
|
||||
t.Errorf("EmbedFile() failed. Filename of embeds expected: %s, got: %s", tt.fn,
|
||||
file.Name)
|
||||
}
|
||||
buf := bytes.Buffer{}
|
||||
if _, err := file.Writer(&buf); err != nil {
|
||||
t.Errorf("failed to execute WriterFunc: %s", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
m.Reset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestMsg_EmbedFileBrokenFunc tests WriterFunc of the Msg.EmbedFile method
|
||||
func TestMsg_EmbedFileBrokenFunc(t *testing.T) {
|
||||
m := NewMsg()
|
||||
|
|
Loading…
Reference in a new issue