From d88dbbc90f28af884b7d0d989bb0fe34118c9a4e Mon Sep 17 00:00:00 2001 From: binwiederhier Date: Sun, 2 Apr 2023 13:59:26 -0400 Subject: [PATCH 1/3] WIP --- go.mod | 3 + go.sum | 6 ++ server/smtp_server.go | 77 +++++++++++++++++++---- server/smtp_server_test.go | 125 +++++++++++++++++++++++++++++++++++++ 4 files changed, 200 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index d5a9025e..10d32350 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require github.com/pkg/errors v0.9.1 // indirect require ( firebase.google.com/go/v4 v4.10.0 + github.com/microcosm-cc/bluemonday v1.0.23 github.com/prometheus/client_golang v1.14.0 github.com/stripe/stripe-go/v74 v74.14.0 ) @@ -39,6 +40,7 @@ require ( cloud.google.com/go/longrunning v0.4.1 // indirect github.com/AlekSi/pointer v1.2.0 // indirect github.com/MicahParks/keyfunc v1.9.0 // indirect + github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -50,6 +52,7 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/gax-go/v2 v2.8.0 // indirect + github.com/gorilla/css v1.0.0 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 8c166afd..27679caa 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= github.com/MicahParks/keyfunc v1.9.0/go.mod h1:IdnCilugA0O/99dW+/MkvlyrsX8+L8+x95xuVNtM5jw= +github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= +github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -85,6 +87,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9 github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -95,6 +99,8 @@ github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwp github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/microcosm-cc/bluemonday v1.0.23 h1:SMZe2IGa0NuHvnVNAZ+6B38gsTbi5e4sViiWJyDDqFY= +github.com/microcosm-cc/bluemonday v1.0.23/go.mod h1:mN70sk7UkkF8TUr2IGBpNN0jAgStuPzlK76QuruE/z4= github.com/olebedev/when v0.0.0-20221205223600-4d190b02b8d8 h1:0uFGkScHef2Xd8g74BMHU1jFcnKEm0PzrPn4CluQ9FI= github.com/olebedev/when v0.0.0-20221205223600-4d190b02b8d8/go.mod h1:T0THb4kP9D3NNqlvCwIG4GyUioTAzEhB4RNVzig/43E= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= diff --git a/server/smtp_server.go b/server/smtp_server.go index 16d97328..fe7e3298 100644 --- a/server/smtp_server.go +++ b/server/smtp_server.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "github.com/emersion/go-smtp" + "github.com/microcosm-cc/bluemonday" "io" "mime" "mime/multipart" @@ -13,6 +14,7 @@ import ( "net/http" "net/http/httptest" "net/mail" + "regexp" "strings" "sync" ) @@ -231,37 +233,66 @@ func readMailBody(body io.Reader, header mail.Header) (string, error) { if err != nil { return "", err } - if strings.ToLower(contentType) == "text/plain" { - return readPlainTextMailBody(body, header.Get("Content-Transfer-Encoding")) - } else if strings.HasPrefix(strings.ToLower(contentType), "multipart/") { - return readMultipartMailBody(body, params, 0) + canonicalContentType := strings.ToLower(contentType) + if canonicalContentType == "text/plain" || canonicalContentType == "text/html" { + return readTextMailBody(body, canonicalContentType, header.Get("Content-Transfer-Encoding")) + } else if strings.HasPrefix(canonicalContentType, "multipart/") { + return readMultipartMailBody(body, params) } return "", errUnsupportedContentType } -func readMultipartMailBody(body io.Reader, params map[string]string, depth int) (string, error) { +func readMultipartMailBody(body io.Reader, params map[string]string) (string, error) { + parts := make(map[string]string) + if err := readMultipartMailBodyParts(body, params, 0, parts); err != nil && err != io.EOF { + return "", err + } else if s, ok := parts["text/plain"]; ok { + return s, nil + } else if s, ok := parts["text/html"]; ok { + return s, nil + } + return "", io.EOF +} + +func readMultipartMailBodyParts(body io.Reader, params map[string]string, depth int, parts map[string]string) error { if depth >= maxMultipartDepth { - return "", errMultipartNestedTooDeep + return errMultipartNestedTooDeep } mr := multipart.NewReader(body, params["boundary"]) for { part, err := mr.NextPart() if err != nil { // may be io.EOF - return "", err + return err } partContentType, partParams, err := mime.ParseMediaType(part.Header.Get("Content-Type")) if err != nil { - return "", err + return err } - if strings.ToLower(partContentType) == "text/plain" { - return readPlainTextMailBody(part, part.Header.Get("Content-Transfer-Encoding")) + canonicalPartContentType := strings.ToLower(partContentType) + if canonicalPartContentType == "text/plain" || canonicalPartContentType == "text/html" { + s, err := readTextMailBody(part, canonicalPartContentType, part.Header.Get("Content-Transfer-Encoding")) + if err != nil { + return err + } + parts[canonicalPartContentType] = s } else if strings.HasPrefix(strings.ToLower(partContentType), "multipart/") { - return readMultipartMailBody(part, partParams, depth+1) + if err := readMultipartMailBodyParts(part, partParams, depth+1, parts); err != nil { + return err + } } // Continue with next part } } +func readTextMailBody(reader io.Reader, contentType, transferEncoding string) (string, error) { + if contentType == "text/plain" { + return readPlainTextMailBody(reader, transferEncoding) + } else if contentType == "text/html" { + return readHTMLMailBody(reader, transferEncoding) + } + return "", fmt.Errorf("unsupported content type: %s", contentType) +} + func readPlainTextMailBody(reader io.Reader, transferEncoding string) (string, error) { if strings.ToLower(transferEncoding) == "base64" { reader = base64.NewDecoder(base64.StdEncoding, reader) @@ -272,3 +303,27 @@ func readPlainTextMailBody(reader io.Reader, transferEncoding string) (string, e } return string(body), nil } + +func readHTMLMailBody(reader io.Reader, transferEncoding string) (string, error) { + body, err := readPlainTextMailBody(reader, transferEncoding) + if err != nil { + return "", err + } + stripped := bluemonday. + StrictPolicy(). + AddSpaceWhenStrippingTag(true). + Sanitize(body) + return removeExtraEmptyLines(stripped), nil +} + +func removeExtraEmptyLines(str string) string { + // Replace lines that contain only spaces with empty lines + re := regexp.MustCompile(`(?m)^\s+$`) + str = re.ReplaceAllString(str, "") + + // Remove more than 2 consecutive empty lines + re = regexp.MustCompile(`\n{3,}`) + str = re.ReplaceAllString(str, "\n\n") + + return str +} diff --git a/server/smtp_server_test.go b/server/smtp_server_test.go index 49085d79..1e504521 100644 --- a/server/smtp_server_test.go +++ b/server/smtp_server_test.go @@ -492,6 +492,131 @@ L0VOIj4KClRoaXMgaXMgYSB0ZXN0IG1lc3NhZ2UgZnJvbSBUcnVlTkFTIENPUkUuCg== writeAndReadUntilLine(t, email, c, scanner, "554 5.0.0 Error: transaction failed, blame it on the weather: multipart message nested too deep") } +func TestSmtpBackend_HTMLEmail(t *testing.T) { + email := `EHLO example.com +MAIL FROM: test@mydomain.me +RCPT TO: ntfy-mytopic@ntfy.sh +DATA +Message-Id: <51610934ss4.mmailer@fritz.box> +From: +To: , + +Date: Thu, 30 Mar 2023 02:56:53 +0000 +Subject: A HTML email +Mime-Version: 1.0 +Content-Type: text/html; + charset="utf-8" +Content-Transfer-Encoding: quoted-printable + +<=21DOCTYPE html> + + +Alerttitle + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + +headertext of table + +
+
+ + + + +
+" Very important information about a change in your +home automation setup + +Now the light is on +
+
+ + + + +
+
+If you don't want to recieve this message anymore, stop the push + services in your FRITZ=21Box=2E
+Here you can see the active push services: "System > Push Service"=2E +
+
+ + + + +
+This mail has ben sent by your FRITZ=21Box automatically=2E +
+
+
+ + +. +` + + s, c, _, scanner := newTestSMTPServer(t, func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/mytopic", r.URL.Path) + require.Equal(t, "A HTML email", r.Header.Get("Title")) + require.Equal(t, "what's up", readAll(t, r.Body)) + }) + defer s.Close() + defer c.Close() + writeAndReadUntilLine(t, email, c, scanner, "250 2.0.0 OK: queued") +} + func TestSmtpBackend_PlaintextWithToken(t *testing.T) { email := `EHLO example.com MAIL FROM: phil@example.com From 7f1855ad4dca4d2d75e8374cb02c6d2bf265d836 Mon Sep 17 00:00:00 2001 From: binwiederhier Date: Thu, 16 Nov 2023 09:49:35 -0500 Subject: [PATCH 2/3] It's better than nothing --- docs/releases.md | 1 + server/smtp_server.go | 19 +- server/smtp_server_test.go | 647 ++++++++++++++++++++++++++++++++++++- 3 files changed, 654 insertions(+), 13 deletions(-) diff --git a/docs/releases.md b/docs/releases.md index ef09c741..e56f8847 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1287,6 +1287,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release **Bug fixes + maintenance:** +* Support for HTML-only emails ([#690](https://github.com/binwiederhier/ntfy/issues/690), thanks to [@teastrainer](https://github.com/teastrainer) and [@CrazyWolf13](https://github.com/CrazyWolf13) for reporting) * Fix ACL issue with topic patterns containing underscores ([#840](https://github.com/binwiederhier/ntfy/issues/840), thanks to [@Joe-0237](https://github.com/Joe-0237) for reporting) * Re-add `tzdata` to Docker images for amd64 image ([#894](https://github.com/binwiederhier/ntfy/issues/894), [#307](https://github.com/binwiederhier/ntfy/pull/307)) * Add special logic to ignore `Priority` header if it resembled a RFC 9218 value ([#851](https://github.com/binwiederhier/ntfy/pull/851)/[#895](https://github.com/binwiederhier/ntfy/pull/895), thanks to [@gusdleon](https://github.com/gusdleon), see also [#351](https://github.com/binwiederhier/ntfy/issues/351), [#353](https://github.com/binwiederhier/ntfy/issues/353), [#461](https://github.com/binwiederhier/ntfy/issues/461)) diff --git a/server/smtp_server.go b/server/smtp_server.go index 76f439e7..467b8ca4 100644 --- a/server/smtp_server.go +++ b/server/smtp_server.go @@ -29,6 +29,11 @@ var ( errUnsupportedContentType = errors.New("unsupported content type") ) +var ( + onlySpacesRegex = regexp.MustCompile(`(?m)^\s+$`) + consecutiveNewLinesRegex = regexp.MustCompile(`\n{3,}`) +) + const ( maxMultipartDepth = 2 ) @@ -319,14 +324,8 @@ func readHTMLMailBody(reader io.Reader, transferEncoding string) (string, error) return removeExtraEmptyLines(stripped), nil } -func removeExtraEmptyLines(str string) string { - // Replace lines that contain only spaces with empty lines - re := regexp.MustCompile(`(?m)^\s+$`) - str = re.ReplaceAllString(str, "") - - // Remove more than 2 consecutive empty lines - re = regexp.MustCompile(`\n{3,}`) - str = re.ReplaceAllString(str, "\n\n") - - return str +func removeExtraEmptyLines(s string) string { + s = onlySpacesRegex.ReplaceAllString(s, "") + s = consecutiveNewLinesRegex.ReplaceAllString(s, "\n\n") + return s } diff --git a/server/smtp_server_test.go b/server/smtp_server_test.go index bdee0785..93335905 100644 --- a/server/smtp_server_test.go +++ b/server/smtp_server_test.go @@ -651,7 +651,7 @@ Now the light is on
-If you don't want to recieve this message anymore, stop the push +If you don't want to receive this message anymore, stop the push services in your FRITZ=21Box=2E
Here you can see the active push services: "System > Push Service"=2E @@ -686,7 +686,649 @@ This mail has ben sent by your +Received: from ccm30.constantcontact.com (ccm30.constantcontact.com. [208.75.123.226]) + by mx.google.com with ESMTPS id h2-20020a05620a21c200b0076eeed38118si5450962qka.131.2023.10.30.06.23.07 + for + (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); + Mon, 30 Oct 2023 06:23:08 -0700 (PDT) +Received-SPF: pass (google.com: domain of aigxeklyirlg+dvwkrmsgua==_1133104752381_suqcukvbeeynm/owplvdba==@in.constantcontact.com designates 208.75.123.226 as permitted sender) client-ip=208.75.123.226; +Authentication-Results: mx.google.com; + dkim=pass header.i=@spamspam.com header.s=2020294246 header.b=G8y6xmtK; + dkim=pass header.i=@auth.ccsend.com header.s=1000073432 header.b=ht8IksVK; + spf=pass (google.com: domain of aigxeklyirlg+dvwkrmsgua==_1133104752381_suqcukvbeeynm/owplvdba==@in.constantcontact.com designates 208.75.123.226 as permitted sender) smtp.mailfrom="AigXeKlyIRLG+DvWkRMsGUA==_1133104752381_sUQcUKVBEeynm/oWPlvDBA==@in.constantcontact.com"; + dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=spamspam.com +Return-Path: +Received: from [10.252.0.3] ([10.252.0.3:53254] helo=p2-jbemailsyndicator12.ctct.net) by 10.249.225.20 (envelope-from ) (ecelerity 4.3.1.999 r(:)) with ESMTP id A4/82-60517-B3EAF356; Mon, 30 Oct 2023 09:23:07 -0400 +DKIM-Signature: v=1; q=dns/txt; a=rsa-sha256; c=relaxed/relaxed; s=2020294246; d=spamspam.com; h=date:mime-version:subject:X-Feedback-ID:X-250ok-CID:message-id:from:reply-to:list-unsubscribe:list-unsubscribe-post:to; bh=BERwBIp6fBgrZePFKQjyNMmgPkcnq1Zy1jPO8M0T4Ok=; b=G8y6xmtKv8asfEXA9o8dP+6foQjclo6j5sFREYVIJBbj5YJ5tqoiv5B04/qoRkoTBFDhmjt+BUua7AqDgPSnwbP2iPSA4fTJehnHhut1PyVUp/9vqSYlhxQehfdhma8tPg8ArKfYIKmfKJwKRaQBU0JHCaB1m+5LNQQX3UjkxAg= +DKIM-Signature: v=1; q=dns/txt; a=rsa-sha256; c=relaxed/relaxed; s=1000073432; d=auth.ccsend.com; h=date:mime-version:subject:X-Feedback-ID:X-250ok-CID:message-id:from:reply-to:list-unsubscribe:list-unsubscribe-post:to; bh=BERwBIp6fBgrZePFKQjyNMmgPkcnq1Zy1jPO8M0T4Ok=; b=ht8IksVKYY/Kb3dUERWoeW4eVdYjKL6F4PEoIZOhfFXor6XAIbPnd3A/CPmbmoqFZjnKh5OdcUy1N5qEoj8w1Q3TmN8/ySQkqrlrmSDSZIHZMY7Qp9/TJrqUe4RMFOO1KKIN6Y0vGP1+dWe98msMAHwvi2qMjG9aEKLfFr2JUTQ= +Message-ID: <1140728754828.1133104752381.1941549819.0.260913JL.2002@synd.ccsend.com> +Date: Mon, 30 Oct 2023 09:23:07 -0400 (EDT) +From: spamspam Loan Servicing +Reply-To: marklake@spamspam.com +To: somebody@gmail.com +Subject: Buying a home? You deserve the confidence of Pre-Approval +MIME-Version: 1.0 +Content-Type: multipart/alternative; boundary="----=_Part_75055660_144854819.1698672187348" +List-Unsubscribe: +List-Unsubscribe-Post: List-Unsubscribe=One-Click +X-Campaign-Activity-ID: 8a05de2a-5c88-44b1-be0e-f5a444cb0650 +X-250ok-CID: 8a05de2a-5c88-44b1-be0e-f5a444cb0650 +X-Channel-ID: b1441c50-a541-11ec-a79b-fa163e5bc304 +X-Return-Path-Hint: AbeefbeefbeefbeefbeefUA==_1133104752381_sUQcUKVBEeynm/oWPlvDBA==@in.constantcontact.com +X-Roving-Campaignid: 1140728754811 +X-Roving-Id: 1133104752381.1111111111 +X-Feedback-ID: b1441c50-a541-11ec-beef-beefbeefbeefbeef5de2a-5c88-44b1-be0e-f5a444cb0650:1133104752381:CTCT +X-CTCT-ID: b13a9586-a541-11ec-beef-beefbeefbeef + +------=_Part_75055660_144854819.1698672187348 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + +When you're buying a home, Pre-Approval gives you confidence you're in the = +right price range and shows sellers you mean business. xxxxxxxxx SELLING or= + BUYING? Call: 844-590-2275 Get Your Homebuying PRE-APPROVAL IN 24-HOURS* G= +et Pre-Approved When you're buying a home, Pre-Approval gives you confidenc= +e you're in the right price range and shows sellers you mean business. xxx= +xxxxxxGet Pre-Approved today! Click or Call to Get Pre-Approved 844-590-227= +5 Get Pre-Approved nmlsconsumeraccess.org/ *The 24 hour timeframe is for mo= +st approvals, however if additional information is needed or a request is o= +n a holiday, the time for preapproval may be greater than 24 hours. This em= +ail is for informational purposes only and is not an offer, loan approval o= +r loan commitment. Mortgage rates are subject to change without notice. Som= +e terms and restrictions may apply to certain loan programs. Refinancing ex= +isting loans may result in total finance charges being higher over the life= + of the loan, reduction in payments may partially reflect a longer loan ter= +m. This information is provided as guidance and illustrative purposes only = +and does not constitute legal or financial advice. We are not liable or bou= +nd legally for any answers provided to any user for our process or position= + on an issue. This information may change from time to time and at any time= + without notification. The most current information will be updated periodi= +cally and posted in the online forum. spamspam Loan Servicing, LLC. NMLS#39= +1521. nmlsconsumeraccess.org. You are receiving this information as a curre= +nt loan customer with spamspam Loan Servicing, LLC. Not licensed for lendin= +g activities in any of the U.S. territories. Not authorized to originate lo= +ans in the State of New York. Licensed by the Dept. of Financial Protection= + and Innovation under the California Residential Mortgage .Lending Act #413= +1216. This email was sent to somebody@gmail.com Version 103023PCHPrAp= +9 xxxxxxxxx spamspam Loan Servicing | 4425 Ponce de Leon Blvd 5-251, Coral = +Gables, FL 33146-1837 Unsubscribe somebody@gmail.com Update Profile |= + Our Privacy Policy | Constant Contact Data Notice Sent by marklake@spamspa= +m.com +------=_Part_75055660_144854819.1698672187348 +Content-Type: text/html; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + + +
When you're buying a home, Pre-Approval = +gives you confidence you're in the right price range and shows sellers= + you mean business.
3D""
+
= +
3D""
= +
+
3D""
+
+

SELLING or BUYING?

+

Call: 844-590-2275

+
+
+

Get Your Homebuying

+

PRE-APPROVAL IN 24-HOURS*

+
= + 3D"" = +
Get Pre-Approved
= + +


+

When you're buying= + a home, Pre-Approval gives you confidence you're in the right price range = +and shows sellers you mean business.

+

Get Pre-Ap= +proved today!

+
+
+


+

Click or Call to Get Pre-Approved

+

844-590-2275= +

+
Get Pre-Approved
+
3D""
<= +tr>
+
+


+

nmlsconsumeraccess.org/

+

*The 24 hour timeframe is for= + most approvals, however if additional information is needed or a request i= +s on a holiday, the time for preapproval may be greater than 24 hours.

+

This email is for informational purposes only and is not an offer,= + loan approval or loan commitment. Mortgage rates are subject to change wit= +hout notice. Some terms and restrictions may apply to certain loan programs= +. Refinancing existing loans may result in total finance charges being high= +er over the life of the loan, reduction in payments may partially reflect a= + longer loan term. This information is provided as guidance and illustrativ= +e purposes only and does not constitute legal or financial advice. We are n= +ot liable or bound legally for any answers provided to any user for our pro= +cess or position on an issue. This information may change from time to time= + and at any time without notification. The most current information will be= + updated periodically and posted in the online forum.

+

spamspam Loan Servicing, LLC. NMLS#391521. nmlsconsumeraccess.org.= + You are receiving this information as a current loan customer with spamspa= +m Loan Servicing, LLC. Not licensed for lending activities in any of the U.= +S. territories. Not authorized to originate loans in the State of New York.= + Licensed by the Dept. of Financial Protection and Innovation under the Cal= +ifornia Residential Mortgage .Lending Act #4131216.

+


+

This email was sent to somebody@gmail.com

+

Version 103023PCHPrAp9

+



+
+
= +
3D""
= +
= +
+ + + +
+
+ + + + +
+ + + + + + + + + + +
+spamspam Loan Servicing | 4425 Ponce de= + Leon Blvd 5-251, Coral Gables, FL 33146-1837 +
+ + + + + + + + + + +
+Uns= +ubscribe somebody@gmail.com + +
+Upd= +ate Profile | +Our Privacy Policy | +Constant Contact Data Noti= +ce +
+Sent by +marklake@spamspam.com +
+
+
+
+
+
= +
+ +------=_Part_75055660_144854819.1698672187348-- +. +` + +func TestSmtpBackend_Spam_Text(t *testing.T) { + email := spamEmail + s, c, _, scanner := newTestSMTPServer(t, func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/mytopic", r.URL.Path) + require.Equal(t, "Buying a home? You deserve the confidence of Pre-Approval", r.Header.Get("Title")) + actual := readAll(t, r.Body) + expected := "When you're buying a home, Pre-Approval gives you confidence you're in the right price range and shows sellers you mean business. xxxxxxxxx SELLING or BUYING? Call: 844-590-2275 Get Your Homebuying PRE-APPROVAL IN 24-HOURS* Get Pre-Approved When you're buying a home, Pre-Approval gives you confidence you're in the right price range and shows sellers you mean business. xxxxxxxxxGet Pre-Approved today! Click or Call to Get Pre-Approved 844-590-2275 Get Pre-Approved nmlsconsumeraccess.org/ *The 24 hour timeframe is for most approvals, however if additional information is needed or a request is on a holiday, the time for preapproval may be greater than 24 hours. This email is for informational purposes only and is not an offer, loan approval or loan commitment. Mortgage rates are subject to change without notice. Some terms and restrictions may apply to certain loan programs. Refinancing existing loans may result in total finance charges being higher over the life of the loan, reduction in payments may partially reflect a longer loan term. This information is provided as guidance and illustrative purposes only and does not constitute legal or financial advice. We are not liable or bound legally for any answers provided to any user for our process or position on an issue. This information may change from time to time and at any time without notification. The most current information will be updated periodically and posted in the online forum. spamspam Loan Servicing, LLC. NMLS#391521. nmlsconsumeraccess.org. You are receiving this information as a current loan customer with spamspam Loan Servicing, LLC. Not licensed for lending activities in any of the U.S. territories. Not authorized to originate loans in the State of New York. Licensed by the Dept. of Financial Protection and Innovation under the California Residential Mortgage .Lending Act #4131216. This email was sent to somebody@gmail.com Version 103023PCHPrAp9 xxxxxxxxx spamspam Loan Servicing | 4425 Ponce de Leon Blvd 5-251, Coral Gables, FL 33146-1837 Unsubscribe somebody@gmail.com Update Profile | Our Privacy Policy | Constant Contact Data Notice Sent by marklake@spamspam.com" + require.Equal(t, expected, actual) + }) + defer s.Close() + defer c.Close() + writeAndReadUntilLine(t, email, c, scanner, "250 2.0.0 OK: queued") +} + +func TestSmtpBackend_Spam_HTML(t *testing.T) { + email := strings.ReplaceAll(spamEmail, "text/plain", "text/not-plain-anymore") // We artificially force HTML parsing here + s, c, _, scanner := newTestSMTPServer(t, func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/mytopic", r.URL.Path) + require.Equal(t, "Buying a home? You deserve the confidence of Pre-Approval", r.Header.Get("Title")) + actual := readAll(t, r.Body) + expected := `When you're buying a home, Pre-Approval gives you confidence you're in the right price range and shows sellers you mean business. + ` + "\u200a" + ` + + SELLING or BUYING? + Call: 844-590-2275 + + Get Your Homebuying + PRE-APPROVAL IN 24-HOURS * + Get Pre-Approved + + When you're buying a home, Pre-Approval gives you confidence you're in the right price range and shows sellers you mean business. + ` + "\ufeff" + `Get Pre-Approved today! + + Click or Call to Get Pre-Approved + 844-590-2275 + Get Pre-Approved + + nmlsconsumeraccess.org/ + *The 24 hour timeframe is for most approvals, however if additional information is needed or a request is on a holiday, the time for preapproval may be greater than 24 hours. + This email is for informational purposes only and is not an offer, loan approval or loan commitment. Mortgage rates are subject to change without notice. Some terms and restrictions may apply to certain loan programs Refinancing existing loans may result in total finance charges being higher over the life of the loan, reduction in payments may partially reflect a longer loan term. This information is provided as guidance and illustrative purposes only and does not constitute legal or financial advice. We are not liable or bound legally for any answers provided to any user for our process or position on an issue. This information may change from time to time and at any time without notification. The most current information will be updated periodically and posted in the online forum. + spamspam Loan Servicing, LLC. NMLS#391521. nmlsconsumeraccess.org. You are receiving this information as a current loan customer with spamspam Loan Servicing, LLC. Not licensed for lending activities in any of the U.S. territories. Not authorized to originate loans in the State of New York. Licensed by the Dept. of Financial Protection and Innovation under the California Residential Mortgage .Lending Act #4131216. + + This email was sent to somebody@gmail.com + Version 103023PCHPrAp9 + ` + "\ufeff" + ` + + spamspam Loan Servicing | 4425 Ponce de Leon Blvd 5-251 , Coral Gables, FL 33146-1837 + + Unsubscribe somebody@gmail.com + + Update Profile | + Our Privacy Policy | + Constant Contact Data Notice + +Sent by + marklake@spamspam.com` + require.Equal(t, expected, actual) }) defer s.Close() defer c.Close() @@ -764,7 +1406,6 @@ func readUntilLine(t *testing.T, conn net.Conn, scanner *bufio.Scanner, expected return } output += text + "\n" - //fmt.Println(text) } t.Fatalf("Expected line '%s' not found in output:\n%s", expectedLine, output) } From 37091f25a887778e40870fea72a33953a6ad981c Mon Sep 17 00:00:00 2001 From: binwiederhier Date: Thu, 16 Nov 2023 09:51:23 -0500 Subject: [PATCH 3/3] Add PR link --- docs/releases.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/releases.md b/docs/releases.md index e56f8847..372ff435 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -1287,7 +1287,7 @@ and the [ntfy Android app](https://github.com/binwiederhier/ntfy-android/release **Bug fixes + maintenance:** -* Support for HTML-only emails ([#690](https://github.com/binwiederhier/ntfy/issues/690), thanks to [@teastrainer](https://github.com/teastrainer) and [@CrazyWolf13](https://github.com/CrazyWolf13) for reporting) +* Support for HTML-only emails ([#690](https://github.com/binwiederhier/ntfy/issues/690)/[#693](https://github.com/binwiederhier/ntfy/pull/693), thanks to [@teastrainer](https://github.com/teastrainer) and [@CrazyWolf13](https://github.com/CrazyWolf13) for reporting) * Fix ACL issue with topic patterns containing underscores ([#840](https://github.com/binwiederhier/ntfy/issues/840), thanks to [@Joe-0237](https://github.com/Joe-0237) for reporting) * Re-add `tzdata` to Docker images for amd64 image ([#894](https://github.com/binwiederhier/ntfy/issues/894), [#307](https://github.com/binwiederhier/ntfy/pull/307)) * Add special logic to ignore `Priority` header if it resembled a RFC 9218 value ([#851](https://github.com/binwiederhier/ntfy/pull/851)/[#895](https://github.com/binwiederhier/ntfy/pull/895), thanks to [@gusdleon](https://github.com/gusdleon), see also [#351](https://github.com/binwiederhier/ntfy/issues/351), [#353](https://github.com/binwiederhier/ntfy/issues/353), [#461](https://github.com/binwiederhier/ntfy/issues/461))