Files
mailgosend/internal/smtp/server.go
T
2026-05-21 20:27:58 +00:00

105 lines
3.0 KiB
Go

// Package smtp provides SMTP inbound (port 25) and submission (587/465) servers
// using github.com/emersion/go-smtp as the protocol layer.
package smtp
import (
"crypto/tls"
"fmt"
"log"
"time"
gosmtp "github.com/emersion/go-smtp"
"ghb.freebede.com/nahakubuilder/mailgosend/internal/auth"
"ghb.freebede.com/nahakubuilder/mailgosend/internal/config"
"ghb.freebede.com/nahakubuilder/mailgosend/internal/crypto"
"ghb.freebede.com/nahakubuilder/mailgosend/internal/db"
"ghb.freebede.com/nahakubuilder/mailgosend/internal/spam"
"ghb.freebede.com/nahakubuilder/mailgosend/internal/storage"
)
// Deps groups all dependencies shared by SMTP servers.
type Deps struct {
DB *db.DB
Crypt *crypto.Crypto
Store *storage.Store
Scorer *spam.Scorer
Brute *auth.BruteGuard
Cfg *config.Config
}
// NewInboundServer creates the SMTP server for port 25 (inbound MTA).
// Accepts mail for local domains from any sender. STARTTLS offered but not required.
func NewInboundServer(d *Deps, tlsCfg *tls.Config) *gosmtp.Server {
be := &InboundBackend{deps: d}
s := gosmtp.NewServer(be)
s.Addr = fmt.Sprintf("%s:%d", d.Cfg.SMTPIface, d.Cfg.SMTPPort)
s.Domain = d.Cfg.SMTPHostname
s.MaxMessageBytes = d.Cfg.MaxMessageSize
s.MaxRecipients = d.Cfg.MaxRcptPer
s.WriteTimeout = 5 * time.Minute
s.ReadTimeout = 5 * time.Minute
s.AllowInsecureAuth = false // AUTH not offered on port 25
if tlsCfg != nil {
// Setting TLSConfig enables STARTTLS automatically in go-smtp v0.24+.
s.TLSConfig = tlsCfg
}
return s
}
// NewSubmissionServer creates the SMTP server for port 587 (STARTTLS submission).
// Auth required. STARTTLS mandatory before AUTH.
func NewSubmissionServer(d *Deps, tlsCfg *tls.Config) *gosmtp.Server {
be := &SubmissionBackend{deps: d}
s := gosmtp.NewServer(be)
s.Addr = fmt.Sprintf("%s:%d", d.Cfg.SubmitIface, d.Cfg.SubmitPort)
s.Domain = d.Cfg.SMTPHostname
s.MaxMessageBytes = d.Cfg.MaxMessageSize
s.MaxRecipients = d.Cfg.MaxRcptPer
s.WriteTimeout = 5 * time.Minute
s.ReadTimeout = 5 * time.Minute
s.AllowInsecureAuth = false // auth only after STARTTLS
if tlsCfg != nil {
s.TLSConfig = tlsCfg
}
return s
}
// NewSMTPSServer creates the SMTP server for port 465 (implicit TLS submission).
func NewSMTPSServer(d *Deps, tlsCfg *tls.Config) *gosmtp.Server {
be := &SubmissionBackend{deps: d}
s := gosmtp.NewServer(be)
s.Addr = fmt.Sprintf("%s:%d", d.Cfg.SMTPIface, d.Cfg.SMTPSPort)
s.Domain = d.Cfg.SMTPHostname
s.MaxMessageBytes = d.Cfg.MaxMessageSize
s.MaxRecipients = d.Cfg.MaxRcptPer
s.WriteTimeout = 5 * time.Minute
s.ReadTimeout = 5 * time.Minute
s.AllowInsecureAuth = false
if tlsCfg != nil {
s.TLSConfig = tlsCfg
}
return s
}
// ListenAndServe starts a server and logs errors.
func ListenAndServe(s *gosmtp.Server, name string) error {
log.Printf("[%s] listening on %s", name, s.Addr)
return s.ListenAndServe()
}
// ListenAndServeTLS starts a server with implicit TLS (port 465).
func ListenAndServeTLS(s *gosmtp.Server, name string) error {
log.Printf("[%s] listening on %s (TLS)", name, s.Addr)
return s.ListenAndServeTLS()
}