mirror of
https://github.com/wneessen/go-mail.git
synced 2024-11-22 13:50:49 +01:00
#105: Add default ports and fallback behavior for SSL and TLS
Introduced default ports for SSL/TLS and STARTTLS connections in SMTP client. Also added fallback behavior, allowing the client to attempt connections on port 25 using plaintext if secured connections fail. Deprecated old methods and implemented new ones to enforce these changes effectively. This is a copy of the PR muhlemmer:enhance-default-tls-port by @muhlemmer. Since they unfortunately didn't reply in the PR anymore I cloned the PR. They will be fully attributed in the PR, though.
This commit is contained in:
parent
161381d880
commit
7a2d9ff938
1 changed files with 94 additions and 4 deletions
96
client.go
96
client.go
|
@ -20,9 +20,15 @@ import (
|
||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
const (
|
const (
|
||||||
// DefaultPort is the default connection port cto the SMTP server
|
// DefaultPort is the default connection port to the SMTP server
|
||||||
DefaultPort = 25
|
DefaultPort = 25
|
||||||
|
|
||||||
|
// DefaultPortSSL is the default connection port for SSL/TLS to the SMTP server
|
||||||
|
DefaultPortSSL = 465
|
||||||
|
|
||||||
|
// DefaultPortTLS is the default connection port for STARTTLS to the SMTP server
|
||||||
|
DefaultPortTLS = 587
|
||||||
|
|
||||||
// DefaultTimeout is the default connection timeout
|
// DefaultTimeout is the default connection timeout
|
||||||
DefaultTimeout = time.Second * 15
|
DefaultTimeout = time.Second * 15
|
||||||
|
|
||||||
|
@ -105,14 +111,15 @@ type Client struct {
|
||||||
// HELO/EHLO string for the greeting the target SMTP server
|
// HELO/EHLO string for the greeting the target SMTP server
|
||||||
helo string
|
helo string
|
||||||
|
|
||||||
// Hostname of the target SMTP server cto connect cto
|
// Hostname of the target SMTP server to connect to
|
||||||
host string
|
host string
|
||||||
|
|
||||||
// pass is the corresponding SMTP AUTH password
|
// pass is the corresponding SMTP AUTH password
|
||||||
pass string
|
pass string
|
||||||
|
|
||||||
// Port of the SMTP server cto connect cto
|
// Port of the SMTP server to connect to
|
||||||
port int
|
port int
|
||||||
|
fallbackPort int
|
||||||
|
|
||||||
// sa is a pointer to smtp.Auth
|
// sa is a pointer to smtp.Auth
|
||||||
sa smtp.Auth
|
sa smtp.Auth
|
||||||
|
@ -246,6 +253,8 @@ func WithTimeout(t time.Duration) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithSSL tells the client to use a SSL/TLS connection
|
// WithSSL tells the client to use a SSL/TLS connection
|
||||||
|
//
|
||||||
|
// Deprecated: use WithSSLPort instead.
|
||||||
func WithSSL() Option {
|
func WithSSL() Option {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.ssl = true
|
c.ssl = true
|
||||||
|
@ -253,6 +262,18 @@ func WithSSL() Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSSLPort tells the client to use a SSL/TLS connection.
|
||||||
|
// It automatically sets the port to 465.
|
||||||
|
//
|
||||||
|
// When the SSL connection fails and fallback is set to true,
|
||||||
|
// the client will attempt to connect on port 25 using plaintext.
|
||||||
|
func WithSSLPort(fb bool) Option {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.SetSSLPort(true, fb)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithDebugLog tells the client to log incoming and outgoing messages of the SMTP client
|
// WithDebugLog tells the client to log incoming and outgoing messages of the SMTP client
|
||||||
// to StdErr
|
// to StdErr
|
||||||
func WithDebugLog() Option {
|
func WithDebugLog() Option {
|
||||||
|
@ -282,6 +303,8 @@ func WithHELO(h string) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTLSPolicy tells the client to use the provided TLSPolicy
|
// WithTLSPolicy tells the client to use the provided TLSPolicy
|
||||||
|
//
|
||||||
|
// Deprecated: use WithTLSPortPolicy instead.
|
||||||
func WithTLSPolicy(p TLSPolicy) Option {
|
func WithTLSPolicy(p TLSPolicy) Option {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
c.tlspolicy = p
|
c.tlspolicy = p
|
||||||
|
@ -289,6 +312,20 @@ func WithTLSPolicy(p TLSPolicy) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTLSPortPolicy tells the client to use the provided TLSPolicy,
|
||||||
|
// The correct port is automatically set.
|
||||||
|
//
|
||||||
|
// Port 587 is used for TLSMandatory and TLSOpportunistic.
|
||||||
|
// If the connection fails with TLSOpportunistic,
|
||||||
|
// a plaintext connection is attempted on port 25 as a fallback.
|
||||||
|
// NoTLS will allways use port 25.
|
||||||
|
func WithTLSPortPolicy(p TLSPolicy) Option {
|
||||||
|
return func(c *Client) error {
|
||||||
|
c.SetTLSPortPolicy(p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WithTLSConfig tells the client to use the provided *tls.Config
|
// WithTLSConfig tells the client to use the provided *tls.Config
|
||||||
func WithTLSConfig(co *tls.Config) Option {
|
func WithTLSConfig(co *tls.Config) Option {
|
||||||
return func(c *Client) error {
|
return func(c *Client) error {
|
||||||
|
@ -430,11 +467,54 @@ func (c *Client) SetTLSPolicy(p TLSPolicy) {
|
||||||
c.tlspolicy = p
|
c.tlspolicy = p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTLSPortPolicy overrides the current TLSPolicy with the given TLSPolicy
|
||||||
|
// value. The correct port is automatically set.
|
||||||
|
//
|
||||||
|
// Port 587 is used for TLSMandatory and TLSOpportunistic.
|
||||||
|
// If the connection fails with TLSOpportunistic, a plaintext connection is
|
||||||
|
// attempted on port 25 as a fallback.
|
||||||
|
// NoTLS will allways use port 25.
|
||||||
|
func (c *Client) SetTLSPortPolicy(p TLSPolicy) {
|
||||||
|
c.port = DefaultPortTLS
|
||||||
|
|
||||||
|
if p == TLSOpportunistic {
|
||||||
|
c.fallbackPort = DefaultPort
|
||||||
|
}
|
||||||
|
if p == NoTLS {
|
||||||
|
c.port = DefaultPort
|
||||||
|
}
|
||||||
|
|
||||||
|
c.tlspolicy = p
|
||||||
|
}
|
||||||
|
|
||||||
// SetSSL tells the Client wether to use SSL or not
|
// SetSSL tells the Client wether to use SSL or not
|
||||||
func (c *Client) SetSSL(s bool) {
|
func (c *Client) SetSSL(s bool) {
|
||||||
c.ssl = s
|
c.ssl = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetSSLPort tells the Client wether or not to use SSL and fallback.
|
||||||
|
// The correct port is automatically set.
|
||||||
|
//
|
||||||
|
// Port 465 is used when SSL set (true).
|
||||||
|
// Port 25 is used when SSL is unset (false).
|
||||||
|
// When the SSL connection fails and fallback is set to true,
|
||||||
|
// the client will attempt to connect on port 25 using plaintext.
|
||||||
|
func (c *Client) SetSSLPort(ssl bool, fb bool) {
|
||||||
|
if ssl {
|
||||||
|
c.port = DefaultPortSSL
|
||||||
|
} else {
|
||||||
|
c.port = DefaultPort
|
||||||
|
}
|
||||||
|
|
||||||
|
if fb {
|
||||||
|
c.fallbackPort = DefaultPort
|
||||||
|
} else {
|
||||||
|
c.fallbackPort = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
c.ssl = ssl
|
||||||
|
}
|
||||||
|
|
||||||
// SetDebugLog tells the Client whether debug logging is enabled or not
|
// SetDebugLog tells the Client whether debug logging is enabled or not
|
||||||
func (c *Client) SetDebugLog(v bool) {
|
func (c *Client) SetDebugLog(v bool) {
|
||||||
c.dl = v
|
c.dl = v
|
||||||
|
@ -507,6 +587,10 @@ func (c *Client) DialWithContext(pc context.Context) error {
|
||||||
}
|
}
|
||||||
var err error
|
var err error
|
||||||
c.co, err = c.dialContextFunc(ctx, "tcp", c.ServerAddr())
|
c.co, err = c.dialContextFunc(ctx, "tcp", c.ServerAddr())
|
||||||
|
if err != nil && c.fallbackPort != 0 {
|
||||||
|
// TODO: should we somehow log or append the previous error?
|
||||||
|
c.co, err = c.dialContextFunc(ctx, "tcp", c.serverFallbackAddr())
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -606,6 +690,12 @@ func (c *Client) checkConn() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// serverFallbackAddr returns the currently set combination of hostname
|
||||||
|
// and fallback port.
|
||||||
|
func (c *Client) serverFallbackAddr() string {
|
||||||
|
return fmt.Sprintf("%s:%d", c.host, c.fallbackPort)
|
||||||
|
}
|
||||||
|
|
||||||
// tls tries to make sure that the STARTTLS requirements are satisfied
|
// tls tries to make sure that the STARTTLS requirements are satisfied
|
||||||
func (c *Client) tls() error {
|
func (c *Client) tls() error {
|
||||||
if c.co == nil {
|
if c.co == nil {
|
||||||
|
|
Loading…
Reference in a new issue