Skip to content

Commit

Permalink
smtp: Support connect TLS server (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
sunshineplan authored Jan 3, 2024
1 parent f6be316 commit 8094598
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 20 deletions.
24 changes: 16 additions & 8 deletions mail/mail.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,37 @@ import (
type Dialer struct {
Server string
Port int
TLS bool
Account string
Password string
Timeout time.Duration
}

func (d *Dialer) Dial() (*smtp.Client, error) {
func (d *Dialer) Dial() (client *smtp.Client, err error) {
if d.Timeout == 0 {
d.Timeout = 3 * time.Minute
}

ctx, cancel := context.WithTimeout(context.Background(), d.Timeout)
defer cancel()

client, err := smtp.Dial(ctx, fmt.Sprintf("%s:%d", d.Server, d.Port))
if d.TLS {
client, err = smtp.DialTLS(ctx, fmt.Sprintf("%s:%d", d.Server, d.Port))
} else {
client, err = smtp.Dial(ctx, fmt.Sprintf("%s:%d", d.Server, d.Port))
}
if err != nil {
return nil, err
return
}
if ok, _ := client.Extension("STARTTLS"); ok {
if err := client.StartTLS(nil); err != nil {
client.Quit()
return nil, err

if !d.TLS {
if ok, _ := client.Extension("STARTTLS"); ok {
if err = client.StartTLS(nil); err != nil {
return
}
}
}

if ok, _ := client.Extension("AUTH"); ok && d.Account != "" && d.Password != "" {
if err = client.Auth2(&smtp.Auth{Identity: "", Username: d.Account, Password: d.Password, Server: d.Server}); err != nil {
client.Quit()
Expand Down Expand Up @@ -110,5 +118,5 @@ func (d *Dialer) Send(msg ...*Message) error {
func (d *Dialer) SendMail(ctx context.Context, from string, to []string, msg []byte) error {
addr := fmt.Sprintf("%s:%d", d.Server, d.Port)
auth := &smtp.Auth{Identity: "", Username: d.Account, Password: d.Password, Server: d.Server}
return smtp.SendMail(ctx, addr, auth, from, to, msg)
return smtp.SendMail(ctx, addr, d.TLS, auth, from, to, msg)
}
49 changes: 37 additions & 12 deletions smtp/smtp.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,22 @@ func Dial(ctx context.Context, addr string) (*Client, error) {
return NewClient(conn, host)
}

// DialTLS returns a new Client connected to an SMTP server with TLS connection at addr.
// The addr must include a port, as in "mail.example.com:smtp".
func DialTLS(ctx context.Context, addr string) (*Client, error) {
host, _, err := net.SplitHostPort(addr)
if err != nil {
return nil, err
}

d := &tls.Dialer{Config: &tls.Config{ServerName: host}}
conn, err := d.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}
return NewClient(conn, host)
}

// NewClient returns a new Client using an existing connection and host as a
// server name to be used when authenticating.
func NewClient(conn net.Conn, host string) (*Client, error) {
Expand Down Expand Up @@ -163,7 +179,8 @@ func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool) {
if !ok {
return
}
return tc.ConnectionState(), true
state = tc.ConnectionState()
return
}

// Verify checks the validity of an email address on the server.
Expand Down Expand Up @@ -371,33 +388,41 @@ func (c *Client) SendMail(from string, to []string, msg []byte) error {
// fields such as "From", "To", "Subject", and "Cc". Sending "Bcc"
// messages is accomplished by including an email address in the to
// parameter but not including it in the msg headers.
func SendMail(ctx context.Context, addr string, auth *Auth, from string, to []string, msg []byte) error {
if err := validateLine(from); err != nil {
return err
func SendMail(ctx context.Context, addr string, tls bool, auth *Auth, from string, to []string, msg []byte) (err error) {
if err = validateLine(from); err != nil {
return
}
for _, recp := range to {
if err := validateLine(recp); err != nil {
return err
if err = validateLine(recp); err != nil {
return
}
}

c, err := Dial(ctx, addr)
var c *Client
if tls {
c, err = DialTLS(ctx, addr)
} else {
c, err = Dial(ctx, addr)
}
if err != nil {
return err
return
}
defer c.Quit()

if ok, _ := c.Extension("STARTTLS"); ok {
if err := c.StartTLS(nil); err != nil {
return err
if !tls {
if ok, _ := c.Extension("STARTTLS"); ok {
if err = c.StartTLS(nil); err != nil {
return
}
}
}

if auth != nil && c.ext != nil {
if _, ok := c.ext["AUTH"]; !ok {
return errors.New("smtp: server doesn't support AUTH")
}
if err = c.Auth2(auth); err != nil {
return err
return
}
}

Expand Down

0 comments on commit 8094598

Please sign in to comment.