mirror of
https://github.com/binwiederhier/ntfy.git
synced 2025-07-20 10:04:08 +00:00
Send emails with gomail to support SMTP servers with AUTH
This commit is contained in:
parent
30301c8a7f
commit
66316eae00
4 changed files with 76 additions and 77 deletions
2
go.mod
2
go.mod
|
@ -100,5 +100,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
|
||||
google.golang.org/grpc v1.72.2 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
4
go.sum
4
go.sum
|
@ -275,9 +275,13 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -4,9 +4,10 @@ import (
|
|||
_ "embed" // required by go:embed
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
gomail "gopkg.in/gomail.v2"
|
||||
"mime"
|
||||
"net"
|
||||
"net/smtp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -29,17 +30,17 @@ type smtpSender struct {
|
|||
|
||||
func (s *smtpSender) Send(v *visitor, m *message, to string) error {
|
||||
return s.withCount(v, m, func() error {
|
||||
host, _, err := net.SplitHostPort(s.config.SMTPSenderAddr)
|
||||
host, portStr, err := net.SplitHostPort(s.config.SMTPSenderAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
message, err := formatMail(s.config.BaseURL, v.ip.String(), s.config.SMTPSenderFrom, to, m)
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var auth smtp.Auth
|
||||
if s.config.SMTPSenderUser != "" {
|
||||
auth = smtp.PlainAuth("", s.config.SMTPSenderUser, s.config.SMTPSenderPass, host)
|
||||
from, subject, message, err := formatMail(s.config.BaseURL, v.ip.String(), s.config.SMTPSenderFrom, m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ev := logvm(v, m).
|
||||
Tag(tagEmail).
|
||||
|
@ -53,7 +54,18 @@ func (s *smtpSender) Send(v *visitor, m *message, to string) error {
|
|||
} else if ev.IsDebug() {
|
||||
ev.Debug("Sending email")
|
||||
}
|
||||
return smtp.SendMail(s.config.SMTPSenderAddr, auth, s.config.SMTPSenderFrom, []string{to}, []byte(message))
|
||||
|
||||
smtpMessage := gomail.NewMessage()
|
||||
smtpMessage.SetHeader("From", from)
|
||||
smtpMessage.SetHeader("To", to)
|
||||
smtpMessage.SetHeader("Subject", subject)
|
||||
smtpMessage.SetBody("text/plain", message)
|
||||
dialer := gomail.NewDialer(host, port, s.config.SMTPSenderUser, s.config.SMTPSenderPass)
|
||||
err = dialer.DialAndSend(smtpMessage)
|
||||
if err == nil {
|
||||
ev.Debug("Mail sent ok")
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -76,7 +88,8 @@ func (s *smtpSender) withCount(v *visitor, m *message, fn func() error) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func formatMail(baseURL, senderIP, from, to string, m *message) (string, error) {
|
||||
// returns: from, subject, content
|
||||
func formatMail(baseURL, senderIP, from string, m *message) (string, string, string, error) {
|
||||
topicURL := baseURL + "/" + m.Topic
|
||||
subject := m.Title
|
||||
if subject == "" {
|
||||
|
@ -88,7 +101,7 @@ func formatMail(baseURL, senderIP, from, to string, m *message) (string, error)
|
|||
if len(m.Tags) > 0 {
|
||||
emojis, tags, err := toEmojis(m.Tags)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", "", err
|
||||
}
|
||||
if len(emojis) > 0 {
|
||||
subject = strings.Join(emojis, " ") + " " + subject
|
||||
|
@ -100,7 +113,7 @@ func formatMail(baseURL, senderIP, from, to string, m *message) (string, error)
|
|||
if m.Priority != 0 && m.Priority != 3 {
|
||||
priority, err := util.PriorityString(m.Priority)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", "", "", err
|
||||
}
|
||||
if trailer != "" {
|
||||
trailer += "\n"
|
||||
|
@ -110,28 +123,20 @@ func formatMail(baseURL, senderIP, from, to string, m *message) (string, error)
|
|||
if trailer != "" {
|
||||
message += "\n\n" + trailer
|
||||
}
|
||||
date := time.Unix(m.Time, 0).UTC().Format(time.RFC1123Z)
|
||||
subject = mime.BEncoding.Encode("utf-8", subject)
|
||||
body := `From: "{shortTopicURL}" <{from}>
|
||||
To: {to}
|
||||
Date: {date}
|
||||
Subject: {subject}
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
fullFrom := `"{shortTopicURL}" <{from}>`
|
||||
fullFrom = strings.ReplaceAll(fullFrom, "{from}", from)
|
||||
fullFrom = strings.ReplaceAll(fullFrom, "{shortTopicURL}", util.ShortTopicURL(topicURL))
|
||||
|
||||
{message}
|
||||
body := `{message}
|
||||
|
||||
--
|
||||
This message was sent by {ip} at {time} via {topicURL}`
|
||||
body = strings.ReplaceAll(body, "{from}", from)
|
||||
body = strings.ReplaceAll(body, "{to}", to)
|
||||
body = strings.ReplaceAll(body, "{date}", date)
|
||||
body = strings.ReplaceAll(body, "{subject}", subject)
|
||||
body = strings.ReplaceAll(body, "{message}", message)
|
||||
body = strings.ReplaceAll(body, "{topicURL}", topicURL)
|
||||
body = strings.ReplaceAll(body, "{shortTopicURL}", util.ShortTopicURL(topicURL))
|
||||
body = strings.ReplaceAll(body, "{time}", time.Unix(m.Time, 0).UTC().Format(time.RFC1123))
|
||||
body = strings.ReplaceAll(body, "{ip}", senderIP)
|
||||
return body, nil
|
||||
return fullFrom, subject, body, nil
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
@ -6,28 +6,26 @@ import (
|
|||
)
|
||||
|
||||
func TestFormatMail_Basic(t *testing.T) {
|
||||
actual, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", "phil@example.com", &message{
|
||||
actualFrom, actualSubject, actualMessage, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", &message{
|
||||
ID: "abc",
|
||||
Time: 1640382204,
|
||||
Event: "message",
|
||||
Topic: "alerts",
|
||||
Message: "A simple message",
|
||||
})
|
||||
expected := `From: "ntfy.sh/alerts" <ntfy@ntfy.sh>
|
||||
To: phil@example.com
|
||||
Date: Fri, 24 Dec 2021 21:43:24 +0000
|
||||
Subject: A simple message
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
A simple message
|
||||
expectedFrom := `"ntfy.sh/alerts" <ntfy@ntfy.sh>`
|
||||
expectedSubject := `A simple message`
|
||||
expectedMessage := `A simple message
|
||||
|
||||
--
|
||||
This message was sent by 1.2.3.4 at Fri, 24 Dec 2021 21:43:24 UTC via https://ntfy.sh/alerts`
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expectedMessage, actualMessage)
|
||||
require.Equal(t, expectedFrom, actualFrom)
|
||||
require.Equal(t, expectedSubject, actualSubject)
|
||||
}
|
||||
|
||||
func TestFormatMail_JustEmojis(t *testing.T) {
|
||||
actual, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", "phil@example.com", &message{
|
||||
actualFrom, actualSubject, actualMessage, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", &message{
|
||||
ID: "abc",
|
||||
Time: 1640382204,
|
||||
Event: "message",
|
||||
|
@ -35,21 +33,19 @@ func TestFormatMail_JustEmojis(t *testing.T) {
|
|||
Message: "A simple message",
|
||||
Tags: []string{"grinning"},
|
||||
})
|
||||
expected := `From: "ntfy.sh/alerts" <ntfy@ntfy.sh>
|
||||
To: phil@example.com
|
||||
Date: Fri, 24 Dec 2021 21:43:24 +0000
|
||||
Subject: =?utf-8?b?8J+YgCBBIHNpbXBsZSBtZXNzYWdl?=
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
A simple message
|
||||
expectedFrom := `"ntfy.sh/alerts" <ntfy@ntfy.sh>`
|
||||
expectedSubject := `=?utf-8?b?8J+YgCBBIHNpbXBsZSBtZXNzYWdl?=`
|
||||
expectedMessage := `A simple message
|
||||
|
||||
--
|
||||
This message was sent by 1.2.3.4 at Fri, 24 Dec 2021 21:43:24 UTC via https://ntfy.sh/alerts`
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expectedMessage, actualMessage)
|
||||
require.Equal(t, expectedFrom, actualFrom)
|
||||
require.Equal(t, expectedSubject, actualSubject)
|
||||
}
|
||||
|
||||
func TestFormatMail_JustOtherTags(t *testing.T) {
|
||||
actual, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", "phil@example.com", &message{
|
||||
actualFrom, actualSubject, actualMessage, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", &message{
|
||||
ID: "abc",
|
||||
Time: 1640382204,
|
||||
Event: "message",
|
||||
|
@ -57,23 +53,21 @@ func TestFormatMail_JustOtherTags(t *testing.T) {
|
|||
Message: "A simple message",
|
||||
Tags: []string{"not-an-emoji"},
|
||||
})
|
||||
expected := `From: "ntfy.sh/alerts" <ntfy@ntfy.sh>
|
||||
To: phil@example.com
|
||||
Date: Fri, 24 Dec 2021 21:43:24 +0000
|
||||
Subject: A simple message
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
A simple message
|
||||
expectedFrom := `"ntfy.sh/alerts" <ntfy@ntfy.sh>`
|
||||
expectedSubject := `A simple message`
|
||||
expectedMessage := `A simple message
|
||||
|
||||
Tags: not-an-emoji
|
||||
|
||||
--
|
||||
This message was sent by 1.2.3.4 at Fri, 24 Dec 2021 21:43:24 UTC via https://ntfy.sh/alerts`
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expectedMessage, actualMessage)
|
||||
require.Equal(t, expectedFrom, actualFrom)
|
||||
require.Equal(t, expectedSubject, actualSubject)
|
||||
}
|
||||
|
||||
func TestFormatMail_JustPriority(t *testing.T) {
|
||||
actual, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", "phil@example.com", &message{
|
||||
actualFrom, actualSubject, actualMessage, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", &message{
|
||||
ID: "abc",
|
||||
Time: 1640382204,
|
||||
Event: "message",
|
||||
|
@ -81,23 +75,21 @@ func TestFormatMail_JustPriority(t *testing.T) {
|
|||
Message: "A simple message",
|
||||
Priority: 2,
|
||||
})
|
||||
expected := `From: "ntfy.sh/alerts" <ntfy@ntfy.sh>
|
||||
To: phil@example.com
|
||||
Date: Fri, 24 Dec 2021 21:43:24 +0000
|
||||
Subject: A simple message
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
A simple message
|
||||
expectedFrom := `"ntfy.sh/alerts" <ntfy@ntfy.sh>`
|
||||
expectedSubject := `A simple message`
|
||||
expectedMessage := `A simple message
|
||||
|
||||
Priority: low
|
||||
|
||||
--
|
||||
This message was sent by 1.2.3.4 at Fri, 24 Dec 2021 21:43:24 UTC via https://ntfy.sh/alerts`
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expectedMessage, actualMessage)
|
||||
require.Equal(t, expectedFrom, actualFrom)
|
||||
require.Equal(t, expectedSubject, actualSubject)
|
||||
}
|
||||
|
||||
func TestFormatMail_UTF8Subject(t *testing.T) {
|
||||
actual, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", "phil@example.com", &message{
|
||||
actualFrom, actualSubject, actualMessage, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", &message{
|
||||
ID: "abc",
|
||||
Time: 1640382204,
|
||||
Event: "message",
|
||||
|
@ -105,21 +97,19 @@ func TestFormatMail_UTF8Subject(t *testing.T) {
|
|||
Message: "A simple message",
|
||||
Title: " :: A not so simple title öäüß ¡Hola, señor!",
|
||||
})
|
||||
expected := `From: "ntfy.sh/alerts" <ntfy@ntfy.sh>
|
||||
To: phil@example.com
|
||||
Date: Fri, 24 Dec 2021 21:43:24 +0000
|
||||
Subject: =?utf-8?b?IDo6IEEgbm90IHNvIHNpbXBsZSB0aXRsZSDDtsOkw7zDnyDCoUhvbGEsIHNl?= =?utf-8?b?w7FvciE=?=
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
A simple message
|
||||
expectedFrom := `"ntfy.sh/alerts" <ntfy@ntfy.sh>`
|
||||
expectedSubject := `=?utf-8?b?IDo6IEEgbm90IHNvIHNpbXBsZSB0aXRsZSDDtsOkw7zDnyDCoUhvbGEsIHNl?= =?utf-8?b?w7FvciE=?=`
|
||||
expectedMessage := `A simple message
|
||||
|
||||
--
|
||||
This message was sent by 1.2.3.4 at Fri, 24 Dec 2021 21:43:24 UTC via https://ntfy.sh/alerts`
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expectedMessage, actualMessage)
|
||||
require.Equal(t, expectedFrom, actualFrom)
|
||||
require.Equal(t, expectedSubject, actualSubject)
|
||||
}
|
||||
|
||||
func TestFormatMail_WithAllTheThings(t *testing.T) {
|
||||
actual, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", "phil@example.com", &message{
|
||||
actualFrom, actualSubject, actualMessage, _ := formatMail("https://ntfy.sh", "1.2.3.4", "ntfy@ntfy.sh", &message{
|
||||
ID: "abc",
|
||||
Time: 1640382204,
|
||||
Event: "message",
|
||||
|
@ -129,13 +119,9 @@ func TestFormatMail_WithAllTheThings(t *testing.T) {
|
|||
Title: "Oh no 🙈\nThis is a message across\nmultiple lines",
|
||||
Message: "A message that contains monkeys 🙉\nNo really, though. Monkeys!",
|
||||
})
|
||||
expected := `From: "ntfy.sh/alerts" <ntfy@ntfy.sh>
|
||||
To: phil@example.com
|
||||
Date: Fri, 24 Dec 2021 21:43:24 +0000
|
||||
Subject: =?utf-8?b?4pqg77iPIPCfkoAgT2ggbm8g8J+ZiCBUaGlzIGlzIGEgbWVzc2FnZSBhY3Jv?= =?utf-8?b?c3MgbXVsdGlwbGUgbGluZXM=?=
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
|
||||
A message that contains monkeys 🙉
|
||||
expectedFrom := `"ntfy.sh/alerts" <ntfy@ntfy.sh>`
|
||||
expectedSubject := `=?utf-8?b?4pqg77iPIPCfkoAgT2ggbm8g8J+ZiCBUaGlzIGlzIGEgbWVzc2FnZSBhY3Jv?= =?utf-8?b?c3MgbXVsdGlwbGUgbGluZXM=?=`
|
||||
expectedMessage := `A message that contains monkeys 🙉
|
||||
No really, though. Monkeys!
|
||||
|
||||
Tags: tag123, other
|
||||
|
@ -143,5 +129,7 @@ Priority: max
|
|||
|
||||
--
|
||||
This message was sent by 1.2.3.4 at Fri, 24 Dec 2021 21:43:24 UTC via https://ntfy.sh/alerts`
|
||||
require.Equal(t, expected, actual)
|
||||
require.Equal(t, expectedMessage, actualMessage)
|
||||
require.Equal(t, expectedFrom, actualFrom)
|
||||
require.Equal(t, expectedSubject, actualSubject)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue