59 lines
2.0 KiB
Go
59 lines
2.0 KiB
Go
package smtpserver
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/emersion/go-smtp"
|
|
"gopkg.in/ini.v1"
|
|
)
|
|
|
|
// ResolveBanner mirrors CustomSMTP's server_banner handling (the '""' literal-quotes
|
|
// convention for "explicitly empty"). go-smtp's greeting is always
|
|
// "220 <Domain> ESMTP Service Ready" with no hook to drop the " ESMTP Service Ready"
|
|
// suffix the way aiosmtpd's raw __ident__ override can — so when no custom banner is
|
|
// configured, this falls back to heloHostname (a normal, protocol-correct greeting)
|
|
// rather than Python's degenerate literally-empty banner. This is a disclosed, cosmetic
|
|
// interface deviation: no test tooling in this project inspects the SMTP banner text.
|
|
func ResolveBanner(cfg *ini.File, heloHostname string) string {
|
|
raw := cfg.Section("Server").Key("server_banner").String()
|
|
if raw == `""` {
|
|
raw = ""
|
|
}
|
|
raw = strings.TrimSpace(raw)
|
|
if raw == "" {
|
|
return heloHostname
|
|
}
|
|
return raw
|
|
}
|
|
|
|
// NewPlainServer mirrors server_runner.py's PlainController: no TLS context at all, so
|
|
// STARTTLS is never offered, and AUTH is advertised and usable in plaintext
|
|
// (auth_require_tls=False).
|
|
func NewPlainServer(backend *Backend, addr, banner string) *smtp.Server {
|
|
s := smtp.NewServer(backend)
|
|
s.Addr = addr
|
|
s.Domain = banner
|
|
s.AllowInsecureAuth = true
|
|
s.ReadTimeout = 5 * time.Minute
|
|
s.WriteTimeout = 5 * time.Minute
|
|
return s
|
|
}
|
|
|
|
// NewTLSServer mirrors server_runner.py's TLSController: implicit/direct TLS (like
|
|
// SMTPS on port 465) — the whole connection is encrypted from the first byte, not
|
|
// STARTTLS-negotiated. Call ListenAndServeTLS (not ListenAndServe) to run it.
|
|
func NewTLSServer(backend *Backend, addr, banner string, tlsConfig *tls.Config) *smtp.Server {
|
|
s := smtp.NewServer(backend)
|
|
s.Addr = addr
|
|
s.Domain = banner
|
|
s.TLSConfig = tlsConfig
|
|
// The session is always already TLS on this listener, so AUTH is always allowed
|
|
// either way (auth_require_tls=True in Python, which is trivially satisfied here).
|
|
s.AllowInsecureAuth = true
|
|
s.ReadTimeout = 5 * time.Minute
|
|
s.WriteTimeout = 5 * time.Minute
|
|
return s
|
|
}
|