From 28b69ef7c9df4d8f2ccb07ad7e6e7a6b344a50f0 Mon Sep 17 00:00:00 2001 From: Vladimir D Date: Mon, 27 Nov 2023 14:33:19 +0400 Subject: [PATCH] make tls InsecureSkipVerify flag configurable --- README.md | 1 + email.go | 62 ++++++++++++++++++++++++++------------------------- email_test.go | 10 ++++----- options.go | 7 ++++++ 4 files changed, 45 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index acee702..bf8567d 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ err := client.Send("some content, foo bar", - `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") diff --git a/email.go b/email.go index 033eb51..3b2ec20 100644 --- a/email.go +++ b/email.go @@ -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 @@ -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 } @@ -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, ServerName: em.host, MinVersion: tls.VersionTLS12, } diff --git a/email_test.go b/email_test.go index 9d36c6f..795cf38 100644 --- a/email_test.go +++ b/email_test.go @@ -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) @@ -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()) } diff --git a/options.go b/options.go index 0707030..1ca4812 100644 --- a/options.go +++ b/options.go @@ -54,6 +54,13 @@ func STARTTLS(enabled bool) Option { } } +// Skip certificate verification support +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) {