Compare commits
No commits in common. "fcf82bc3596b660b3c650bfd9d57519e6fa6b5a6" and "4fb0764bcc561bdeddd3089390c6609ba268a6be" have entirely different histories.
fcf82bc359
...
4fb0764bcc
4 changed files with 30 additions and 86 deletions
|
@ -1,5 +1,3 @@
|
||||||
Port = 11025
|
|
||||||
|
|
||||||
[[Recipients]]
|
[[Recipients]]
|
||||||
Addresses = ["something@something.com"]
|
Addresses = ["something@something.com"]
|
||||||
Target = "ntfy://ntfy.sh/fmartingr-dev"
|
Target = "ntfy://ntfy.sh/fmartingr-dev"
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -3,18 +3,17 @@ module git.nakama.town/fmartingr/smtp2shoutrrr
|
||||||
go 1.23.3
|
go 1.23.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.nakama.town/fmartingr/gotoolkit v0.0.0-20241123184121-ef80892aa542
|
git.nakama.town/fmartingr/gotoolkit v0.0.0-00010101000000-000000000000
|
||||||
github.com/containrrr/shoutrrr v0.8.0
|
|
||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
|
||||||
github.com/emersion/go-smtp v0.21.3
|
github.com/emersion/go-smtp v0.21.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/containrrr/shoutrrr v0.8.0 // indirect
|
||||||
github.com/fatih/color v1.15.0 // indirect
|
github.com/fatih/color v1.15.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
|
||||||
golang.org/x/sys v0.22.0 // indirect
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
//replace git.nakama.town/fmartingr/gotoolkit => ../gotoolkit
|
replace git.nakama.town/fmartingr/gotoolkit => ../gotoolkit
|
||||||
|
|
36
go.sum
36
go.sum
|
@ -1,53 +1,17 @@
|
||||||
git.nakama.town/fmartingr/gotoolkit v0.0.0-20241123184121-ef80892aa542 h1:y1LuMKkVUvrPDOuHmhHTGpNFu+S34NwxgAU3cHN/ihk=
|
|
||||||
git.nakama.town/fmartingr/gotoolkit v0.0.0-20241123184121-ef80892aa542/go.mod h1:wT4a0weU051koADRquRKWQeUsNeOyLDm7lqSqVl16Z8=
|
|
||||||
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
|
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
|
||||||
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
|
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
|
||||||
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||||
github.com/emersion/go-smtp v0.21.3 h1:7uVwagE8iPYE48WhNsng3RRpCUpFvNl39JGNSIyGVMY=
|
github.com/emersion/go-smtp v0.21.3 h1:7uVwagE8iPYE48WhNsng3RRpCUpFvNl39JGNSIyGVMY=
|
||||||
github.com/emersion/go-smtp v0.21.3/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
github.com/emersion/go-smtp v0.21.3/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
|
||||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
|
||||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
|
||||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
|
||||||
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
|
||||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
|
||||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
|
||||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
|
||||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
|
||||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
|
||||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
|
||||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
|
||||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
|
|
71
main.go
71
main.go
|
@ -8,12 +8,10 @@ import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.nakama.town/fmartingr/gotoolkit/encoding"
|
|
||||||
"git.nakama.town/fmartingr/gotoolkit/model"
|
"git.nakama.town/fmartingr/gotoolkit/model"
|
||||||
"git.nakama.town/fmartingr/gotoolkit/service"
|
"git.nakama.town/fmartingr/gotoolkit/service"
|
||||||
"github.com/containrrr/shoutrrr"
|
"github.com/containrrr/shoutrrr"
|
||||||
|
@ -46,28 +44,21 @@ func (re *ReceivedEmail) Body() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Port int
|
|
||||||
Recipients []ConfigRecipient
|
Recipients []ConfigRecipient
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) SetDefaults() {
|
|
||||||
if c.Port == 0 {
|
|
||||||
c.Port = 11125
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConfigRecipient struct {
|
type ConfigRecipient struct {
|
||||||
Addresses []string // email addresses
|
Addresses []string // email addresses
|
||||||
Target string // shoutrrr address
|
target string // shoutrrr address
|
||||||
targetURL *url.URL
|
targetURL *url.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cr ConfigRecipient) GetTargetURL() *url.URL {
|
func (cr ConfigRecipient) Target() *url.URL {
|
||||||
if cr.targetURL == nil {
|
if cr.targetURL == nil {
|
||||||
var err error
|
var err error
|
||||||
cr.targetURL, err = url.Parse(cr.Target)
|
cr.targetURL, err = url.Parse(cr.target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("failed to parse shoutrrr target URL", slog.String("target", cr.Target), slog.String("err", err.Error()))
|
slog.Error("failed to parse shoutrrr target URL", slog.String("target", cr.target), slog.String("err", err.Error()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cr.targetURL
|
return cr.targetURL
|
||||||
|
@ -94,22 +85,9 @@ func (s *smtpServer) Stop(ctx context.Context) error {
|
||||||
return s.backend.Shutdown(ctx)
|
return s.backend.Shutdown(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSMTPServer(config *Config) model.Server {
|
func NewSMTPServer(backend *smtp.Server) model.Server {
|
||||||
be := &Backend{
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
smtpBackend := smtp.NewServer(be)
|
|
||||||
smtpBackend.Addr = fmt.Sprintf(":%d", config.Port)
|
|
||||||
// smtpBackend.Domain = "localhost"
|
|
||||||
smtpBackend.WriteTimeout = 10 * time.Second
|
|
||||||
smtpBackend.ReadTimeout = 10 * time.Second
|
|
||||||
smtpBackend.MaxMessageBytes = 1024 * 1024
|
|
||||||
smtpBackend.MaxRecipients = 50
|
|
||||||
smtpBackend.AllowInsecureAuth = true
|
|
||||||
|
|
||||||
return &smtpServer{
|
return &smtpServer{
|
||||||
backend: smtpBackend,
|
backend: backend,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +104,7 @@ func (bkd *Backend) NewSession(c *smtp.Conn) (smtp.Session, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bkd *Backend) forwardEmail(email ReceivedEmail) error {
|
func (bkd *Backend) forwardEmail(email ReceivedEmail) error {
|
||||||
slog.Info("forwading message", slog.String("to", strings.Join(email.Recipients, ",")))
|
slog.Info("forwading message", slog.String("email", email.String()))
|
||||||
|
|
||||||
for _, r := range bkd.config.Recipients {
|
for _, r := range bkd.config.Recipients {
|
||||||
for _, a := range email.Recipients {
|
for _, a := range email.Recipients {
|
||||||
|
@ -135,7 +113,7 @@ func (bkd *Backend) forwardEmail(email ReceivedEmail) error {
|
||||||
"title": {email.Msg.Header.Get("Subject")},
|
"title": {email.Msg.Header.Get("Subject")},
|
||||||
}
|
}
|
||||||
|
|
||||||
destinationURL := r.GetTargetURL()
|
destinationURL := r.Target()
|
||||||
destinationURL.RawQuery = urlParams.Encode()
|
destinationURL.RawQuery = urlParams.Encode()
|
||||||
|
|
||||||
if err := shoutrrr.Send(destinationURL.String(), email.Body()); err != nil {
|
if err := shoutrrr.Send(destinationURL.String(), email.Body()); err != nil {
|
||||||
|
@ -213,27 +191,32 @@ func (s *Session) Logout() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var config *Config
|
config := &Config{
|
||||||
configPath := "config.toml"
|
Recipients: []ConfigRecipient{{
|
||||||
|
Addresses: []string{"test@fmartingr.com", "caca@caca.com"},
|
||||||
f, err := os.Open(configPath)
|
target: "ntfy://ntfy.sh/fmartingr-dev",
|
||||||
if err != nil {
|
}, {
|
||||||
slog.Error("Error opening config file", slog.String("err", err.Error()), slog.String("path", configPath))
|
Addresses: []string{"something@something.com"},
|
||||||
return
|
target: "ntfy://ntfy.sh/fmartingr-dev",
|
||||||
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
enc := encoding.NewTOMLEncoding()
|
be := &Backend{
|
||||||
if err := enc.DecodeReader(f, &config); err != nil {
|
config: config,
|
||||||
slog.Error("Error decoding config file", slog.String("err", err.Error()), slog.String("path", configPath))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.SetDefaults()
|
smtpBackend := smtp.NewServer(be)
|
||||||
|
|
||||||
slog.Info("config loaded", slog.Int("recipients", len(config.Recipients)))
|
smtpBackend.Addr = "localhost:11025"
|
||||||
|
smtpBackend.Domain = "localhost"
|
||||||
|
smtpBackend.WriteTimeout = 10 * time.Second
|
||||||
|
smtpBackend.ReadTimeout = 10 * time.Second
|
||||||
|
smtpBackend.MaxMessageBytes = 1024 * 1024
|
||||||
|
smtpBackend.MaxRecipients = 50
|
||||||
|
smtpBackend.AllowInsecureAuth = true
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
smtpServer := NewSMTPServer(config)
|
smtpServer := NewSMTPServer(smtpBackend)
|
||||||
|
|
||||||
svc, err := service.NewService([]model.Server{
|
svc, err := service.NewService([]model.Server{
|
||||||
smtpServer,
|
smtpServer,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue