From 2abd6a57ee768806756c43a2832030776f826388 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Sat, 21 May 2022 20:20:44 -0400 Subject: [PATCH] Support emails without Content-Type, closes #265 --- docs/releases.md | 10 +++++++ server/smtp_server.go | 56 ++++++++++++++++++++++---------------- server/smtp_server_test.go | 18 ++++++++++++ 3 files changed, 61 insertions(+), 23 deletions(-) diff --git a/docs/releases.md b/docs/releases.md index 22b2f6d3..4c8e980e 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -2,6 +2,16 @@ Binaries for all releases can be found on the GitHub releases pages for the [ntfy server](https://github.com/binwiederhier/ntfy/releases) and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/releases). + + ## ntfy server v1.23.0 Released May 21, 2022 diff --git a/server/smtp_server.go b/server/smtp_server.go index 689deaf3..c437d235 100644 --- a/server/smtp_server.go +++ b/server/smtp_server.go @@ -159,37 +159,47 @@ func (s *smtpSession) withFailCount(fn func() error) error { } func readMailBody(msg *mail.Message) (string, error) { + if msg.Header.Get("Content-Type") == "" { + return readPlainTextMailBody(msg) + } contentType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type")) if err != nil { return "", err } if contentType == "text/plain" { - body, err := io.ReadAll(msg.Body) + return readPlainTextMailBody(msg) + } else if strings.HasPrefix(contentType, "multipart/") { + return readMultipartMailBody(msg, params) + } + return "", errUnsupportedContentType +} + +func readPlainTextMailBody(msg *mail.Message) (string, error) { + body, err := io.ReadAll(msg.Body) + if err != nil { + return "", err + } + return string(body), nil +} + +func readMultipartMailBody(msg *mail.Message, params map[string]string) (string, error) { + mr := multipart.NewReader(msg.Body, params["boundary"]) + for { + part, err := mr.NextPart() + if err != nil { // may be io.EOF + return "", err + } + partContentType, _, err := mime.ParseMediaType(part.Header.Get("Content-Type")) + if err != nil { + return "", err + } + if partContentType != "text/plain" { + continue + } + body, err := io.ReadAll(part) if err != nil { return "", err } return string(body), nil } - if strings.HasPrefix(contentType, "multipart/") { - mr := multipart.NewReader(msg.Body, params["boundary"]) - for { - part, err := mr.NextPart() - if err != nil { // may be io.EOF - return "", err - } - partContentType, _, err := mime.ParseMediaType(part.Header.Get("Content-Type")) - if err != nil { - return "", err - } - if partContentType != "text/plain" { - continue - } - body, err := io.ReadAll(part) - if err != nil { - return "", err - } - return string(body), nil - } - } - return "", errUnsupportedContentType } diff --git a/server/smtp_server_test.go b/server/smtp_server_test.go index c954d124..d0e8bfd2 100644 --- a/server/smtp_server_test.go +++ b/server/smtp_server_test.go @@ -94,6 +94,24 @@ what's up require.Nil(t, session.Data(strings.NewReader(email))) } +func TestSmtpBackend_Plaintext_No_ContentType(t *testing.T) { + email := `Subject: Very short mail + +what's up +` + conf, backend := newTestBackend(t, func(m *message) error { + require.Equal(t, "mytopic", m.Topic) + require.Equal(t, "Very short mail", m.Title) + require.Equal(t, "what's up", m.Message) + return nil + }) + conf.SMTPServerAddrPrefix = "" + session, _ := backend.AnonymousLogin(nil) + require.Nil(t, session.Mail("phil@example.com", smtp.MailOptions{})) + require.Nil(t, session.Rcpt("mytopic@ntfy.sh")) + require.Nil(t, session.Data(strings.NewReader(email))) +} + func TestSmtpBackend_Plaintext_EncodedSubject(t *testing.T) { email := `Date: Tue, 28 Dec 2021 00:30:10 +0100 Subject: =?UTF-8?B?VGhyZWUgc2FudGFzIPCfjoXwn46F8J+OhQ==?=