Formatting fixed
diff --git a/README.md b/README.md
index fb6f870..8648e8f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Parsemail - simple email parsing Go library
-[![Build Status](https://circleci.com/gh/DusanKasan/Parsemail.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/DusanKasan/Parsemail) [![Coverage Status](https://coveralls.io/repos/github/DusanKasan/Parsemail/badge.svg?branch=master)](https://coveralls.io/github/DusanKasan/Parsemail?branch=master)
+[![Build Status](https://circleci.com/gh/DusanKasan/Parsemail.svg?style=shield&circle-token=:circle-token)](https://circleci.com/gh/DusanKasan/Parsemail) [![Coverage Status](https://coveralls.io/repos/github/DusanKasan/Parsemail/badge.svg?branch=master)](https://coveralls.io/github/DusanKasan/Parsemail?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/DusanKasan/Parsemail)](https://goreportcard.com/report/github.com/DusanKasan/Parsemail)
This library allows for parsing an email message into a more convenient form than the `net/mail` provides. Where the `net/mail` just gives you a map of header fields and a `io.Reader` of its body, Parsemail allows access to all the standard header fields set in [RFC5322](https://tools.ietf.org/html/rfc5322), html/text body as well as attachements/embedded content as binary streams with metadata.
diff --git a/parsemail.go b/parsemail.go
index 52a1d57..293433f 100644
--- a/parsemail.go
+++ b/parsemail.go
@@ -3,7 +3,6 @@
import (
"bytes"
"encoding/base64"
- "errors"
"fmt"
"io"
"io/ioutil"
@@ -14,12 +13,13 @@
"time"
)
-const content_type_multipart_mixed = "multipart/mixed"
-const content_type_multipart_alternative = "multipart/alternative"
-const content_type_multipart_related = "multipart/related"
-const content_type_text_html = "text/html"
-const content_type_text_plain = "text/plain"
+const contentTypeMultipartMixed = "multipart/mixed"
+const contentTypeMultipartAlternative = "multipart/alternative"
+const contentTypeMultipartRelated = "multipart/related"
+const contentTypeTextHtml = "text/html"
+const contentTypeTextPlain = "text/plain"
+// Parse an email message read from io.Reader into parsemail.Email struct
func Parse(r io.Reader) (email Email, err error) {
msg, err := mail.ReadMessage(r)
if err != nil {
@@ -37,18 +37,18 @@
}
switch contentType {
- case content_type_multipart_mixed:
+ case contentTypeMultipartMixed:
email.TextBody, email.HTMLBody, email.Attachments, email.EmbeddedFiles, err = parseMultipartMixed(msg.Body, params["boundary"])
- case content_type_multipart_alternative:
+ case contentTypeMultipartAlternative:
email.TextBody, email.HTMLBody, email.EmbeddedFiles, err = parseMultipartAlternative(msg.Body, params["boundary"])
- case content_type_text_plain:
+ case contentTypeTextPlain:
message, _ := ioutil.ReadAll(msg.Body)
email.TextBody = strings.TrimSuffix(string(message[:]), "\n")
- case content_type_text_html:
+ case contentTypeTextHtml:
message, _ := ioutil.ReadAll(msg.Body)
email.HTMLBody = strings.TrimSuffix(string(message[:]), "\n")
default:
- err = errors.New(fmt.Sprintf("Unknown top level mime type: %s", contentType))
+ err = fmt.Errorf("Unknown top level mime type: %s", contentType)
}
return
@@ -143,7 +143,7 @@
func parseContentType(contentTypeHeader string) (contentType string, params map[string]string, err error) {
if contentTypeHeader == "" {
- contentType = content_type_text_plain
+ contentType = contentTypeTextPlain
return
}
@@ -203,24 +203,23 @@
contentType, params, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
switch contentType {
- case content_type_text_plain:
+ case contentTypeTextPlain:
ppContent, err := ioutil.ReadAll(part)
if err != nil {
return textBody, htmlBody, embeddedFiles, err
}
textBody += strings.TrimSuffix(string(ppContent[:]), "\n")
- case content_type_text_html:
+ case contentTypeTextHtml:
ppContent, err := ioutil.ReadAll(part)
if err != nil {
return textBody, htmlBody, embeddedFiles, err
}
htmlBody += strings.TrimSuffix(string(ppContent[:]), "\n")
- case content_type_multipart_related:
- var tb, hb string
- var ef []EmbeddedFile
- tb, hb, ef, err = parseMultipartAlternative(part, params["boundary"])
+ case contentTypeMultipartRelated:
+ tb, hb, ef, er := parseMultipartAlternative(part, params["boundary"])
+ err = er
htmlBody += hb
textBody += tb
embeddedFiles = append(embeddedFiles, ef...)
@@ -233,7 +232,7 @@
embeddedFiles = append(embeddedFiles, ef)
} else {
- return textBody, htmlBody, embeddedFiles, errors.New(fmt.Sprintf("Can't process multipart/alternative inner mime type: %s", contentType))
+ return textBody, htmlBody, embeddedFiles, fmt.Errorf("Can't process multipart/alternative inner mime type: %s", contentType)
}
}
}
@@ -256,7 +255,7 @@
return textBody, htmlBody, attachments, embeddedFiles, err
}
- if contentType == content_type_multipart_alternative {
+ if contentType == contentTypeMultipartAlternative {
textBody, htmlBody, embeddedFiles, err = parseMultipartAlternative(part, params["boundary"])
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
@@ -269,7 +268,7 @@
attachments = append(attachments, at)
} else {
- return textBody, htmlBody, attachments, embeddedFiles, errors.New(fmt.Sprintf("Unknown multipart/mixed nested mime type: %s", contentType))
+ return textBody, htmlBody, attachments, embeddedFiles, fmt.Errorf("Unknown multipart/mixed nested mime type: %s", contentType)
}
}
@@ -328,9 +327,9 @@
}
return bytes.NewReader(dd), nil
- } else {
- return nil, errors.New(fmt.Sprintf("Unknown encoding: %s", encoding))
}
+
+ return nil, fmt.Errorf("Unknown encoding: %s", encoding)
}
func isEmbeddedFile(part *multipart.Part) bool {
@@ -377,18 +376,21 @@
return
}
+// Represents email attachment with filename, content type and data (as a io.Reader)
type Attachment struct {
Filename string
ContentType string
Data io.Reader
}
+// Represents email embedded file with content id, content type and data (as a io.Reader)
type EmbeddedFile struct {
CID string
ContentType string
Data io.Reader
}
+// Represents email with fields for all the headers defined in RFC5322 with it's attachments and
type Email struct {
Header mail.Header
diff --git a/parsemail_test.go b/parsemail_test.go
index fb9a231..6904f3b 100644
--- a/parsemail_test.go
+++ b/parsemail_test.go
@@ -39,49 +39,85 @@
headerCheck func(mail.Header, *testing.T)
}{
1: {
- mailData: RFC5322_Example_A11,
+ mailData: rfc5322exampleA11,
subject: "Saying Hello",
from: []mail.Address{
- {"John Doe", "jdoe@machine.example"},
+ {
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ },
},
to: []mail.Address{
- {"Mary Smith", "mary@example.net"},
+ {
+ Name: "Mary Smith",
+ Address: "mary@example.net",
+ },
},
- sender: mail.Address{"Michael Jones", "mjones@machine.example"},
+ sender: mail.Address{
+ Name: "Michael Jones",
+ Address: "mjones@machine.example",
+ },
messageID: "1234@local.machine.example",
date: parseDate("Fri, 21 Nov 1997 09:55:06 -0600"),
textBody: `This is a message just to say hello.
So, "Hello".`,
},
2: {
- mailData: RFC5322_Example_A12,
+ mailData: rfc5322exampleA12,
from: []mail.Address{
- {"Joe Q. Public", "john.q.public@example.com"},
+ {
+ Name: "Joe Q. Public",
+ Address: "john.q.public@example.com",
+ },
},
to: []mail.Address{
- {"Mary Smith", "mary@x.test"},
- {"", "jdoe@example.org"},
- {"Who?", "one@y.test"},
+ {
+ Name: "Mary Smith",
+ Address: "mary@x.test",
+ },
+ {
+ Name: "",
+ Address: "jdoe@example.org",
+ },
+ {
+ Name: "Who?",
+ Address: "one@y.test",
+ },
},
cc: []mail.Address{
- {"", "boss@nil.test"},
- {"Giant; \"Big\" Box", "sysservices@example.net"},
+ {
+ Name: "",
+ Address: "boss@nil.test",
+ },
+ {
+ Name: "Giant; \"Big\" Box",
+ Address: "sysservices@example.net",
+ },
},
messageID: "5678.21-Nov-1997@example.com",
date: parseDate("Tue, 01 Jul 2003 10:52:37 +0200"),
textBody: `Hi everyone.`,
},
3: {
- mailData: RFC5322_Example_A2a,
+ mailData: rfc5322exampleA2a,
subject: "Re: Saying Hello",
from: []mail.Address{
- {"Mary Smith", "mary@example.net"},
+ {
+ Name: "Mary Smith",
+ Address: "mary@example.net",
+ },
},
replyTo: []mail.Address{
- {"Mary Smith: Personal Account", "smith@home.example"},
+ {
+ Name: "Mary Smith: Personal Account",
+ Address: "smith@home.example",
+ },
},
to: []mail.Address{
- {"John Doe", "jdoe@machine.example"},
+ {
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ },
},
messageID: "3456@example.net",
inReplyTo: []string{"1234@local.machine.example"},
@@ -90,13 +126,19 @@
textBody: `This is a reply to your hello.`,
},
4: {
- mailData: RFC5322_Example_A2b,
+ mailData: rfc5322exampleA2b,
subject: "Re: Saying Hello",
from: []mail.Address{
- {"John Doe", "jdoe@machine.example"},
+ {
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ },
},
to: []mail.Address{
- {"Mary Smith: Personal Account", "smith@home.example"},
+ {
+ Name: "Mary Smith: Personal Account",
+ Address: "smith@home.example",
+ },
},
messageID: "abcd.1234@local.machine.test",
inReplyTo: []string{"3456@example.net"},
@@ -105,21 +147,33 @@
textBody: `This is a reply to your reply.`,
},
5: {
- mailData: RFC5322_Example_A3,
+ mailData: rfc5322exampleA3,
subject: "Saying Hello",
from: []mail.Address{
- {"John Doe", "jdoe@machine.example"},
+ {
+ Name: "John Doe",
+ Address: "jdoe@machine.example",
+ },
},
to: []mail.Address{
- {"Mary Smith", "mary@example.net"},
+ {
+ Name: "Mary Smith",
+ Address: "mary@example.net",
+ },
},
messageID: "1234@local.machine.example",
date: parseDate("Fri, 21 Nov 1997 09:55:06 -0600"),
resentFrom: []mail.Address{
- {"Mary Smith", "mary@example.net"},
+ {
+ Name: "Mary Smith",
+ Address: "mary@example.net",
+ },
},
resentTo: []mail.Address{
- {"Jane Brown", "j-brown@other.example"},
+ {
+ Name: "Jane Brown",
+ Address: "j-brown@other.example",
+ },
},
resentMessageID: "78910@example.net",
resentDate: parseDate("Mon, 24 Nov 1997 14:22:01 -0800"),
@@ -127,13 +181,19 @@
So, "Hello".`,
},
6: {
- mailData: Data1,
+ mailData: data1,
subject: "Test Subject 1",
from: []mail.Address{
- {"Peter Paholík", "peter.paholik@gmail.com"},
+ {
+ Name: "Peter Paholík",
+ Address: "peter.paholik@gmail.com",
+ },
},
to: []mail.Address{
- {"", "dusan@kasan.sk"},
+ {
+ Name: "",
+ Address: "dusan@kasan.sk",
+ },
},
messageID: "CACtgX4kNXE7T5XKSKeH_zEcfUUmf2vXVASxYjaaK9cCn-3zb_g@mail.gmail.com",
date: parseDate("Fri, 07 Apr 2017 09:17:26 +0200"),
@@ -147,16 +207,25 @@
},
},
7: {
- mailData: Data2,
+ mailData: data2,
subject: "Re: Test Subject 2",
from: []mail.Address{
- {"Sender Man", "sender@domain.com"},
+ {
+ Name: "Sender Man",
+ Address: "sender@domain.com",
+ },
},
to: []mail.Address{
- {"", "info@receiver.com"},
+ {
+ Name: "",
+ Address: "info@receiver.com",
+ },
},
cc: []mail.Address{
- {"Cc Man", "ccman@gmail.com"},
+ {
+ Name: "Cc Man",
+ Address: "ccman@gmail.com",
+ },
},
messageID: "0e9a21b4-01dc-e5c1-dcd6-58ce5aa61f4f@receiver.com",
inReplyTo: []string{"9ff38d03-c4ab-89b7-9328-e99d5e24e3ba@receiver.eu"},
@@ -313,7 +382,7 @@
}
if len(td.embeddedFiles) != len(e.EmbeddedFiles) {
- t.Errorf("[Test Case %v] Incorrect number of embedded files! Expected: %s, Got: %s.", index, len(td.embeddedFiles), len(e.EmbeddedFiles))
+ t.Errorf("[Test Case %v] Incorrect number of embedded files! Expected: %s, Got: %v.", index, len(td.embeddedFiles), len(e.EmbeddedFiles))
} else {
embeds := e.EmbeddedFiles[:]
@@ -427,7 +496,7 @@
return
}
-var Data1 = `From: =?UTF-8?Q?Peter_Pahol=C3=ADk?= <peter.paholik@gmail.com>
+var data1 = `From: =?UTF-8?Q?Peter_Pahol=C3=ADk?= <peter.paholik@gmail.com>
Date: Fri, 7 Apr 2017 09:17:26 +0200
Message-ID: <CACtgX4kNXE7T5XKSKeH_zEcfUUmf2vXVASxYjaaK9cCn-3zb_g@mail.gmail.com>
Subject: Test Subject 1
@@ -465,7 +534,7 @@
--f403045f1dcc043a44054c8e6bbf--
`
-var Data2 = `Subject: Re: Test Subject 2
+var data2 = `Subject: Re: Test Subject 2
To: info@receiver.com
References: <2f6b7595-c01e-46e5-42bc-f263e1c4282d@receiver.com>
<9ff38d03-c4ab-89b7-9328-e99d5e24e3ba@domain.com>
@@ -514,7 +583,7 @@
--------------C70C0458A558E585ACB75FB4--
`
-var RFC5322_Example_A11 = `From: John Doe <jdoe@machine.example>
+var rfc5322exampleA11 = `From: John Doe <jdoe@machine.example>
Sender: Michael Jones <mjones@machine.example>
To: Mary Smith <mary@example.net>
Subject: Saying Hello
@@ -525,7 +594,7 @@
So, "Hello".
`
-var RFC5322_Example_A12 = `From: "Joe Q. Public" <john.q.public@example.com>
+var rfc5322exampleA12 = `From: "Joe Q. Public" <john.q.public@example.com>
To: Mary Smith <mary@x.test>, jdoe@example.org, Who? <one@y.test>
Cc: <boss@nil.test>, "Giant; \"Big\" Box" <sysservices@example.net>
Date: Tue, 1 Jul 2003 10:52:37 +0200
@@ -536,7 +605,7 @@
//todo: not yet implemented in net/mail
//once there is support for this, add it
-var RFC5322_Example_A13 = `From: Pete <pete@silly.example>
+var rfc5322exampleA13 = `From: Pete <pete@silly.example>
To: A Group:Ed Jones <c@a.test>,joe@where.test,John <jdoe@one.test>;
Cc: Undisclosed recipients:;
Date: Thu, 13 Feb 1969 23:32:54 -0330
@@ -546,7 +615,7 @@
`
//we skipped the first message bcause it's the same as A 1.1
-var RFC5322_Example_A2a = `From: Mary Smith <mary@example.net>
+var rfc5322exampleA2a = `From: Mary Smith <mary@example.net>
To: John Doe <jdoe@machine.example>
Reply-To: "Mary Smith: Personal Account" <smith@home.example>
Subject: Re: Saying Hello
@@ -558,7 +627,7 @@
This is a reply to your hello.
`
-var RFC5322_Example_A2b = `To: "Mary Smith: Personal Account" <smith@home.example>
+var rfc5322exampleA2b = `To: "Mary Smith: Personal Account" <smith@home.example>
From: John Doe <jdoe@machine.example>
Subject: Re: Saying Hello
Date: Fri, 21 Nov 1997 11:00:00 -0600
@@ -569,7 +638,7 @@
This is a reply to your reply.
`
-var RFC5322_Example_A3 = `Resent-From: Mary Smith <mary@example.net>
+var rfc5322exampleA3 = `Resent-From: Mary Smith <mary@example.net>
Resent-To: Jane Brown <j-brown@other.example>
Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800
Resent-Message-ID: <78910@example.net>
@@ -582,7 +651,7 @@
This is a message just to say hello.
So, "Hello".`
-var RFC5322_Example_A4 = `Received: from x.y.test
+var rfc5322exampleA4 = `Received: from x.y.test
by example.net
via TCP
with ESMTP