Refactor attachment and embed parsing in EML

The EML parsing has been refactored to separate the handling of attachments and embeds into a new helper function. This improves the organization of the code, makes it easier to understand and helps to better manage error handling and resource closing.
This commit is contained in:
Winni Neessen 2024-06-19 14:41:13 +02:00
parent 85c07c22cc
commit e95799ad60
Signed by: wneessen
GPG key ID: 5F3AF39B820C119D

40
eml.go
View file

@ -231,19 +231,23 @@ func parseEMLMultipart(params map[string]string, bodybuf *bytes.Buffer, msg *Msg
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 contentDisposition, ok := multiPart.Header[HeaderContentDisposition.String()]; ok {
cdType, optional := parseMultiPartHeader(contentDisposition[0]) if err := parseEMLAttachmentEmbed(contentDisposition, multiPart, msg); err != nil {
fmt.Println("CTD:", cdType) return fmt.Errorf("failed to parse attachment/embed: %w", err)
fmt.Printf("optional: %+v\n", optional)
if err = msg.AttachReader("", multiPart); err != nil {
return fmt.Errorf("failed to attach multipart body: %w", err)
} }
return nil goto ReadNextPart
} }
multiPartData, mperr := io.ReadAll(multiPart) multiPartData, mperr := io.ReadAll(multiPart)
@ -285,7 +289,6 @@ func parseEMLMultipart(params map[string]string, bodybuf *bytes.Buffer, msg *Msg
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
@ -344,3 +347,24 @@ func parseMultiPartHeader(multiPartHeader string) (header string, optional map[s
} }
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)
}
}
fmt.Printf("FOUND Content: %s\n", cdType)
return nil
}