mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-22 13:50:49 +01:00
Merge pull request #270 from wneessen/feature/262_support-7bit-encoding
Add 7bit support for EML parsing
This commit is contained in:
commit
3ca2968158
4 changed files with 165 additions and 2 deletions
18
eml.go
18
eml.go
|
@ -207,6 +207,12 @@ func parseEMLBodyParts(parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *M
|
||||||
// parseEMLBodyPlain parses the mail body of plain type mails
|
// parseEMLBodyPlain parses the mail body of plain type mails
|
||||||
func parseEMLBodyPlain(mediatype string, parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *Msg) error {
|
func parseEMLBodyPlain(mediatype string, parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *Msg) error {
|
||||||
contentTransferEnc := parsedMsg.Header.Get(HeaderContentTransferEnc.String())
|
contentTransferEnc := parsedMsg.Header.Get(HeaderContentTransferEnc.String())
|
||||||
|
// According to RFC2045, if no Content-Transfer-Encoding is set, we can imply 7bit US-ASCII encoding
|
||||||
|
if contentTransferEnc == "" || strings.EqualFold(contentTransferEnc, EncodingUSASCII.String()) {
|
||||||
|
msg.SetEncoding(EncodingUSASCII)
|
||||||
|
msg.SetBodyString(ContentType(mediatype), bodybuf.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if strings.EqualFold(contentTransferEnc, NoEncoding.String()) {
|
if strings.EqualFold(contentTransferEnc, NoEncoding.String()) {
|
||||||
msg.SetEncoding(NoEncoding)
|
msg.SetEncoding(NoEncoding)
|
||||||
msg.SetBodyString(ContentType(mediatype), bodybuf.String())
|
msg.SetBodyString(ContentType(mediatype), bodybuf.String())
|
||||||
|
@ -308,14 +314,22 @@ ReadNextPart:
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case strings.EqualFold(mutliPartTransferEnc[0], EncodingUSASCII.String()):
|
||||||
|
part.SetEncoding(EncodingUSASCII)
|
||||||
|
part.SetContent(string(multiPartData))
|
||||||
|
case strings.EqualFold(mutliPartTransferEnc[0], NoEncoding.String()):
|
||||||
|
part.SetEncoding(NoEncoding)
|
||||||
|
part.SetContent(string(multiPartData))
|
||||||
case strings.EqualFold(mutliPartTransferEnc[0], EncodingB64.String()):
|
case strings.EqualFold(mutliPartTransferEnc[0], EncodingB64.String()):
|
||||||
if err := handleEMLMultiPartBase64Encoding(multiPartData, part); err != nil {
|
part.SetEncoding(EncodingB64)
|
||||||
|
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()):
|
||||||
|
part.SetEncoding(EncodingQP)
|
||||||
part.SetContent(string(multiPartData))
|
part.SetContent(string(multiPartData))
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported Content-Transfer-Encoding")
|
return fmt.Errorf("unsupported Content-Transfer-Encoding: %s", mutliPartTransferEnc[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.parts = append(msg.parts, part)
|
msg.parts = append(msg.parts, part)
|
||||||
|
|
145
eml_test.go
145
eml_test.go
|
@ -32,6 +32,29 @@ 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`
|
||||||
|
exampleMailPlain7Bit = `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: 7bit
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
@ -525,6 +548,72 @@ hw22iFHl7YlpOmedZvtMTfQffXeXnvI+rTKNxguyvDKvB7U4qQAAAAlwSFlzAAALEwAACxMBAJqc
|
||||||
GAAAABFJREFUCJljnMoAA0wMNGcCAEQrAKk9oHKhAAAAAElFTkSuQmCC
|
GAAAABFJREFUCJljnMoAA0wMNGcCAEQrAKk9oHKhAAAAAElFTkSuQmCC
|
||||||
|
|
||||||
--fe785e0384e2607697cc2ecb17cce003003bb7ca9112104f3e8ce727edb5--`
|
--fe785e0384e2607697cc2ecb17cce003003bb7ca9112104f3e8ce727edb5--`
|
||||||
|
exampleMultiPart7BitBase64 = `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"
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHRlc3QgaW4gQmFzZTY0
|
||||||
|
--------------26A45336F6C6196BD8BBA2A2--`
|
||||||
|
exampleMultiPart8BitBase64 = `Date: Wed, 01 Nov 2023 00:00:00 +0000
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Message-ID: <1305604950.683004066175.AAAAAAAAaaaaaaaaB@go-mail.dev>
|
||||||
|
Subject: Example mail // 8bit 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: 8bit
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
VGhpcyBpcyBhIHRlc3QgaW4gQmFzZTY0
|
||||||
|
--------------26A45336F6C6196BD8BBA2A2--`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEMLToMsgFromString(t *testing.T) {
|
func TestEMLToMsgFromString(t *testing.T) {
|
||||||
|
@ -534,6 +623,10 @@ func TestEMLToMsgFromString(t *testing.T) {
|
||||||
enc string
|
enc string
|
||||||
sub string
|
sub string
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
"Plain text no encoding (7bit)", exampleMailPlain7Bit, "7bit",
|
||||||
|
"Example mail // plain text without encoding",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Plain text no encoding", exampleMailPlainNoEnc, "8bit",
|
"Plain text no encoding", exampleMailPlainNoEnc, "8bit",
|
||||||
"Example mail // plain text without encoding",
|
"Example mail // plain text without encoding",
|
||||||
|
@ -866,6 +959,58 @@ func TestEMLToMsgFromStringMultipartMixedAlternativeRelated(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEMLToMsgFromStringMultipartMixedWith7Bit(t *testing.T) {
|
||||||
|
wantSubject := "Example mail // 7bit with base64 attachment"
|
||||||
|
msg, err := EMLToMsgFromString(exampleMultiPart7BitBase64)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("EML multipart mixed with 7bit: %s", err)
|
||||||
|
}
|
||||||
|
if subject := msg.GetGenHeader(HeaderSubject); len(subject) > 0 && !strings.EqualFold(subject[0], wantSubject) {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 7bit: expected subject: %s,"+
|
||||||
|
" but got: %s", wantSubject, subject[0])
|
||||||
|
}
|
||||||
|
if len(msg.parts) != 1 {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 7bit failed: expected 1 part, got: %d",
|
||||||
|
len(msg.parts))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(msg.parts[0].GetEncoding().String(), EncodingUSASCII.String()) {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 7bit failed: expected encoding: %s, got %s",
|
||||||
|
EncodingUSASCII.String(), msg.parts[0].GetEncoding().String())
|
||||||
|
}
|
||||||
|
if len(msg.attachments) != 1 {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 7bit failed: expected 1 attachment, got: %d",
|
||||||
|
len(msg.attachments))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEMLToMsgFromStringMultipartMixedWith8Bit(t *testing.T) {
|
||||||
|
wantSubject := "Example mail // 8bit with base64 attachment"
|
||||||
|
msg, err := EMLToMsgFromString(exampleMultiPart8BitBase64)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("EML multipart mixed with 8bit: %s", err)
|
||||||
|
}
|
||||||
|
if subject := msg.GetGenHeader(HeaderSubject); len(subject) > 0 && !strings.EqualFold(subject[0], wantSubject) {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 8bit: expected subject: %s,"+
|
||||||
|
" but got: %s", wantSubject, subject[0])
|
||||||
|
}
|
||||||
|
if len(msg.parts) != 1 {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 8bit failed: expected 1 part, got: %d",
|
||||||
|
len(msg.parts))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !strings.EqualFold(msg.parts[0].GetEncoding().String(), NoEncoding.String()) {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 8bit failed: expected encoding: %s, got %s",
|
||||||
|
NoEncoding.String(), msg.parts[0].GetEncoding().String())
|
||||||
|
}
|
||||||
|
if len(msg.attachments) != 1 {
|
||||||
|
t.Errorf("EMLToMsgFromString of EML multipart mixed with 8bit failed: expected 1 attachment, got: %d",
|
||||||
|
len(msg.attachments))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// stringToTempFile is a helper method that will create a temporary file form a give data string
|
// stringToTempFile is a helper method that will create a temporary file form a give data string
|
||||||
func stringToTempFile(data, name string) (string, string, error) {
|
func stringToTempFile(data, name string) (string, string, error) {
|
||||||
tempDir, err := os.MkdirTemp("", fmt.Sprintf("*-%s", name))
|
tempDir, err := os.MkdirTemp("", fmt.Sprintf("*-%s", name))
|
||||||
|
|
|
@ -27,6 +27,9 @@ const (
|
||||||
// EncodingQP represents the "quoted-printable" encoding as specified in RFC 2045.
|
// EncodingQP represents the "quoted-printable" encoding as specified in RFC 2045.
|
||||||
EncodingQP Encoding = "quoted-printable"
|
EncodingQP Encoding = "quoted-printable"
|
||||||
|
|
||||||
|
// EncodingUSASCII represents encoding with only US-ASCII characters (aka 7Bit)
|
||||||
|
EncodingUSASCII Encoding = "7bit"
|
||||||
|
|
||||||
// NoEncoding avoids any character encoding (except of the mail headers)
|
// NoEncoding avoids any character encoding (except of the mail headers)
|
||||||
NoEncoding Encoding = "8bit"
|
NoEncoding Encoding = "8bit"
|
||||||
)
|
)
|
||||||
|
|
|
@ -16,6 +16,7 @@ func TestEncoding_String(t *testing.T) {
|
||||||
{"Encoding: Base64", EncodingB64, "base64"},
|
{"Encoding: Base64", EncodingB64, "base64"},
|
||||||
{"Encoding: QP", EncodingQP, "quoted-printable"},
|
{"Encoding: QP", EncodingQP, "quoted-printable"},
|
||||||
{"Encoding: None/8bit", NoEncoding, "8bit"},
|
{"Encoding: None/8bit", NoEncoding, "8bit"},
|
||||||
|
{"Encoding: US-ASCII/7bit", EncodingUSASCII, "7bit"},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue