Decode plain text mbox bodies

This commit is contained in:
DonVoo 2026-07-05 21:46:35 +02:00
parent 955c1e0f92
commit 88e82286d8

View file

@ -2,9 +2,12 @@ package backend
import ( import (
"bytes" "bytes"
"encoding/base64"
"fmt" "fmt"
"io" "io"
"mime" "mime"
"mime/multipart"
"mime/quotedprintable"
"net/mail" "net/mail"
"os" "os"
"path/filepath" "path/filepath"
@ -162,7 +165,64 @@ func messageBody(raw []byte) string {
if err != nil { if err != nil {
return string(raw) return string(raw)
} }
return string(body) return extractTextBody(msg.Header, body)
}
type headerGetter interface {
Get(string) string
}
func extractTextBody(h headerGetter, body []byte) string {
mediaType, params, _ := mime.ParseMediaType(h.Get("Content-Type"))
decoded := decodeTransfer(body, h.Get("Content-Transfer-Encoding"))
if strings.HasPrefix(mediaType, "multipart/") {
boundary := params["boundary"]
if boundary == "" {
return string(decoded)
}
mr := multipart.NewReader(bytes.NewReader(decoded), boundary)
var htmlBody string
for {
part, err := mr.NextPart()
if err == io.EOF {
break
}
if err != nil {
break
}
partBody, _ := io.ReadAll(part)
text := extractTextBody(part.Header, partBody)
partType, _, _ := mime.ParseMediaType(part.Header.Get("Content-Type"))
if strings.HasPrefix(partType, "text/plain") && strings.TrimSpace(text) != "" {
return text
}
if strings.HasPrefix(partType, "text/html") && htmlBody == "" {
htmlBody = text
}
}
if htmlBody != "" {
return htmlBody
}
return ""
}
return string(decoded)
}
func decodeTransfer(body []byte, enc string) []byte {
switch strings.ToLower(strings.TrimSpace(enc)) {
case "quoted-printable":
b, err := io.ReadAll(quotedprintable.NewReader(bytes.NewReader(body)))
if err == nil {
return b
}
case "base64":
cleaned := strings.NewReplacer("\r", "", "\n", "", " ", "", "\t", "").Replace(string(body))
b, err := base64.StdEncoding.DecodeString(cleaned)
if err == nil {
return b
}
}
return body
} }
func safeMboxName(folder string) string { func safeMboxName(folder string) string {