use gabriel-vasile/mimetype for the mail attachments
This commit is contained in:
parent
824c7db388
commit
9f1946057f
|
@ -1,3 +1,8 @@
|
||||||
|
## v0.27.0 (WIP)
|
||||||
|
|
||||||
|
- Updated the mail attachments auto MIME type detection to use `gabriel-vasile/mimetype` for consistency and broader sniffing signatures support.
|
||||||
|
|
||||||
|
|
||||||
## v0.26.1
|
## v0.26.1
|
||||||
|
|
||||||
- Removed the wrapping of `io.EOF` error when reading files since currently `io.ReadAll` doesn't check for wrapped errors ([#6600](https://github.com/pocketbase/pocketbase/issues/6600)).
|
- Removed the wrapping of `io.EOF` error when reading files since currently `io.ReadAll` doesn't check for wrapped errors ([#6600](https://github.com/pocketbase/pocketbase/issues/6600)).
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package mailer
|
package mailer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
|
|
||||||
|
"github.com/gabriel-vasile/mimetype"
|
||||||
"github.com/pocketbase/pocketbase/tools/hook"
|
"github.com/pocketbase/pocketbase/tools/hook"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,3 +56,17 @@ func addressesToStrings(addresses []mail.Address, withName bool) []string {
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// detectReaderMimeType reads the first couple bytes of the reader to detect its MIME type.
|
||||||
|
//
|
||||||
|
// Returns a new combined reader from the partial read + the remaining of the original reader.
|
||||||
|
func detectReaderMimeType(r io.Reader) (io.Reader, string, error) {
|
||||||
|
readCopy := new(bytes.Buffer)
|
||||||
|
|
||||||
|
mime, err := mimetype.DetectReader(io.TeeReader(r, readCopy))
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return io.MultiReader(readCopy, r), mime.String(), nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package mailer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/mail"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddressesToStrings(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
withName bool
|
||||||
|
addresses []mail.Address
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
true,
|
||||||
|
[]mail.Address{{Name: "John Doe", Address: "test1@example.com"}, {Name: "Jane Doe", Address: "test2@example.com"}},
|
||||||
|
[]string{`"John Doe" <test1@example.com>`, `"Jane Doe" <test2@example.com>`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
true,
|
||||||
|
[]mail.Address{{Name: "John Doe", Address: "test1@example.com"}, {Address: "test2@example.com"}},
|
||||||
|
[]string{`"John Doe" <test1@example.com>`, `test2@example.com`},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
false,
|
||||||
|
[]mail.Address{{Name: "John Doe", Address: "test1@example.com"}, {Name: "Jane Doe", Address: "test2@example.com"}},
|
||||||
|
[]string{`test1@example.com`, `test2@example.com`},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range scenarios {
|
||||||
|
t.Run(fmt.Sprintf("%v_%v", s.withName, s.addresses), func(t *testing.T) {
|
||||||
|
result := addressesToStrings(s.addresses, s.withName)
|
||||||
|
|
||||||
|
if len(s.expected) != len(result) {
|
||||||
|
t.Fatalf("Expected\n%v\ngot\n%v", s.expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range s.expected {
|
||||||
|
if v != result[k] {
|
||||||
|
t.Fatalf("Expected %d address %q, got %q", k, v, result[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetectReaderMimeType(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
str := "#!/bin/node\n" + strings.Repeat("a", 10000) // ensure that it is large enough to remain after the signature sniffing
|
||||||
|
|
||||||
|
r, mime, err := detectReaderMimeType(strings.NewReader(str))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedMime := "text/javascript"
|
||||||
|
if mime != expectedMime {
|
||||||
|
t.Fatalf("Expected mime %q, got %q", expectedMime, mime)
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
rawStr := string(raw)
|
||||||
|
|
||||||
|
if rawStr != str {
|
||||||
|
t.Fatalf("Expected content\n%s\ngot\n%s", str, rawStr)
|
||||||
|
}
|
||||||
|
}
|
|
@ -116,12 +116,20 @@ func (c *SMTPClient) send(m *Message) error {
|
||||||
|
|
||||||
// add regular attachements (if any)
|
// add regular attachements (if any)
|
||||||
for name, data := range m.Attachments {
|
for name, data := range m.Attachments {
|
||||||
yak.Attach(name, data)
|
r, mime, err := detectReaderMimeType(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
yak.AttachWithMimeType(name, r, mime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add inline attachments (if any)
|
// add inline attachments (if any)
|
||||||
for name, data := range m.InlineAttachments {
|
for name, data := range m.InlineAttachments {
|
||||||
yak.AttachInline(name, data)
|
r, mime, err := detectReaderMimeType(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
yak.AttachInlineWithMimeType(name, r, mime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add custom headers (if any)
|
// add custom headers (if any)
|
||||||
|
|
Loading…
Reference in New Issue