Skip to content

Commit

Permalink
make tls InsecureSkipVerify flag configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
Vladimir D committed Nov 27, 2023
1 parent 7ee2efb commit 28b69ef
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 35 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ err := client.Send("<html>some content, foo bar</html>",
- `Port`: SMTP port (default: 25)
- `TLS`: Use TLS SMTP (default: false)
- `STARTTLS`: Use STARTTLS (default: false)
- `InsecureSkipVerify`: skip certificate verification (default: false)
- `Auth(user, password)`: Username and password for SMTP authentication (default: empty, no authentication)
- `LoginAuth`: Use [LOGIN mechanism](https://www.ietf.org/archive/id/draft-murchison-sasl-login-00.txt) instead of PLAIN mechanism for SMTP authentication, e.g. this is relevant for Office 365 and Outlook.com
- `ContentType`: Content type for the email (default: "text/plain")
Expand Down
62 changes: 32 additions & 30 deletions email.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,20 @@ import (

// Sender implements email sender
type Sender struct {
smtpClient SMTPClient
logger Logger
host string // SMTP host
port int // SMTP port
contentType string // Content type, optional. Will trigger MIME and Content-Type headers
tls bool // TLS auth
starttls bool // StartTLS
smtpUserName string // username
smtpPassword string // password
authMethod authMethod // auth method
timeOut time.Duration
contentCharset string
timeNow func() time.Time
smtpClient SMTPClient
logger Logger
host string // SMTP host
port int // SMTP port
contentType string // Content type, optional. Will trigger MIME and Content-Type headers
tls bool // TLS auth
starttls bool // StartTLS
insecureSkipVerify bool // Insecure Skip Verify
smtpUserName string // username
smtpPassword string // password
authMethod authMethod // auth method
timeOut time.Duration
contentCharset string
timeNow func() time.Time
}

// Params contains all user-defined parameters to send emails
Expand Down Expand Up @@ -70,26 +71,27 @@ type SMTPClient interface {
// NewSender creates email client with prepared smtp
func NewSender(smtpHost string, options ...Option) *Sender {
res := Sender{
smtpClient: nil,
logger: nopLogger{},
host: smtpHost,
port: 25,
contentType: `text/plain`,
tls: false,
smtpUserName: "",
smtpPassword: "",
authMethod: authMethodPlain,
contentCharset: "UTF-8",
timeOut: time.Second * 30,
timeNow: time.Now,
smtpClient: nil,
logger: nopLogger{},
host: smtpHost,
port: 25,
contentType: `text/plain`,
tls: false,
insecureSkipVerify: false,
smtpUserName: "",
smtpPassword: "",
authMethod: authMethodPlain,
contentCharset: "UTF-8",
timeOut: time.Second * 30,
timeNow: time.Now,
}
for _, opt := range options {
opt(&res)
}

res.logger.Logf("[INFO] new email sender created with host: %s:%d, tls: %v, username: %q, timeout: %v, "+
res.logger.Logf("[INFO] new email sender created with host: %s:%d, tls: %v, insecureSkipVerify: %v, username: %q, timeout: %v, "+
"content type: %q, charset: %q", smtpHost,
res.port, res.tls, res.smtpUserName, res.timeOut, res.contentType, res.contentCharset)
res.port, res.tls, res.insecureSkipVerify, res.smtpUserName, res.timeOut, res.contentType, res.contentCharset)
return &res
}

Expand Down Expand Up @@ -164,14 +166,14 @@ func (em *Sender) Send(text string, params Params) error {
}

func (em *Sender) String() string {
return fmt.Sprintf("smtp://%s:%d, auth:%v, tls:%v, starttls:%v, timeout:%v, content-type:%q, charset:%q",
em.host, em.port, em.smtpUserName != "", em.tls, em.starttls, em.timeOut, em.contentType, em.contentCharset)
return fmt.Sprintf("smtp://%s:%d, auth:%v, tls:%v, starttls:%v, insecureSkipVerify:%v, timeout:%v, content-type:%q, charset:%q",
em.host, em.port, em.smtpUserName != "", em.tls, em.starttls, em.insecureSkipVerify, em.timeOut, em.contentType, em.contentCharset)
}

func (em *Sender) client() (c *smtp.Client, err error) {
srvAddress := fmt.Sprintf("%s:%d", em.host, em.port)
tlsConf := &tls.Config{
InsecureSkipVerify: false,
InsecureSkipVerify: em.insecureSkipVerify,

Check failure on line 176 in email.go

View workflow job for this annotation

GitHub Actions / build

G402: TLS InsecureSkipVerify may be true. (gosec)
ServerName: em.host,
MinVersion: tls.VersionTLS12,
}
Expand Down
10 changes: 5 additions & 5 deletions email_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ func TestEmail_New(t *testing.T) {
}}

s := NewSender("localhost", ContentType("text/html"), Port(123),
TLS(true), STARTTLS(true), Auth("user", "pass"), TimeOut(time.Second),
TLS(true), STARTTLS(true), InsecureSkipVerify(true), Auth("user", "pass"), TimeOut(time.Second),
Log(logger), Charset("blah"),
)
require.NotNil(t, s)
assert.Equal(t, "[INFO] new email sender created with host: localhost:123, tls: true, username: \"user\", timeout: 1s, content type: \"text/html\", charset: \"blah\"",
assert.Equal(t, "[INFO] new email sender created with host: localhost:123, tls: true, insecureSkipVerify: true, username: \"user\", timeout: 1s, content type: \"text/html\", charset: \"blah\"",
logBuff.String())

assert.Equal(t, "localhost", s.host)
Expand Down Expand Up @@ -497,12 +497,12 @@ func TestWriteBodyFail(t *testing.T) {

func TestSender_String(t *testing.T) {
e := NewSender("localhost", ContentType("text/html"), Port(2525), Auth("user", "pass"))
assert.Equal(t, `smtp://localhost:2525, auth:true, tls:false, starttls:false, timeout:30s, content-type:"text/html", charset:"UTF-8"`,
assert.Equal(t, `smtp://localhost:2525, auth:true, tls:false, starttls:false, insecureSkipVerify:false, timeout:30s, content-type:"text/html", charset:"UTF-8"`,
e.String())

e = NewSender("localhost", ContentType("text/html"), Port(2525), TLS(true),
STARTTLS(true), TimeOut(10*time.Second))
assert.Equal(t, `smtp://localhost:2525, auth:false, tls:true, starttls:true, timeout:10s, content-type:"text/html", charset:"UTF-8"`,
STARTTLS(true), InsecureSkipVerify(true), TimeOut(10*time.Second))
assert.Equal(t, `smtp://localhost:2525, auth:false, tls:true, starttls:true, insecureSkipVerify:true, timeout:10s, content-type:"text/html", charset:"UTF-8"`,
e.String())
}

Expand Down
7 changes: 7 additions & 0 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func STARTTLS(enabled bool) Option {
}
}

// Skip certificate verification support

Check warning on line 57 in options.go

View workflow job for this annotation

GitHub Actions / build

exported: comment on exported function InsecureSkipVerify should be of the form "InsecureSkipVerify ..." (revive)
func InsecureSkipVerify(enabled bool) Option {
return func(s *Sender) {
s.insecureSkipVerify = enabled
}
}

// Auth sets smtp username and password
func Auth(smtpUserName, smtpPasswd string) Option {
return func(s *Sender) {
Expand Down

0 comments on commit 28b69ef

Please sign in to comment.