From 2abd6a57ee768806756c43a2832030776f826388 Mon Sep 17 00:00:00 2001
From: Philipp Heckel <pheckel@datto.com>
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 22b2f6d..4c8e980 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.24.0 (UNRELEASED)
+
+**Bugs:**
+
+* Support emails without `Content-Type` ([#265](https://github.com/binwiederhier/ntfy/issues/265), thanks to [@dmbonsall](https://github.com/dmbonsall))
+
+-->
+
 ## ntfy server v1.23.0
 Released May 21, 2022
 
diff --git a/server/smtp_server.go b/server/smtp_server.go
index 689deaf..c437d23 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
 		}
-		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
+		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 c954d12..d0e8bfd 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==?=
-- 
GitLab