mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-23 22:20:51 +01:00
Compare commits
5 commits
047d923b45
...
52ef13a5d5
Author | SHA1 | Date | |
---|---|---|---|
52ef13a5d5 | |||
e95799ad60 | |||
85c07c22cc | |||
29305675d6 | |||
04c41a1f10 |
2 changed files with 208 additions and 49 deletions
131
eml.go
131
eml.go
|
@ -112,26 +112,8 @@ func parseEMLHeaders(mailHeader *netmail.Header, msg *Msg) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract content type, charset and encoding first
|
// Extract content type, charset and encoding first
|
||||||
if value := mailHeader.Get(HeaderContentTransferEnc.String()); value != "" {
|
parseEMLEncoding(mailHeader, msg)
|
||||||
switch {
|
parseEMLContentTypeCharset(mailHeader, msg)
|
||||||
case strings.EqualFold(value, EncodingQP.String()):
|
|
||||||
msg.SetEncoding(EncodingQP)
|
|
||||||
case strings.EqualFold(value, EncodingB64.String()):
|
|
||||||
msg.SetEncoding(EncodingB64)
|
|
||||||
default:
|
|
||||||
msg.SetEncoding(NoEncoding)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if value := mailHeader.Get(HeaderContentType.String()); value != "" {
|
|
||||||
contentType, charSet := parseContentType(value)
|
|
||||||
if charSet != "" {
|
|
||||||
msg.SetCharset(Charset(charSet))
|
|
||||||
}
|
|
||||||
msg.setEncoder()
|
|
||||||
if contentType != "" {
|
|
||||||
msg.SetGenHeader(HeaderContentType, contentType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract address headers
|
// Extract address headers
|
||||||
if value := mailHeader.Get(HeaderFrom.String()); value != "" {
|
if value := mailHeader.Get(HeaderFrom.String()); value != "" {
|
||||||
|
@ -202,8 +184,8 @@ func parseEMLBodyParts(parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *M
|
||||||
return fmt.Errorf("failed to parse plain body: %w", err)
|
return fmt.Errorf("failed to parse plain body: %w", err)
|
||||||
}
|
}
|
||||||
case strings.EqualFold(mediatype, TypeMultipartAlternative.String()),
|
case strings.EqualFold(mediatype, TypeMultipartAlternative.String()),
|
||||||
strings.EqualFold(mediatype, "multipart/mixed"):
|
strings.EqualFold(mediatype, TypeMultipartMixed.String()):
|
||||||
if err = parseEMLMultipartAlternative(params, bodybuf, msg); err != nil {
|
if err = parseEMLMultipart(params, bodybuf, msg); err != nil {
|
||||||
return fmt.Errorf("failed to parse multipart/alternative body: %w", err)
|
return fmt.Errorf("failed to parse multipart/alternative body: %w", err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -242,18 +224,32 @@ func parseEMLBodyPlain(mediatype string, parsedMsg *netmail.Message, bodybuf *by
|
||||||
return fmt.Errorf("unsupported Content-Transfer-Encoding")
|
return fmt.Errorf("unsupported Content-Transfer-Encoding")
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseEMLMultipartAlternative parses a multipart/alternative body part of a EML
|
// parseEMLMultipart parses a multipart body part of a EML
|
||||||
func parseEMLMultipartAlternative(params map[string]string, bodybuf *bytes.Buffer, msg *Msg) error {
|
func parseEMLMultipart(params map[string]string, bodybuf *bytes.Buffer, msg *Msg) error {
|
||||||
boundary, ok := params["boundary"]
|
boundary, ok := params["boundary"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("no boundary tag found in multipart body")
|
return fmt.Errorf("no boundary tag found in multipart body")
|
||||||
}
|
}
|
||||||
multipartReader := multipart.NewReader(bodybuf, boundary)
|
multipartReader := multipart.NewReader(bodybuf, boundary)
|
||||||
|
ReadNextPart:
|
||||||
multiPart, err := multipartReader.NextPart()
|
multiPart, err := multipartReader.NextPart()
|
||||||
if err != nil {
|
defer func() {
|
||||||
|
if multiPart != nil {
|
||||||
|
_ = multiPart.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err != nil && !errors.Is(err, io.EOF) {
|
||||||
return fmt.Errorf("failed to get next part of multipart message: %w", err)
|
return fmt.Errorf("failed to get next part of multipart message: %w", err)
|
||||||
}
|
}
|
||||||
for err == nil {
|
for err == nil {
|
||||||
|
// Content-Disposition header means we have an attachment or embed
|
||||||
|
if contentDisposition, ok := multiPart.Header[HeaderContentDisposition.String()]; ok {
|
||||||
|
if err := parseEMLAttachmentEmbed(contentDisposition, multiPart, msg); err != nil {
|
||||||
|
return fmt.Errorf("failed to parse attachment/embed: %w", err)
|
||||||
|
}
|
||||||
|
goto ReadNextPart
|
||||||
|
}
|
||||||
|
|
||||||
multiPartData, mperr := io.ReadAll(multiPart)
|
multiPartData, mperr := io.ReadAll(multiPart)
|
||||||
if mperr != nil {
|
if mperr != nil {
|
||||||
_ = multiPart.Close()
|
_ = multiPart.Close()
|
||||||
|
@ -264,9 +260,11 @@ func parseEMLMultipartAlternative(params map[string]string, bodybuf *bytes.Buffe
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("failed to get content-type from part")
|
return fmt.Errorf("failed to get content-type from part")
|
||||||
}
|
}
|
||||||
contentType, charSet := parseContentType(multiPartContentType[0])
|
contentType, optional := parseMultiPartHeader(multiPartContentType[0])
|
||||||
p := msg.newPart(ContentType(contentType))
|
part := msg.newPart(ContentType(contentType))
|
||||||
p.SetCharset(Charset(charSet))
|
if charset, ok := optional["charset"]; ok {
|
||||||
|
part.SetCharset(Charset(charset))
|
||||||
|
}
|
||||||
|
|
||||||
mutliPartTransferEnc, ok := multiPart.Header[HeaderContentTransferEnc.String()]
|
mutliPartTransferEnc, ok := multiPart.Header[HeaderContentTransferEnc.String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -278,25 +276,52 @@ func parseEMLMultipartAlternative(params map[string]string, bodybuf *bytes.Buffe
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.EqualFold(mutliPartTransferEnc[0], EncodingB64.String()):
|
case strings.EqualFold(mutliPartTransferEnc[0], EncodingB64.String()):
|
||||||
if err := handleEMLMultiPartBase64Encoding(multiPartData, p); err != nil {
|
if err := handleEMLMultiPartBase64Encoding(multiPartData, part); err != nil {
|
||||||
return fmt.Errorf("failed to handle multipart base64 transfer-encoding: %w", err)
|
return fmt.Errorf("failed to handle multipart base64 transfer-encoding: %w", err)
|
||||||
}
|
}
|
||||||
case strings.EqualFold(mutliPartTransferEnc[0], EncodingQP.String()):
|
case strings.EqualFold(mutliPartTransferEnc[0], EncodingQP.String()):
|
||||||
p.SetContent(string(multiPartData))
|
part.SetContent(string(multiPartData))
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported Content-Transfer-Encoding")
|
return fmt.Errorf("unsupported Content-Transfer-Encoding")
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.parts = append(msg.parts, p)
|
msg.parts = append(msg.parts, part)
|
||||||
multiPart, err = multipartReader.NextPart()
|
multiPart, err = multipartReader.NextPart()
|
||||||
}
|
}
|
||||||
if !errors.Is(err, io.EOF) {
|
if !errors.Is(err, io.EOF) {
|
||||||
_ = multiPart.Close()
|
|
||||||
return fmt.Errorf("failed to read multipart: %w", err)
|
return fmt.Errorf("failed to read multipart: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseEMLEncoding parses and determines the encoding of the message
|
||||||
|
func parseEMLEncoding(mailHeader *netmail.Header, msg *Msg) {
|
||||||
|
if value := mailHeader.Get(HeaderContentTransferEnc.String()); value != "" {
|
||||||
|
switch {
|
||||||
|
case strings.EqualFold(value, EncodingQP.String()):
|
||||||
|
msg.SetEncoding(EncodingQP)
|
||||||
|
case strings.EqualFold(value, EncodingB64.String()):
|
||||||
|
msg.SetEncoding(EncodingB64)
|
||||||
|
default:
|
||||||
|
msg.SetEncoding(NoEncoding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseEMLContentTypeCharset parses and determines the charset and content type of the message
|
||||||
|
func parseEMLContentTypeCharset(mailHeader *netmail.Header, msg *Msg) {
|
||||||
|
if value := mailHeader.Get(HeaderContentType.String()); value != "" {
|
||||||
|
contentType, optional := parseMultiPartHeader(value)
|
||||||
|
if charset, ok := optional["charset"]; ok {
|
||||||
|
msg.SetCharset(Charset(charset))
|
||||||
|
}
|
||||||
|
msg.setEncoder()
|
||||||
|
if contentType != "" {
|
||||||
|
msg.SetGenHeader(HeaderContentType, contentType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handleEMLMultiPartBase64Encoding sets the content body of a base64 encoded Part
|
// handleEMLMultiPartBase64Encoding sets the content body of a base64 encoded Part
|
||||||
func handleEMLMultiPartBase64Encoding(multiPartData []byte, part *Part) error {
|
func handleEMLMultiPartBase64Encoding(multiPartData []byte, part *Part) error {
|
||||||
part.SetEncoding(EncodingB64)
|
part.SetEncoding(EncodingB64)
|
||||||
|
@ -308,19 +333,37 @@ func handleEMLMultiPartBase64Encoding(multiPartData []byte, part *Part) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseContentType parses the Content-Type header and returns the type and charse as
|
// parseMultiPartHeader parses a multipart header and returns the value and optional parts as
|
||||||
// separate string values
|
// separate map
|
||||||
func parseContentType(contentTypeHeader string) (contentType string, charSet string) {
|
func parseMultiPartHeader(multiPartHeader string) (header string, optional map[string]string) {
|
||||||
contentTypeSplit := strings.SplitN(contentTypeHeader, "; ", 2)
|
optional = make(map[string]string)
|
||||||
if len(contentTypeSplit) != 2 {
|
headerSplit := strings.SplitN(multiPartHeader, "; ", 2)
|
||||||
return
|
header = headerSplit[0]
|
||||||
}
|
if len(headerSplit) == 2 {
|
||||||
contentType = contentTypeSplit[0]
|
optSplit := strings.SplitN(headerSplit[1], "=", 2)
|
||||||
if strings.HasPrefix(strings.ToLower(contentTypeSplit[1]), "charset=") {
|
if len(optSplit) == 2 {
|
||||||
charSetSplit := strings.SplitN(contentTypeSplit[1], "=", 2)
|
optional[optSplit[0]] = optSplit[1]
|
||||||
if len(charSetSplit) == 2 {
|
|
||||||
charSet = charSetSplit[1]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseEMLAttachmentEmbed parses a multipart that is an attachment or embed
|
||||||
|
func parseEMLAttachmentEmbed(contentDisposition []string, multiPart *multipart.Part, msg *Msg) error {
|
||||||
|
cdType, optional := parseMultiPartHeader(contentDisposition[0])
|
||||||
|
filename := "generic.attachment"
|
||||||
|
if name, ok := optional["filename"]; ok {
|
||||||
|
filename = name[1 : len(name)-1]
|
||||||
|
}
|
||||||
|
switch strings.ToLower(cdType) {
|
||||||
|
case "attachment":
|
||||||
|
if err := msg.AttachReader(filename, multiPart); err != nil {
|
||||||
|
return fmt.Errorf("failed to attach multipart body: %w", err)
|
||||||
|
}
|
||||||
|
case "inline":
|
||||||
|
if err := msg.EmbedReader(filename, multiPart); err != nil {
|
||||||
|
return fmt.Errorf("failed to embed multipart body: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
126
eml_test.go
126
eml_test.go
|
@ -5,6 +5,8 @@
|
||||||
package mail
|
package mail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -119,6 +121,37 @@ RGVhciBDdXN0b21lciwKClRoaXMgaXMgYSB0ZXN0IG1haWwuIFBsZWFzZSBkbyBub3QgcmVwbHkg
|
||||||
dG8gdGhpcy4gQWxzbyB0aGlzIGxpbmUgaXMgdmVyeSBsb25nIHNvIGl0CnNob3VsZCBiZSB3cmFw
|
dG8gdGhpcy4gQWxzbyB0aGlzIGxpbmUgaXMgdmVyeSBsb25nIHNvIGl0CnNob3VsZCBiZSB3cmFw
|
||||||
cGVkLgoKClRoYW5rIHlvdXIgZm9yIHlvdXIgYnVzaW5lc3MhClRoZSBnby1tYWlsIHRlYW0KCi0t
|
cGVkLgoKClRoYW5rIHlvdXIgZm9yIHlvdXIgYnVzaW5lc3MhClRoZSBnby1tYWlsIHRlYW0KCi0t
|
||||||
ClRoaXMgaXMgYSBzaWduYXR1cmU=`
|
ClRoaXMgaXMgYSBzaWduYXR1cmU=`
|
||||||
|
exampleMailPlainB64WithAttachment = `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: application/octet-stream; name="test.attachment"
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
||||||
|
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||||
|
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||||
|
|
||||||
|
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEMLToMsgFromString(t *testing.T) {
|
func TestEMLToMsgFromString(t *testing.T) {
|
||||||
|
@ -143,15 +176,68 @@ func TestEMLToMsgFromString(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
m, err := EMLToMsgFromString(tt.eml)
|
msg, err := EMLToMsgFromString(tt.eml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("failed to parse EML: %s", err)
|
t.Errorf("failed to parse EML: %s", err)
|
||||||
}
|
}
|
||||||
if m.Encoding() != tt.enc {
|
if msg.Encoding() != tt.enc {
|
||||||
t.Errorf("EMLToMsgFromString failed: expected encoding: %s, but got: %s", tt.enc, m.Encoding())
|
t.Errorf("EMLToMsgFromString failed: expected encoding: %s, but got: %s", tt.enc, msg.Encoding())
|
||||||
}
|
}
|
||||||
if s := m.GetGenHeader(HeaderSubject); len(s) > 0 && !strings.EqualFold(s[0], tt.sub) {
|
if subject := msg.GetGenHeader(HeaderSubject); len(subject) > 0 && !strings.EqualFold(subject[0], tt.sub) {
|
||||||
t.Errorf("EMLToMsgFromString failed: expected subject: %s, but got: %s", tt.sub, s[0])
|
t.Errorf("EMLToMsgFromString failed: expected subject: %s, but got: %s",
|
||||||
|
tt.sub, subject[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEMLToMsgFromFile(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
eml string
|
||||||
|
enc string
|
||||||
|
sub string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"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 {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tempDir, err := os.MkdirTemp("", fmt.Sprintf("*-%s", tt.name))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to create temp dir: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err = os.RemoveAll(tempDir); err != nil {
|
||||||
|
t.Error("failed to remove temp dir:", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
err = os.WriteFile(fmt.Sprintf("%s/%s.eml", tempDir, tt.name), []byte(tt.eml), 0666)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("failed to write mail to temp file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg, err := EMLToMsgFromFile(fmt.Sprintf("%s/%s.eml", tempDir, tt.name))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to parse EML: %s", err)
|
||||||
|
}
|
||||||
|
if msg.Encoding() != tt.enc {
|
||||||
|
t.Errorf("EMLToMsgFromString failed: expected encoding: %s, but got: %s", tt.enc, msg.Encoding())
|
||||||
|
}
|
||||||
|
if subject := msg.GetGenHeader(HeaderSubject); len(subject) > 0 && !strings.EqualFold(subject[0], tt.sub) {
|
||||||
|
t.Errorf("EMLToMsgFromString failed: expected subject: %s, but got: %s",
|
||||||
|
tt.sub, subject[0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -177,3 +263,33 @@ func TestEMLToMsgFromStringBrokenDate(t *testing.T) {
|
||||||
t.Errorf("EML with no date expected: %s, got: %s", now.Format(time.RFC1123Z), d)
|
t.Errorf("EML with no date expected: %s, got: %s", now.Format(time.RFC1123Z), d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEMLToMsgFromStringWithAttachment(t *testing.T) {
|
||||||
|
wantSubject := "Example mail // plain text base64 with attachment"
|
||||||
|
msg, err := EMLToMsgFromString(exampleMailPlainB64WithAttachment)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("EML with attachment failed: %s", err)
|
||||||
|
}
|
||||||
|
if subject := msg.GetGenHeader(HeaderSubject); len(subject) > 0 && !strings.EqualFold(subject[0], wantSubject) {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML with attachment failed: expected subject: %s, but got: %s",
|
||||||
|
wantSubject, subject[0])
|
||||||
|
}
|
||||||
|
if len(msg.attachments) != 1 {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML with attachment failed: expected no. of attachments: %d, but got: %d",
|
||||||
|
1, len(msg.attachments))
|
||||||
|
}
|
||||||
|
contentTypeHeader := msg.GetGenHeader(HeaderContentType)
|
||||||
|
if len(contentTypeHeader) != 1 {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML with attachment failed: expected no. of content-type header: %d, "+
|
||||||
|
"but got: %d", 1, len(contentTypeHeader))
|
||||||
|
}
|
||||||
|
contentTypeSplit := strings.SplitN(contentTypeHeader[0], "; ", 2)
|
||||||
|
if len(contentTypeSplit) != 2 {
|
||||||
|
t.Error("failed to split Content-Type header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(contentTypeSplit[0], "multipart/mixed") {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML with attachment failed: expected content-type: %s, "+
|
||||||
|
"but got: %s", "multipart/mixed", contentTypeSplit[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue