diff --git a/main.go b/main.go index d2a25f2..41bc0d2 100644 --- a/main.go +++ b/main.go @@ -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 }