mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-23 14:10:50 +01:00
Compare commits
4 commits
4c88dce2a8
...
db9893f15a
Author | SHA1 | Date | |
---|---|---|---|
db9893f15a | |||
0cec8a28f7 | |||
9fa8644a9a | |||
70c9387003 |
2 changed files with 312 additions and 22 deletions
27
eml.go
27
eml.go
|
@ -39,11 +39,8 @@ func EMLToMsgFromReader(reader io.Reader) (*Msg, error) {
|
|||
return msg, fmt.Errorf("failed to parse EML from reader: %w", err)
|
||||
}
|
||||
|
||||
if err = parseEMLHeaders(&parsedMsg.Header, msg); err != nil {
|
||||
return msg, fmt.Errorf("failed to parse EML headers: %w", err)
|
||||
}
|
||||
if err = parseEMLBodyParts(parsedMsg, bodybuf, msg); err != nil {
|
||||
return msg, fmt.Errorf("failed to parse EML body parts: %w", err)
|
||||
if err := parseEML(parsedMsg, bodybuf, msg); err != nil {
|
||||
return msg, fmt.Errorf("failed to parse EML contents: %w", err)
|
||||
}
|
||||
|
||||
return msg, nil
|
||||
|
@ -64,17 +61,24 @@ func EMLToMsgFromFile(filePath string) (*Msg, error) {
|
|||
return msg, fmt.Errorf("failed to parse EML file: %w", err)
|
||||
}
|
||||
|
||||
if err = parseEMLHeaders(&parsedMsg.Header, msg); err != nil {
|
||||
return msg, fmt.Errorf("failed to parse EML headers: %w", err)
|
||||
if err := parseEML(parsedMsg, bodybuf, msg); err != nil {
|
||||
return msg, fmt.Errorf("failed to parse EML contents: %w", err)
|
||||
}
|
||||
if err = parseEMLBodyParts(parsedMsg, bodybuf, msg); err != nil {
|
||||
return msg, fmt.Errorf("failed to parse EML body parts: %w", err)
|
||||
}
|
||||
//fmt.Printf("FOO: %+v\n", msg)
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// parseEML parses the EML's headers and body and inserts the parsed values into the Msg
|
||||
func parseEML(parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *Msg) error {
|
||||
if err := parseEMLHeaders(&parsedMsg.Header, msg); err != nil {
|
||||
return fmt.Errorf("failed to parse EML headers: %w", err)
|
||||
}
|
||||
if err := parseEMLBodyParts(parsedMsg, bodybuf, msg); err != nil {
|
||||
return fmt.Errorf("failed to parse EML body parts: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readEML opens an EML file and uses net/mail to parse the header and body
|
||||
func readEML(filePath string) (*netmail.Message, *bytes.Buffer, error) {
|
||||
fileHandle, err := os.Open(filePath)
|
||||
|
@ -195,6 +199,7 @@ func parseEMLBodyParts(parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *M
|
|||
return fmt.Errorf("failed to parse multipart body: %w", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("failed to parse body, unknown content type: %s", mediatype)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
307
eml_test.go
307
eml_test.go
|
@ -5,6 +5,7 @@
|
|||
package mail
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -31,6 +32,115 @@ This is a test mail. Please do not reply to this. Also this line is very long so
|
|||
should be wrapped.
|
||||
|
||||
|
||||
Thank your for your business!
|
||||
The go-mail team
|
||||
|
||||
--
|
||||
This is a signature`
|
||||
exampleMailPlainBrokenBody = `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: base64
|
||||
|
||||
This plain text body should not be parsed as Base64.
|
||||
`
|
||||
exampleMailPlainNoContentType = `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>
|
||||
|
||||
This plain text body should not be parsed as Base64.
|
||||
`
|
||||
exampleMailPlainUnknownContentType = `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: application/unknown; charset=UTF-8
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
This plain text body should not be parsed as Base64.
|
||||
`
|
||||
exampleMailPlainBrokenHeader = `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 = 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!
|
||||
The go-mail team
|
||||
|
||||
--
|
||||
This is a signature`
|
||||
exampleMailPlainBrokenFrom = `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: 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!
|
||||
The go-mail team
|
||||
|
||||
--
|
||||
This is a signature`
|
||||
exampleMailPlainBrokenTo = `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: 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!
|
||||
The go-mail team
|
||||
|
||||
|
@ -99,6 +209,28 @@ This is a test mail. Please do not reply to this. Also this line is very lo=
|
|||
ng so it
|
||||
should be wrapped.
|
||||
|
||||
Thank your for your business!
|
||||
The go-mail team
|
||||
|
||||
--
|
||||
This is a signature`
|
||||
exampleMailPlainUnsupportedTransferEnc = `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 quoted-printable
|
||||
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=ISO-8859-1
|
||||
Content-Transfer-Encoding: unknown
|
||||
|
||||
Dear Customer,
|
||||
|
||||
This is a test mail. Please do not reply to this. Also this line is very long so it should be wrapped.
|
||||
㋛
|
||||
This is not ==D3
|
||||
|
||||
Thank your for your business!
|
||||
The go-mail team
|
||||
|
@ -151,6 +283,37 @@ VGhpcyBpcyBhIHNpbXBsZSB0ZXN0IHRleHQgZmlsZSBhdHRhY2htZW50LgoKSXQgCiAgaGFzCiAg
|
|||
ICAgc2V2ZXJhbAogICAgICAgICAgICBuZXdsaW5lcwoJICAgICAgICAgICAgYW5kCgkgICAgc3Bh
|
||||
Y2VzCiAgICAgaW4KICBpdAouCgpBcyB3ZWxsIGFzIGFuIGVtb2ppOiDwn5mCCg==
|
||||
|
||||
--45c75ff528359022eb03679fbe91877d75343f2e1f8193e349deffa33ff7--`
|
||||
exampleMailPlainB64BrokenBody = `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--`
|
||||
exampleMailPlainB64WithEmbed = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||
MIME-Version: 1.0
|
||||
|
@ -240,22 +403,13 @@ func TestEMLToMsgFromFile(t *testing.T) {
|
|||
}
|
||||
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
|
||||
}
|
||||
tempDir, tempFile, err := stringToTempFile(tt.eml, tt.name)
|
||||
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))
|
||||
msg, err := EMLToMsgFromFile(tempFile)
|
||||
if err != nil {
|
||||
t.Errorf("failed to parse EML: %s", err)
|
||||
}
|
||||
|
@ -270,6 +424,109 @@ func TestEMLToMsgFromFile(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEMLToMsgFromReaderFailing(t *testing.T) {
|
||||
mailbuf := bytes.NewBufferString(exampleMailPlainBrokenFrom)
|
||||
_, err := EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken FROM was supposed to fail, but didn't")
|
||||
}
|
||||
mailbuf.Reset()
|
||||
mailbuf.WriteString(exampleMailPlainBrokenHeader)
|
||||
_, err = EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken header was supposed to fail, but didn't")
|
||||
}
|
||||
mailbuf.Reset()
|
||||
mailbuf.WriteString(exampleMailPlainB64BrokenBody)
|
||||
_, err = EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken body was supposed to fail, but didn't")
|
||||
}
|
||||
mailbuf.Reset()
|
||||
mailbuf.WriteString(exampleMailPlainBrokenBody)
|
||||
_, err = EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken body was supposed to fail, but didn't")
|
||||
}
|
||||
mailbuf.Reset()
|
||||
mailbuf.WriteString(exampleMailPlainUnknownContentType)
|
||||
_, err = EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with unknown content type was supposed to fail, but didn't")
|
||||
}
|
||||
mailbuf.Reset()
|
||||
mailbuf.WriteString(exampleMailPlainNoContentType)
|
||||
_, err = EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with no content type was supposed to fail, but didn't")
|
||||
}
|
||||
mailbuf.Reset()
|
||||
mailbuf.WriteString(exampleMailPlainUnsupportedTransferEnc)
|
||||
_, err = EMLToMsgFromReader(mailbuf)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with unsupported Transer-Encoding was supposed to fail, but didn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEMLToMsgFromFileFailing(t *testing.T) {
|
||||
tempDir, tempFile, err := stringToTempFile(exampleMailPlainBrokenFrom, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken FROM was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
tempDir, tempFile, err = stringToTempFile(exampleMailPlainBrokenHeader, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken header was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
tempDir, tempFile, err = stringToTempFile(exampleMailPlainB64BrokenBody, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken body was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
tempDir, tempFile, err = stringToTempFile(exampleMailPlainBrokenBody, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with broken body was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
tempDir, tempFile, err = stringToTempFile(exampleMailPlainUnknownContentType, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with unknown content type was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
tempDir, tempFile, err = stringToTempFile(exampleMailPlainNoContentType, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with no content type was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
tempDir, tempFile, err = stringToTempFile(exampleMailPlainUnsupportedTransferEnc, "testmail")
|
||||
_, err = EMLToMsgFromFile(tempFile)
|
||||
if err == nil {
|
||||
t.Error("EML from Reader with unsupported Transer-Encoding was supposed to fail, but didn't")
|
||||
}
|
||||
if err = os.RemoveAll(tempDir); err != nil {
|
||||
t.Error("failed to remove temp dir:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEMLToMsgFromStringBrokenDate(t *testing.T) {
|
||||
_, err := EMLToMsgFromString(exampleMailPlainNoEncInvalidDate)
|
||||
if err == nil {
|
||||
|
@ -291,6 +548,20 @@ func TestEMLToMsgFromStringBrokenDate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestEMLToMsgFromStringBrokenFrom(t *testing.T) {
|
||||
_, err := EMLToMsgFromString(exampleMailPlainBrokenFrom)
|
||||
if err == nil {
|
||||
t.Error("EML with broken FROM was supposed to fail, but didn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEMLToMsgFromStringBrokenTo(t *testing.T) {
|
||||
_, err := EMLToMsgFromString(exampleMailPlainBrokenTo)
|
||||
if err == nil {
|
||||
t.Error("EML with broken TO was supposed to fail, but didn't")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEMLToMsgFromStringWithAttachment(t *testing.T) {
|
||||
wantSubject := "Example mail // plain text base64 with attachment"
|
||||
msg, err := EMLToMsgFromString(exampleMailPlainB64WithAttachment)
|
||||
|
@ -322,3 +593,17 @@ func TestEMLToMsgFromStringWithEmbed(t *testing.T) {
|
|||
1, len(msg.attachments))
|
||||
}
|
||||
}
|
||||
|
||||
// stringToTempFile is a helper method that will create a temporary file form a give data string
|
||||
func stringToTempFile(data, name string) (string, string, error) {
|
||||
tempDir, err := os.MkdirTemp("", fmt.Sprintf("*-%s", name))
|
||||
if err != nil {
|
||||
return tempDir, "", fmt.Errorf("failed to create temp dir: %w", err)
|
||||
}
|
||||
filePath := fmt.Sprintf("%s/%s", tempDir, name)
|
||||
err = os.WriteFile(filePath, []byte(data), 0666)
|
||||
if err != nil {
|
||||
return tempDir, "", fmt.Errorf("failed to write data to temp file: %w", err)
|
||||
}
|
||||
return tempDir, filePath, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue