parse multipart emails

This commit is contained in:
Felipe M 2024-11-23 20:08:02 +01:00
parent fcf82bc359
commit 1a809a1184
Signed by: fmartingr
GPG key ID: CCFBC5637D4000A8

69
main.go
View file

@ -1,11 +1,15 @@
package main
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"log"
"log/slog"
"mime"
"mime/multipart"
"net/mail"
"net/url"
"os"
@ -27,22 +31,55 @@ type ReceivedEmail struct {
body string
}
func (re *ReceivedEmail) String() string {
return fmt.Sprintf(`FROM: %s
TO: %s,
BODY: %s`, re.Msg.Header.Get("From"), re.Recipients, re.Body())
}
func (re *ReceivedEmail) Body() string {
func (re *ReceivedEmail) Body() (string, error) {
if re.body == "" {
body, err := io.ReadAll(re.Msg.Body)
if err != nil {
slog.Error("failed to read email body", slog.String("err", err.Error()))
// Get the Content-Type header
contentType := re.Msg.Header.Get("Content-Type")
if contentType == "" {
body, err := io.ReadAll(re.Msg.Body)
if err != nil {
return "", fmt.Errorf("failed to read email body: %w", err)
}
re.body = string(body)
} else {
mediaType, params, err := mime.ParseMediaType(contentType)
if err != nil {
log.Fatalf("Failed to parse Content-Type: %v", err)
}
if strings.HasPrefix(mediaType, "multipart/alternative") {
// Parse the multipart message
mr := multipart.NewReader(re.Msg.Body, params["boundary"])
for {
part, err := mr.NextPart()
if err != nil {
break // End of parts
}
defer part.Close()
// Print part headers
fmt.Printf("Part Content-Type: %s\n", part.Header.Get("Content-Type"))
// Set body if this is the text/plain part
if strings.HasPrefix(part.Header.Get("Content-Type"), "text/plain") {
// Read the part's body
body := new(bytes.Buffer)
_, err = body.ReadFrom(part)
if err != nil {
slog.Error("Failed to read part body", slog.String("err", err.Error()))
return "", fmt.Errorf("failed to read part body: %w", err)
}
re.body = body.String()
break
}
}
}
}
re.body = string(body)
}
return re.body
return re.body, nil
}
type Config struct {
@ -138,7 +175,13 @@ func (bkd *Backend) forwardEmail(email ReceivedEmail) error {
destinationURL := r.GetTargetURL()
destinationURL.RawQuery = urlParams.Encode()
if err := shoutrrr.Send(destinationURL.String(), email.Body()); err != nil {
body, err := email.Body()
if err != nil {
slog.Error("Error getting email body", slog.String("err", err.Error()))
continue
}
if err := shoutrrr.Send(destinationURL.String(), body); err != nil {
slog.Error("Error sending message", slog.String("err", err.Error()))
continue
}