Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support to Encapsulated Messages (message/rfc822) inside multipart/mixed #27

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 28 additions & 14 deletions parsemail.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ const contentTypeMultipartAlternative = "multipart/alternative"
const contentTypeMultipartRelated = "multipart/related"
const contentTypeTextHtml = "text/html"
const contentTypeTextPlain = "text/plain"
const contentTypeEncapsulatedMessage = "message/rfc822"


// Parse an email message read from io.Reader into parsemail.Email struct
func Parse(r io.Reader) (email Email, err error) {
Expand All @@ -39,7 +41,7 @@ func Parse(r io.Reader) (email Email, err error) {

switch contentType {
case contentTypeMultipartMixed:
email.TextBody, email.HTMLBody, email.Attachments, email.EmbeddedFiles, err = parseMultipartMixed(msg.Body, params["boundary"])
email.TextBody, email.HTMLBody, email.Attachments, email.EmbeddedFiles, email.EmbeddedEmails, err = parseMultipartMixed(msg.Body, params["boundary"])
case contentTypeMultipartAlternative:
email.TextBody, email.HTMLBody, email.EmbeddedFiles, err = parseMultipartAlternative(msg.Body, params["boundary"])
case contentTypeMultipartRelated:
Expand Down Expand Up @@ -217,58 +219,69 @@ func parseMultipartAlternative(msg io.Reader, boundary string) (textBody, htmlBo
return textBody, htmlBody, embeddedFiles, err
}

func parseMultipartMixed(msg io.Reader, boundary string) (textBody, htmlBody string, attachments []Attachment, embeddedFiles []EmbeddedFile, err error) {
func parseMultipartMixed(msg io.Reader, boundary string) (textBody, htmlBody string, attachments []Attachment, embeddedFiles []EmbeddedFile, embeddedEmails []Email, err error) {
mr := multipart.NewReader(msg, boundary)
for {
part, err := mr.NextPart()
if err == io.EOF {
break
} else if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

contentType, params, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

if contentType == contentTypeMultipartAlternative {
textBody, htmlBody, embeddedFiles, err = parseMultipartAlternative(part, params["boundary"])
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}
} else if contentType == contentTypeMultipartRelated {
textBody, htmlBody, embeddedFiles, err = parseMultipartRelated(part, params["boundary"])
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}
} else if contentType == contentTypeTextPlain {
ppContent, err := ioutil.ReadAll(part)
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

textBody += strings.TrimSuffix(string(ppContent[:]), "\n")
} else if contentType == contentTypeTextHtml {
ppContent, err := ioutil.ReadAll(part)
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

htmlBody += strings.TrimSuffix(string(ppContent[:]), "\n")
} else if isAttachment(part) {
at, err := decodeAttachment(part)
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

attachments = append(attachments, at)

} else if contentType == contentTypeEncapsulatedMessage {
// message/rfc822
email, err := Parse(part)
if err != nil {
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

embeddedEmails = append(embeddedEmails, email)


} else {
return textBody, htmlBody, attachments, embeddedFiles, fmt.Errorf("Unknown multipart/mixed nested mime type: %s", contentType)
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, fmt.Errorf("Unknown multipart/mixed nested mime type: %s", contentType)
}
}

return textBody, htmlBody, attachments, embeddedFiles, err
return textBody, htmlBody, attachments, embeddedFiles, embeddedEmails, err
}

func decodeMimeSentence(s string) string {
Expand Down Expand Up @@ -488,6 +501,7 @@ type Email struct {
HTMLBody string
TextBody string

Attachments []Attachment
EmbeddedFiles []EmbeddedFile
}
Attachments []Attachment
EmbeddedFiles []EmbeddedFile
EmbeddedEmails []Email
}