mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-22 22:00:49 +01:00
Compare commits
17 commits
28dc629674
...
9834c6508d
Author | SHA1 | Date | |
---|---|---|---|
9834c6508d | |||
75e035c783 | |||
769783f037 | |||
9f1e1976fe | |||
887e3cd768 | |||
127cfdf2bc | |||
7ed23bf01b | |||
0310527eb5 | |||
1399a3331a | |||
45ebcb95b3 | |||
1519522e5d | |||
3bf1992cab | |||
4a8ac76636 | |||
5e3ebcc1a6 | |||
040289cea4 | |||
2a2176d700 | |||
e442419c18 |
9 changed files with 1929 additions and 1978 deletions
16
client.go
16
client.go
|
@ -1094,10 +1094,6 @@ func (c *Client) DialAndSendWithContext(ctx context.Context, messages ...*Msg) e
|
||||||
// - An error if the connection check fails, if no supported authentication method is found,
|
// - An error if the connection check fails, if no supported authentication method is found,
|
||||||
// or if the authentication process fails.
|
// or if the authentication process fails.
|
||||||
func (c *Client) auth() error {
|
func (c *Client) auth() error {
|
||||||
if err := c.checkConn(); err != nil {
|
|
||||||
return fmt.Errorf("failed to authenticate: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.smtpAuth == nil && c.smtpAuthType != SMTPAuthNoAuth {
|
if c.smtpAuth == nil && c.smtpAuthType != SMTPAuthNoAuth {
|
||||||
hasSMTPAuth, smtpAuthType := c.smtpClient.Extension("AUTH")
|
hasSMTPAuth, smtpAuthType := c.smtpClient.Extension("AUTH")
|
||||||
if !hasSMTPAuth {
|
if !hasSMTPAuth {
|
||||||
|
@ -1280,12 +1276,6 @@ func (c *Client) sendSingleMsg(message *Msg) error {
|
||||||
affectedMsg: message,
|
affectedMsg: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = c.checkConn(); err != nil {
|
|
||||||
return &SendError{
|
|
||||||
Reason: ErrConnCheck, errlist: []error{err}, isTemp: isTempError(err),
|
|
||||||
affectedMsg: message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1302,6 +1292,9 @@ func (c *Client) sendSingleMsg(message *Msg) error {
|
||||||
// - An error if there is no active connection, if the NOOP command fails, or if extending
|
// - An error if there is no active connection, if the NOOP command fails, or if extending
|
||||||
// the deadline fails; otherwise, returns nil.
|
// the deadline fails; otherwise, returns nil.
|
||||||
func (c *Client) checkConn() error {
|
func (c *Client) checkConn() error {
|
||||||
|
if c.smtpClient == nil {
|
||||||
|
return ErrNoActiveConnection
|
||||||
|
}
|
||||||
if !c.smtpClient.HasConnection() {
|
if !c.smtpClient.HasConnection() {
|
||||||
return ErrNoActiveConnection
|
return ErrNoActiveConnection
|
||||||
}
|
}
|
||||||
|
@ -1360,9 +1353,6 @@ func (c *Client) setDefaultHelo() error {
|
||||||
// - An error if there is no active connection, if STARTTLS is required but not supported,
|
// - An error if there is no active connection, if STARTTLS is required but not supported,
|
||||||
// or if there are issues during the TLS handshake; otherwise, returns nil.
|
// or if there are issues during the TLS handshake; otherwise, returns nil.
|
||||||
func (c *Client) tls() error {
|
func (c *Client) tls() error {
|
||||||
if !c.smtpClient.HasConnection() {
|
|
||||||
return ErrNoActiveConnection
|
|
||||||
}
|
|
||||||
if !c.useSSL && c.tlspolicy != NoTLS {
|
if !c.useSSL && c.tlspolicy != NoTLS {
|
||||||
hasStartTLS := false
|
hasStartTLS := false
|
||||||
extension, _ := c.smtpClient.Extension("STARTTLS")
|
extension, _ := c.smtpClient.Extension("STARTTLS")
|
||||||
|
|
2575
client_test.go
2575
client_test.go
File diff suppressed because it is too large
Load diff
12
eml.go
12
eml.go
|
@ -60,7 +60,7 @@ func EMLToMsgFromReader(reader io.Reader) (*Msg, error) {
|
||||||
return msg, fmt.Errorf("failed to parse EML from reader: %w", err)
|
return msg, fmt.Errorf("failed to parse EML from reader: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := parseEML(parsedMsg, bodybuf, msg); err != nil {
|
if err = parseEML(parsedMsg, bodybuf, msg); err != nil {
|
||||||
return msg, fmt.Errorf("failed to parse EML contents: %w", err)
|
return msg, fmt.Errorf("failed to parse EML contents: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ func EMLToMsgFromFile(filePath string) (*Msg, error) {
|
||||||
return msg, fmt.Errorf("failed to parse EML file: %w", err)
|
return msg, fmt.Errorf("failed to parse EML file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := parseEML(parsedMsg, bodybuf, msg); err != nil {
|
if err = parseEML(parsedMsg, bodybuf, msg); err != nil {
|
||||||
return msg, fmt.Errorf("failed to parse EML contents: %w", err)
|
return msg, fmt.Errorf("failed to parse EML contents: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,9 +218,9 @@ func parseEMLHeaders(mailHeader *netmail.Header, msg *Msg) error {
|
||||||
for _, addr := range parsedAddrs {
|
for _, addr := range parsedAddrs {
|
||||||
addrStrings = append(addrStrings, addr.String())
|
addrStrings = append(addrStrings, addr.String())
|
||||||
}
|
}
|
||||||
if err = addrFunc(addrStrings...); err != nil {
|
// We can skip the error checking here since netmail.ParseAddressList already performed the
|
||||||
return fmt.Errorf(`failed to parse %q header: %w`, addrHeader, err)
|
// same address checking that the msg methods do.
|
||||||
}
|
_ = addrFunc(addrStrings...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,6 +600,8 @@ func parseEMLAttachmentEmbed(contentDisposition []string, multiPart *multipart.P
|
||||||
if err := msg.EmbedReader(filename, dataReader); err != nil {
|
if err := msg.EmbedReader(filename, dataReader); err != nil {
|
||||||
return fmt.Errorf("failed to embed multipart body: %w", err)
|
return fmt.Errorf("failed to embed multipart body: %w", err)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return errors.New("unsupported content disposition type")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
588
eml_test.go
588
eml_test.go
|
@ -6,11 +6,8 @@ package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -22,6 +19,23 @@ Subject: Saying Hello
|
||||||
Date: Fri, 21 Nov 1997 09:55:06 -0600
|
Date: Fri, 21 Nov 1997 09:55:06 -0600
|
||||||
Message-ID: <1234@local.machine.example>
|
Message-ID: <1234@local.machine.example>
|
||||||
|
|
||||||
|
This is a message just to say hello.
|
||||||
|
So, "Hello".`
|
||||||
|
exampleMailRFC5322A11InvalidFrom = `From: §§§§§§§§§
|
||||||
|
To: Mary Smith <mary@example.net>
|
||||||
|
Subject: Saying Hello
|
||||||
|
Date: Fri, 21 Nov 1997 09:55:06 -0600
|
||||||
|
Message-ID: <1234@local.machine.example>
|
||||||
|
|
||||||
|
This is a message just to say hello.
|
||||||
|
So, "Hello".`
|
||||||
|
exampleMailInvalidHeader = `From: John Doe <jdoe@machine.example>
|
||||||
|
To: Mary Smith <mary@example.net>
|
||||||
|
Inva@id*Header; This is a header
|
||||||
|
Subject: Saying Hello
|
||||||
|
Date: Fri, 21 Nov 1997 09:55:06 -0600
|
||||||
|
Message-ID: <1234@local.machine.example>
|
||||||
|
|
||||||
This is a message just to say hello.
|
This is a message just to say hello.
|
||||||
So, "Hello".`
|
So, "Hello".`
|
||||||
exampleMailPlainNoEnc = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
exampleMailPlainNoEnc = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
@ -42,6 +56,52 @@ This is a test mail. Please do not reply to this. Also this line is very long so
|
||||||
should be wrapped.
|
should be wrapped.
|
||||||
|
|
||||||
|
|
||||||
|
Thank your for your business!
|
||||||
|
The go-mail team
|
||||||
|
|
||||||
|
--
|
||||||
|
This is a signature`
|
||||||
|
exampleMailPlainInvalidCTE = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // plain text without encoding
|
||||||
|
User-Agent: go-mail v0.4.0 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.0 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: invalid
|
||||||
|
|
||||||
|
Dear Customer,
|
||||||
|
|
||||||
|
This is a test mail. Please do not reply to this. Also this line is very long so it
|
||||||
|
should be wrapped.
|
||||||
|
|
||||||
|
|
||||||
|
Thank your for your business!
|
||||||
|
The go-mail team
|
||||||
|
|
||||||
|
--
|
||||||
|
This is a signature`
|
||||||
|
exampleMailInvalidContentType = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // plain text without encoding
|
||||||
|
User-Agent: go-mail v0.4.0 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.0 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: text/plain @ charset=UTF-8; $foo; bar; --invalid--
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Dear Customer,
|
||||||
|
|
||||||
|
This is a test mail. Please do not reply to this. Also this line is very long so it
|
||||||
|
should be wrapped.
|
||||||
|
|
||||||
|
|
||||||
Thank your for your business!
|
Thank your for your business!
|
||||||
The go-mail team
|
The go-mail team
|
||||||
|
|
||||||
|
@ -304,6 +364,128 @@ VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
||||||
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||||
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||||
|
exampleMailPlainB64WithAttachmentNoContentType = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // plain text base64 with attachment
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary=45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
RGVhciBDdXN0b21lciwKClRoaXMgaXMgYSB0ZXN0IG1haWwuIFBsZWFzZSBkbyBub3QgcmVwbHkg
|
||||||
|
dG8gdGhpcy4gQWxzbyB0aGlzIGxpbmUgaXMgdmVyeSBsb25nIHNvIGl0CnNob3VsZCBiZSB3cmFw
|
||||||
|
cGVkLgoKClRoYW5rIHlvdXIgZm9yIHlvdXIgYnVzaW5lc3MhClRoZSBnby1tYWlsIHRlYW0KCi0t
|
||||||
|
ClRoaXMgaXMgYSBzaWduYXR1cmU=
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Disposition: attachment; filename="test.attachment"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
||||||
|
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||||
|
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||||
|
exampleMailPlainB64WithAttachmentBrokenB64 = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // plain text base64 with attachment
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary=45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|
||||||
|
RGVhciBDdXN0b21lciwKClRoaXMgaXMgYSB0ZXN0IG1haWwuIFBsZWFzZSBkbyBub3QgcmVwbHkg
|
||||||
|
dG8gdGhpcy4gQWxzbyB0aGl§§§§§@@@@@XMgdmVyeSBsb25nIHNvIGl0CnNob3VsZCBiZSB3cmFw
|
||||||
|
cGVkLgoKClRoYW5rIHlvdXIgZm9yIHlvdXIgYnVzaW5lc3MhClRoZSBnby1tYWlsIHRlYW0KCi0t
|
||||||
|
ClRoaXMgaXMgYSBzaWduYXR1cmU=
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Disposition: attachment; filename="test.attachment"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Type: application/octet-stream; name="test.attachment"
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
||||||
|
ICAgc2V2ZXJhbAogICAg§§§§§@@@@@BuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||||
|
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||||
|
exampleMailPlainB64WithAttachmentInvalidCTE = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // plain text base64 with attachment
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary=45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Transfer-Encoding: invalid
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|
||||||
|
RGVhciBDdXN0b21lciwKClRoaXMgaXMgYSB0ZXN0IG1haWwuIFBsZWFzZSBkbyBub3QgcmVwbHkg
|
||||||
|
dG8gdGhpcy4gQWxzbyB0aGlzIGxpbmUgaXMgdmVyeSBsb25nIHNvIGl0CnNob3VsZCBiZSB3cmFw
|
||||||
|
cGVkLgoKClRoYW5rIHlvdXIgZm9yIHlvdXIgYnVzaW5lc3MhClRoZSBnby1tYWlsIHRlYW0KCi0t
|
||||||
|
ClRoaXMgaXMgYSBzaWduYXR1cmU=
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Disposition: attachment; filename="test.attachment"
|
||||||
|
Content-Transfer-Encoding: invalid
|
||||||
|
Content-Type: application/octet-stream; name="test.attachment"
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
||||||
|
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||||
|
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||||
|
exampleMailPlainB64WithAttachmentInvalidContentType = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // plain text base64 with attachment
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary=45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|
||||||
|
RGVhciBDdXN0b21lciwKClRoaXMgaXMgYSB0ZXN0IG1haWwuIFBsZWFzZSBkbyBub3QgcmVwbHkg
|
||||||
|
dG8gdGhpcy4gQWxzbyB0aGlzIGxpbmUgaXMgdmVyeSBsb25nIHNvIGl0CnNob3VsZCBiZSB3cmFw
|
||||||
|
cGVkLgoKClRoYW5rIHlvdXIgZm9yIHlvdXIgYnVzaW5lc3MhClRoZSBnby1tYWlsIHRlYW0KCi0t
|
||||||
|
ClRoaXMgaXMgYSBzaWduYXR1cmU=
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7
|
||||||
|
Content-Disposition: attachment; filename="test.attachment"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Type; text/plain @ charset=UTF-8; $foo; bar; --invalid--
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
||||||
|
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||||
|
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||||
|
|
||||||
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||||
exampleMailPlainB64WithAttachmentNoBoundary = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
exampleMailPlainB64WithAttachmentNoBoundary = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
|
@ -578,6 +760,39 @@ Content-Disposition: attachment;
|
||||||
filename="testfile.txt"
|
filename="testfile.txt"
|
||||||
|
|
||||||
VGhpcyBpcyBhIHRlc3QgaW4gQmFzZTY0
|
VGhpcyBpcyBhIHRlc3QgaW4gQmFzZTY0
|
||||||
|
--------------26A45336F6C6196BD8BBA2A2--`
|
||||||
|
exampleMultiPart7BitBase64BrokenB64 = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // 7bit with base64 attachment
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Cc: <go-mail+cc@go-mail.dev>
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary="------------26A45336F6C6196BD8BBA2A2"
|
||||||
|
|
||||||
|
This is a multi-part message in MIME format.
|
||||||
|
--------------26A45336F6C6196BD8BBA2A2
|
||||||
|
Content-Type: text/plain; charset=US-ASCII; format=flowed
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
testtest
|
||||||
|
testtest
|
||||||
|
testtest
|
||||||
|
testtest
|
||||||
|
testtest
|
||||||
|
testtest
|
||||||
|
|
||||||
|
--------------26A45336F6C6196BD8BBA2A2
|
||||||
|
Content-Type: text/plain; charset=UTF-8;
|
||||||
|
name="testfile.txt"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Disposition: attachment;
|
||||||
|
filename="testfile.txt"
|
||||||
|
|
||||||
|
VGh@@@@§§§§hIHRlc3QgaW4gQmFzZTY0
|
||||||
--------------26A45336F6C6196BD8BBA2A2--`
|
--------------26A45336F6C6196BD8BBA2A2--`
|
||||||
exampleMultiPart8BitBase64 = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
exampleMultiPart8BitBase64 = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
|
@ -612,8 +827,352 @@ Content-Disposition: attachment;
|
||||||
|
|
||||||
VGhpcyBpcyBhIHRlc3QgaW4gQmFzZTY0
|
VGhpcyBpcyBhIHRlc3QgaW4gQmFzZTY0
|
||||||
--------------26A45336F6C6196BD8BBA2A2--`
|
--------------26A45336F6C6196BD8BBA2A2--`
|
||||||
|
exampleMailWithInlineEmbed = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail with inline embed
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Content-Type: multipart/related; boundary="abc123"
|
||||||
|
|
||||||
|
--abc123
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>Hello,</p>
|
||||||
|
<p>This is an example email with an inline image:</p>
|
||||||
|
<img src="cid:12345@go-mail.dev" alt="Inline Image">
|
||||||
|
<p>Best regards,<br>The go-mail team</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
--abc123
|
||||||
|
Content-Type: image/png
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-ID: <12345@go-mail.dev>
|
||||||
|
Content-Disposition: inline; filename="test.png"
|
||||||
|
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2O
|
||||||
|
UAAAAABJRU5ErkJggg==
|
||||||
|
--abc123--`
|
||||||
|
exampleMailWithInlineEmbedWrongDisposition = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail with inline embed
|
||||||
|
User-Agent: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
X-Mailer: go-mail v0.4.1 // https://github.com/wneessen/go-mail
|
||||||
|
From: "Toni Tester" <go-mail@go-mail.dev>
|
||||||
|
To: <go-mail+test@go-mail.dev>
|
||||||
|
Content-Type: multipart/related; boundary="abc123"
|
||||||
|
|
||||||
|
--abc123
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>Hello,</p>
|
||||||
|
<p>This is an example email with an inline image:</p>
|
||||||
|
<img src="cid:12345@go-mail.dev" alt="Inline Image">
|
||||||
|
<p>Best regards,<br>The go-mail team</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
--abc123
|
||||||
|
Content-Type: image/png
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-ID: <12345@go-mail.dev>
|
||||||
|
Content-Disposition: broken; filename="test.png"
|
||||||
|
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYGD4DwABBAEAwS2O
|
||||||
|
UAAAAABJRU5ErkJggg==
|
||||||
|
--abc123--`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestEMLToMsgFromReader(t *testing.T) {
|
||||||
|
t.Run("EMLToMsgFromReader via EMLToMsgFromString, check subject and encoding", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
emlString string
|
||||||
|
wantEncoding Encoding
|
||||||
|
wantSubject string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"RFC5322 A1.1 example mail", exampleMailRFC5322A11, EncodingUSASCII,
|
||||||
|
"Saying Hello"},
|
||||||
|
{
|
||||||
|
"Plain text no encoding (7bit)", exampleMailPlain7Bit, EncodingUSASCII,
|
||||||
|
"Example mail // plain text without encoding",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Plain text no encoding", exampleMailPlainNoEnc, NoEncoding,
|
||||||
|
"Example mail // plain text without encoding",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Plain text quoted-printable", exampleMailPlainQP, EncodingQP,
|
||||||
|
"Example mail // plain text quoted-printable",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Plain text base64", exampleMailPlainB64, EncodingB64,
|
||||||
|
"Example mail // plain text base64",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
parsed, err := EMLToMsgFromString(tt.emlString)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to parse EML string: %s", err)
|
||||||
|
}
|
||||||
|
if parsed.Encoding() != tt.wantEncoding.String() {
|
||||||
|
t.Errorf("failed to parse EML string: want encoding %s, got %s", tt.wantEncoding,
|
||||||
|
parsed.Encoding())
|
||||||
|
}
|
||||||
|
gotSubject, ok := parsed.genHeader[HeaderSubject]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("failed to parse EML string. No subject header found")
|
||||||
|
}
|
||||||
|
if len(gotSubject) != 1 {
|
||||||
|
t.Fatalf("failed to parse EML string, more than one subject header found")
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(gotSubject[0], tt.wantSubject) {
|
||||||
|
t.Errorf("failed to parse EML string: want subject %s, got %s", tt.wantSubject,
|
||||||
|
gotSubject[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("EMLToMsgFromReader fails on reader", func(t *testing.T) {
|
||||||
|
emlReader := bytes.NewBufferString("invalid")
|
||||||
|
if _, err := EMLToMsgFromReader(emlReader); err == nil {
|
||||||
|
t.Errorf("EML parsing with invalid EML string should fail")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("EMLToMsgFromReader fails on parseEML", func(t *testing.T) {
|
||||||
|
emlReader := bytes.NewBufferString(exampleMailRFC5322A11InvalidFrom)
|
||||||
|
if _, err := EMLToMsgFromReader(emlReader); err == nil {
|
||||||
|
t.Errorf("EML parsing with invalid EML string should fail")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("EMLToMsgFromReader via EMLToMsgFromString on different examples", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
emlString string
|
||||||
|
shouldFail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid RFC 5322 Example",
|
||||||
|
emlString: exampleMailRFC5322A11,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid From Header (RFC 5322)",
|
||||||
|
emlString: exampleMailRFC5322A11InvalidFrom,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Header",
|
||||||
|
emlString: exampleMailInvalidHeader,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Plain broken Content-Type",
|
||||||
|
emlString: exampleMailInvalidContentType,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Plain No Encoding",
|
||||||
|
emlString: exampleMailPlainNoEnc,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Plain invalid CTE",
|
||||||
|
emlString: exampleMailPlainInvalidCTE,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Plain 7bit",
|
||||||
|
emlString: exampleMailPlain7Bit,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Broken Body Base64",
|
||||||
|
emlString: exampleMailPlainBrokenBody,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unknown Content Type",
|
||||||
|
emlString: exampleMailPlainUnknownContentType,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Broken Header",
|
||||||
|
emlString: exampleMailPlainBrokenHeader,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Broken From Header",
|
||||||
|
emlString: exampleMailPlainBrokenFrom,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Broken To Header",
|
||||||
|
emlString: exampleMailPlainBrokenTo,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Date",
|
||||||
|
emlString: exampleMailPlainNoEncInvalidDate,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "No Date Header",
|
||||||
|
emlString: exampleMailPlainNoEncNoDate,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Quoted Printable Encoding",
|
||||||
|
emlString: exampleMailPlainQP,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unsupported Transfer Encoding",
|
||||||
|
emlString: exampleMailPlainUnsupportedTransferEnc,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 Encoding",
|
||||||
|
emlString: exampleMailPlainB64,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Attachment",
|
||||||
|
emlString: exampleMailPlainB64WithAttachment,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Attachment no content types",
|
||||||
|
emlString: exampleMailPlainB64WithAttachmentNoContentType,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart Base64 with Attachment broken Base64",
|
||||||
|
emlString: exampleMailPlainB64WithAttachmentBrokenB64,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Attachment with invalid content type in attachment",
|
||||||
|
emlString: exampleMailPlainB64WithAttachmentInvalidContentType,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Attachment with invalid CTE in attachment",
|
||||||
|
emlString: exampleMailPlainB64WithAttachmentInvalidCTE,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Attachment No Boundary",
|
||||||
|
emlString: exampleMailPlainB64WithAttachmentNoBoundary,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Broken Body Base64",
|
||||||
|
emlString: exampleMailPlainB64BrokenBody,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Embedded Image",
|
||||||
|
emlString: exampleMailPlainB64WithEmbed,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Base64 with Embed No Content-ID",
|
||||||
|
emlString: exampleMailPlainB64WithEmbedNoContentID,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart Mixed with Attachment, Embed, and Alternative Part",
|
||||||
|
emlString: exampleMailMultipartMixedAlternativeRelated,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart 7bit Base64",
|
||||||
|
emlString: exampleMultiPart7BitBase64,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart 7bit Base64 with broken Base64",
|
||||||
|
emlString: exampleMultiPart7BitBase64BrokenB64,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart 8bit Base64",
|
||||||
|
emlString: exampleMultiPart8BitBase64,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart with inline embed",
|
||||||
|
emlString: exampleMailWithInlineEmbed,
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Multipart with inline embed disposition broken",
|
||||||
|
emlString: exampleMailWithInlineEmbedWrongDisposition,
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_, err := EMLToMsgFromString(tt.emlString)
|
||||||
|
if tt.shouldFail && err == nil {
|
||||||
|
t.Errorf("parsing of EML was supposed to fail, but it did not")
|
||||||
|
}
|
||||||
|
if !tt.shouldFail && err != nil {
|
||||||
|
t.Errorf("parsing of EML failed: %s", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEMLToMsgFromFile(t *testing.T) {
|
||||||
|
t.Run("EMLToMsgFromFile succeeds", func(t *testing.T) {
|
||||||
|
parsed, err := EMLToMsgFromFile("testdata/RFC5322-A1-1.eml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("EMLToMsgFromFile failed: %s ", err)
|
||||||
|
}
|
||||||
|
if parsed.Encoding() != EncodingUSASCII.String() {
|
||||||
|
t.Errorf("EMLToMsgFromFile failed: want encoding %s, got %s", EncodingUSASCII,
|
||||||
|
parsed.Encoding())
|
||||||
|
}
|
||||||
|
gotSubject, ok := parsed.genHeader[HeaderSubject]
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("failed to parse EML string. No subject header found")
|
||||||
|
}
|
||||||
|
if len(gotSubject) != 1 {
|
||||||
|
t.Fatalf("failed to parse EML string, more than one subject header found")
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(gotSubject[0], "Saying Hello") {
|
||||||
|
t.Errorf("failed to parse EML string: want subject %s, got %s", "Saying Hello",
|
||||||
|
gotSubject[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
t.Run("EMLToMsgFromFile fails on file not found", func(t *testing.T) {
|
||||||
|
if _, err := EMLToMsgFromFile("testdata/not-existing.eml"); err == nil {
|
||||||
|
t.Errorf("EMLToMsgFromFile with invalid file should fail")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("EMLToMsgFromFile fails on parseEML", func(t *testing.T) {
|
||||||
|
if _, err := EMLToMsgFromFile("testdata/RFC5322-A1-1-invalid-from.eml"); err == nil {
|
||||||
|
t.Errorf("EMLToMsgFromFile with invalid EML message should fail")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
func TestEMLToMsgFromString(t *testing.T) {
|
func TestEMLToMsgFromString(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -621,26 +1180,6 @@ func TestEMLToMsgFromString(t *testing.T) {
|
||||||
enc string
|
enc string
|
||||||
sub string
|
sub string
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
"RFC5322 A1.1", exampleMailRFC5322A11, "7bit",
|
|
||||||
"Saying Hello",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Plain text no encoding (7bit)", exampleMailPlain7Bit, "7bit",
|
|
||||||
"Example mail // plain text without encoding",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Plain text no encoding", exampleMailPlainNoEnc, "8bit",
|
|
||||||
"Example mail // plain text without encoding",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Plain text quoted-printable", exampleMailPlainQP, "quoted-printable",
|
|
||||||
"Example mail // plain text quoted-printable",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Plain text base64", exampleMailPlainB64, "base64",
|
|
||||||
"Example mail // plain text base64",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -1009,3 +1548,6 @@ func stringToTempFile(data, name string) (string, string, error) {
|
||||||
}
|
}
|
||||||
return tempDir, filePath, nil
|
return tempDir, filePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
162
file_test.go
162
file_test.go
|
@ -6,109 +6,160 @@ package mail
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
// TestFile_SetGetHeader tests the set-/getHeader method of the File object
|
func TestFile(t *testing.T) {
|
||||||
func TestFile_SetGetHeader(t *testing.T) {
|
t.Run("setHeader", func(t *testing.T) {
|
||||||
f := File{
|
f := File{
|
||||||
Name: "testfile.txt",
|
Name: "testfile.txt",
|
||||||
Header: make(map[string][]string),
|
Header: make(map[string][]string),
|
||||||
}
|
}
|
||||||
f.setHeader(HeaderContentType, "text/plain")
|
f.setHeader(HeaderContentType, "text/plain")
|
||||||
fi, ok := f.getHeader(HeaderContentType)
|
contentType, ok := f.Header[HeaderContentType.String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("getHeader method of File did not return a value")
|
t.Fatalf("setHeader failed. Expected header %s to be set", HeaderContentType)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if fi != "text/plain" {
|
if len(contentType) != 1 {
|
||||||
t.Errorf("getHeader returned wrong value. Expected: %s, got: %s", "text/plain", fi)
|
t.Fatalf("setHeader failed. Expected header %s to have one value, got: %d", HeaderContentType,
|
||||||
|
len(contentType))
|
||||||
}
|
}
|
||||||
fi, ok = f.getHeader(HeaderContentTransferEnc)
|
if contentType[0] != "text/plain" {
|
||||||
if ok {
|
t.Fatalf("setHeader failed. Expected header %s to have value %s, got: %s",
|
||||||
t.Errorf("getHeader method of File did return a value, but wasn't supposed to")
|
HeaderContentType.String(), "text/plain", contentType[0])
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if fi != "" {
|
})
|
||||||
t.Errorf("getHeader returned wrong value. Expected: %s, got: %s", "", fi)
|
t.Run("getHeader", func(t *testing.T) {
|
||||||
|
f := File{
|
||||||
|
Name: "testfile.txt",
|
||||||
|
Header: make(map[string][]string),
|
||||||
}
|
}
|
||||||
}
|
f.setHeader(HeaderContentType, "text/plain")
|
||||||
|
contentType, ok := f.getHeader(HeaderContentType)
|
||||||
// TestFile_WithFileDescription tests the WithFileDescription option
|
if !ok {
|
||||||
func TestFile_WithFileDescription(t *testing.T) {
|
t.Fatalf("setHeader failed. Expected header %s to be set", HeaderContentType)
|
||||||
|
}
|
||||||
|
if contentType != "text/plain" {
|
||||||
|
t.Fatalf("setHeader failed. Expected header %s to have value %s, got: %s",
|
||||||
|
HeaderContentType.String(), "text/plain", contentType)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("WithFileDescription", func(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
desc string
|
desc string
|
||||||
}{
|
}{
|
||||||
{"File description: test", "test"},
|
{"File description: test", "test"},
|
||||||
|
{"File description: with newline", "test\n"},
|
||||||
{"File description: empty", ""},
|
{"File description: empty", ""},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
m := NewMsg()
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
m.AttachFile("file.go", WithFileDescription(tt.desc))
|
message := NewMsg()
|
||||||
al := m.GetAttachments()
|
message.AttachFile("file.go", WithFileDescription(tt.desc))
|
||||||
if len(al) <= 0 {
|
attachments := message.GetAttachments()
|
||||||
t.Errorf("AttachFile() failed. Attachment list is empty")
|
if len(attachments) <= 0 {
|
||||||
|
t.Fatalf("failed to retrieve attachments list")
|
||||||
}
|
}
|
||||||
a := al[0]
|
firstAttachment := attachments[0]
|
||||||
if a.Desc != tt.desc {
|
if firstAttachment == nil {
|
||||||
t.Errorf("WithFileDescription() failed. Expected: %s, got: %s", tt.desc, a.Desc)
|
t.Fatalf("failed to retrieve first attachment, got nil")
|
||||||
|
}
|
||||||
|
if firstAttachment.Desc != tt.desc {
|
||||||
|
t.Errorf("WithFileDescription() failed. Expected: %s, got: %s", tt.desc,
|
||||||
|
firstAttachment.Desc)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
t.Run("WithFileContentID", func(t *testing.T) {
|
||||||
// TestFile_WithContentID tests the WithFileContentID option
|
|
||||||
func TestFile_WithContentID(t *testing.T) {
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
contentid string
|
id string
|
||||||
}{
|
}{
|
||||||
{"File Content-ID: test", "test"},
|
{"Content-ID: test", "test"},
|
||||||
{"File Content-ID: empty", ""},
|
{"Content-ID: with newline", "test\n"},
|
||||||
|
{"Content-ID: empty", ""},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
m := NewMsg()
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
m.AttachFile("file.go", WithFileContentID(tt.contentid))
|
message := NewMsg()
|
||||||
al := m.GetAttachments()
|
message.AttachFile("file.go", WithFileContentID(tt.id))
|
||||||
if len(al) <= 0 {
|
attachments := message.GetAttachments()
|
||||||
t.Errorf("AttachFile() failed. Attachment list is empty")
|
if len(attachments) <= 0 {
|
||||||
|
t.Fatalf("failed to retrieve attachments list")
|
||||||
}
|
}
|
||||||
a := al[0]
|
firstAttachment := attachments[0]
|
||||||
if a.Header.Get(HeaderContentID.String()) != tt.contentid {
|
if firstAttachment == nil {
|
||||||
t.Errorf("WithFileContentID() failed. Expected: %s, got: %s", tt.contentid,
|
t.Fatalf("failed to retrieve first attachment, got nil")
|
||||||
a.Header.Get(HeaderContentID.String()))
|
}
|
||||||
|
contentID := firstAttachment.Header.Get(HeaderContentID.String())
|
||||||
|
if contentID != tt.id {
|
||||||
|
t.Errorf("WithFileContentID() failed. Expected: %s, got: %s", tt.id,
|
||||||
|
contentID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
t.Run("WithFileEncoding", func(t *testing.T) {
|
||||||
// TestFile_WithFileEncoding tests the WithFileEncoding option
|
|
||||||
func TestFile_WithFileEncoding(t *testing.T) {
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
enc Encoding
|
encoding Encoding
|
||||||
want Encoding
|
want Encoding
|
||||||
}{
|
}{
|
||||||
|
{"File encoding: US-ASCII", EncodingUSASCII, EncodingUSASCII},
|
||||||
{"File encoding: 8bit raw", NoEncoding, NoEncoding},
|
{"File encoding: 8bit raw", NoEncoding, NoEncoding},
|
||||||
{"File encoding: Base64", EncodingB64, EncodingB64},
|
{"File encoding: Base64", EncodingB64, EncodingB64},
|
||||||
{"File encoding: quoted-printable (not allowed)", EncodingQP, ""},
|
{"File encoding: quoted-printable (not allowed)", EncodingQP, ""},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
m := NewMsg()
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
m.AttachFile("file.go", WithFileEncoding(tt.enc))
|
message := NewMsg()
|
||||||
al := m.GetAttachments()
|
message.AttachFile("file.go", WithFileEncoding(tt.encoding))
|
||||||
if len(al) <= 0 {
|
attachments := message.GetAttachments()
|
||||||
t.Errorf("AttachFile() failed. Attachment list is empty")
|
if len(attachments) <= 0 {
|
||||||
|
t.Fatalf("failed to retrieve attachments list")
|
||||||
}
|
}
|
||||||
a := al[0]
|
firstAttachment := attachments[0]
|
||||||
if a.Enc != tt.want {
|
if firstAttachment == nil {
|
||||||
t.Errorf("WithFileEncoding() failed. Expected: %s, got: %s", tt.enc, a.Enc)
|
t.Fatalf("failed to retrieve first attachment, got nil")
|
||||||
|
}
|
||||||
|
if firstAttachment.Enc != tt.want {
|
||||||
|
t.Errorf("WithFileEncoding() failed. Expected: %s, got: %s", tt.want, firstAttachment.Enc)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
t.Run("WithFileName", func(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fileName string
|
||||||
|
}{
|
||||||
|
{"File name: test", "test"},
|
||||||
|
{"File name: with newline", "test\n"},
|
||||||
|
{"File name: empty", ""},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
message := NewMsg()
|
||||||
|
message.AttachFile("file.go", WithFileName(tt.fileName))
|
||||||
|
attachments := message.GetAttachments()
|
||||||
|
if len(attachments) <= 0 {
|
||||||
|
t.Fatalf("failed to retrieve attachments list")
|
||||||
|
}
|
||||||
|
firstAttachment := attachments[0]
|
||||||
|
if firstAttachment == nil {
|
||||||
|
t.Fatalf("failed to retrieve first attachment, got nil")
|
||||||
|
}
|
||||||
|
if firstAttachment.Name != tt.fileName {
|
||||||
|
t.Errorf("WithFileName() failed. Expected: %s, got: %s", tt.fileName,
|
||||||
|
firstAttachment.Name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
// TestFile_WithFileContentType tests the WithFileContentType option
|
// TestFile_WithFileContentType tests the WithFileContentType option
|
||||||
func TestFile_WithFileContentType(t *testing.T) {
|
func TestFile_WithFileContentType(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -137,3 +188,6 @@ func TestFile_WithFileContentType(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
8
testdata/RFC5322-A1-1-invalid-from.eml
vendored
Normal file
8
testdata/RFC5322-A1-1-invalid-from.eml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
From: §§§§§§§§
|
||||||
|
To: Mary Smith <mary@example.net>
|
||||||
|
Subject: Saying Hello
|
||||||
|
Date: Fri, 21 Nov 1997 09:55:06 -0600
|
||||||
|
Message-ID: <1234@local.machine.example>
|
||||||
|
|
||||||
|
This is a message just to say hello.
|
||||||
|
So, "Hello".
|
3
testdata/RFC5322-A1-1-invalid-from.eml.license
vendored
Normal file
3
testdata/RFC5322-A1-1-invalid-from.eml.license
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 The go-mail Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
8
testdata/RFC5322-A1-1.eml
vendored
Normal file
8
testdata/RFC5322-A1-1.eml
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
From: John Doe <jdoe@machine.example>
|
||||||
|
To: Mary Smith <mary@example.net>
|
||||||
|
Subject: Saying Hello
|
||||||
|
Date: Fri, 21 Nov 1997 09:55:06 -0600
|
||||||
|
Message-ID: <1234@local.machine.example>
|
||||||
|
|
||||||
|
This is a message just to say hello.
|
||||||
|
So, "Hello".
|
3
testdata/RFC5322-A1-1.eml.license
vendored
Normal file
3
testdata/RFC5322-A1-1.eml.license
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 The go-mail Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
Loading…
Reference in a new issue