~bigbes/core-go

31e77bac08eedc3d9bf64274b341466f66acf548 — Peter Sanchez 4 years ago d5f650d
Add support for mail setups that don't support TLS or Auth
3 files changed, 99 insertions(+), 14 deletions(-)

M email/send.go
M go.mod
M go.sum
M email/send.go => email/send.go +94 -13
@@ 14,33 14,114 @@ import (
	"git.sr.ht/~sircmpwn/core-go/config"
)

// Sends an email. Blocks until it's sent or an error occurs.
func Send(ctx context.Context, msg io.Reader, rcpts []string) error {
type mailConfig struct {
	host string
	port int
	from string

	enctype  string
	authtype string

	user string
	pass string
}

func mailSetup(ctx context.Context) (*smtp.Client, *mail.Address, error) {
	conf := config.ForContext(ctx)
	mailconf := &mailConfig{enctype: "starttls", authtype: "plain"}
	var err error

	portStr, ok := conf.Get("mail", "smtp-port")
	if !ok {
		panic(fmt.Errorf("[mail]smtp-port unset"))
	}
	port, err := strconv.Atoi(portStr)
	mailconf.port, err = strconv.Atoi(portStr)
	if err != nil {
		panic(fmt.Errorf("Unable to parse [mail]smtp-port (must be integer)"))
	}

	host, ok1 := conf.Get("mail", "smtp-host")
	user, ok2 := conf.Get("mail", "smtp-user")
	pass, ok3 := conf.Get("mail", "smtp-password")
	from, ok4 := conf.Get("mail", "smtp-from")
	if !ok1 || !ok2 || !ok3 || !ok4 {
		panic(fmt.Errorf("Missing SMTP configuration options"))
	if mailconf.host, ok = conf.Get("mail", "smtp-host"); !ok {
		panic(fmt.Errorf("Missing SMTP configuration options [smtp-host]"))
	}
	if mailconf.from, ok = conf.Get("mail", "smtp-from"); !ok {
		panic(fmt.Errorf("Missing SMTP configuration options [smtp-from]"))
	}

	sender, err := mail.ParseAddress(from)
	sender, err := mail.ParseAddress(mailconf.from)
	if err != nil {
		panic(err)
	}

	auth := sasl.NewPlainClient("", user, pass)
	return smtp.SendMail(fmt.Sprintf("%s:%d", host, port),
		auth, sender.Address, rcpts, msg)
	if enctype, ok := conf.Get("mail", "smtp-encryption"); ok {
		switch enctype {
		case "starttls", "tls", "insecure":
			mailconf.enctype = enctype
		default:
			panic(fmt.Errorf("Invalid SMTP configuration value for [smtp-encryption]"))
		}
	}

	if authtype, ok := conf.Get("mail", "smtp-auth"); ok {
		switch authtype {
		case "none", "plain":
			mailconf.enctype = authtype
		default:
			panic(fmt.Errorf("Invalid SMTP configuration value for [smtp-auth]"))
		}
	}
	if mailconf.authtype == "plain" {
		if mailconf.user, ok = conf.Get("mail", "smtp-user"); !ok {
			panic(fmt.Errorf("Missing SMTP configuration options [smtp-user]"))
		}
		if mailconf.pass, ok = conf.Get("mail", "smtp-password"); !ok {
			panic(fmt.Errorf("Missing SMTP configuration options [smtp-password]"))
		}
	}

	var c *smtp.Client
	addr := fmt.Sprintf("%s:%d", mailconf.host, mailconf.port)

	if mailconf.enctype == "tls" {
		c, err = smtp.DialTLS(addr, nil)
	} else {
		c, err = smtp.Dial(addr)
	}
	if err != nil {
		return nil, nil, err
	}

	if err = c.Hello("localhost"); err != nil {
		return nil, nil, err
	}

	if mailconf.enctype == "starttls" {
		if ok, _ := c.Extension("STARTTLS"); !ok {
			panic(fmt.Errorf("smtp: server doesn't support STARTTLS"))
		}
		if err = c.StartTLS(nil); err != nil {
			return nil, nil, err
		}
	}

	if mailconf.authtype == "plain" {
		auth := sasl.NewPlainClient("", mailconf.user, mailconf.pass)
		if ok, _ := c.Extension("AUTH"); !ok {
			panic(fmt.Errorf("smtp: server doesn't support AUTH"))
		}
		if err = c.Auth(auth); err != nil {
			return nil, nil, err
		}
	}

	return c, sender, nil
}

// Sends an email. Blocks until it's sent or an error occurs.
func Send(ctx context.Context, msg io.Reader, rcpts []string) error {
	c, sender, err := mailSetup(ctx)
	if err != nil {
		return err
	}
	defer c.Close()
	return c.SendMail(sender.Address, rcpts, msg)
}

M go.mod => go.mod +1 -1
@@ 12,7 12,7 @@ require (
	github.com/emersion/go-message v0.13.1-0.20201112194930-f77964fe28bd
	github.com/emersion/go-pgpmail v0.1.0
	github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21
	github.com/emersion/go-smtp v0.14.0
	github.com/emersion/go-smtp v0.15.1-0.20211103212524-30169acc42e7
	github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 // indirect
	github.com/fernet/fernet-go v0.0.0-20191111064656-eff2850e6001
	github.com/go-chi/chi v4.1.2+incompatible

M go.sum => go.sum +4 -0
@@ 131,6 131,10 @@ github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1X
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.14.0 h1:RYW203p+EcPjL8Z/ZpT9lZ6iOc8MG1MQzEx1UKEkXlA=
github.com/emersion/go-smtp v0.14.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-smtp v0.15.0 h1:3+hMGMGrqP/lqd7qoxZc1hTU8LY8gHV9RFGWlqSDmP8=
github.com/emersion/go-smtp v0.15.0/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-smtp v0.15.1-0.20211103212524-30169acc42e7 h1:y2h9HJElyAP5kgYujXAJC1DvlcTgCUhtYr/BlXnlGfs=
github.com/emersion/go-smtp v0.15.1-0.20211103212524-30169acc42e7/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe h1:40SWqY0zE3qCi6ZrtTf5OUdNm5lDnGnjRSq9GgmeTrg=
github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwoTQyw0fIM5xv1HF+Y+3ZijDR839WMulgxCcUY=