Decode plain text mbox bodies
This commit is contained in:
parent
955c1e0f92
commit
88e82286d8
1 changed files with 61 additions and 1 deletions
|
|
@ -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 {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue