parse multipart emails
This commit is contained in:
parent
fcf82bc359
commit
1a809a1184
1 changed files with 56 additions and 13 deletions
69
main.go
69
main.go
|
@ -1,11 +1,15 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"mime"
|
||||||
|
"mime/multipart"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -27,22 +31,55 @@ type ReceivedEmail struct {
|
||||||
body string
|
body string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (re *ReceivedEmail) String() string {
|
func (re *ReceivedEmail) Body() (string, error) {
|
||||||
return fmt.Sprintf(`FROM: %s
|
|
||||||
TO: %s,
|
|
||||||
BODY: %s`, re.Msg.Header.Get("From"), re.Recipients, re.Body())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (re *ReceivedEmail) Body() string {
|
|
||||||
if re.body == "" {
|
if re.body == "" {
|
||||||
body, err := io.ReadAll(re.Msg.Body)
|
// Get the Content-Type header
|
||||||
if err != nil {
|
contentType := re.Msg.Header.Get("Content-Type")
|
||||||
slog.Error("failed to read email body", slog.String("err", err.Error()))
|
|
||||||
|
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 {
|
type Config struct {
|
||||||
|
@ -138,7 +175,13 @@ func (bkd *Backend) forwardEmail(email ReceivedEmail) error {
|
||||||
destinationURL := r.GetTargetURL()
|
destinationURL := r.GetTargetURL()
|
||||||
destinationURL.RawQuery = urlParams.Encode()
|
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()))
|
slog.Error("Error sending message", slog.String("err", err.Error()))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue