Skip to content

Fails to connect to SMTP with STARTTLS protocol #13694

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
yurivict opened this issue Dec 20, 2015 · 9 comments
Closed

Fails to connect to SMTP with STARTTLS protocol #13694

yurivict opened this issue Dec 20, 2015 · 9 comments

Comments

@yurivict
Copy link

This is about https://golang.org/src/net/smtp/smtp.go

Originally this issue is spotted in gogs, which uses the library: gogs/gogs#2244 (comment) (detailed description of the symptoms there).

@minux
Copy link
Member

minux commented Dec 20, 2015 via email

@yurivict
Copy link
Author

Ok, I will make a standalone program.

@yurivict
Copy link
Author

This example:

package main

import (
    "net/smtp"
    "fmt"
    "strconv"
    "net"
    "crypto/tls"
    "encoding/base64"
)

func main() {
  smtpHost   := "mail.{domain}.com"
  smtpPort   := 587
  smtpLogin  := "{user}@{domain}.com"
  smtpPasswd := "{password}"

  useTls     := false
  useStartTls:= true

  from := "{from@...}"
  to   := "{to@...}"
  title := "Just the sample message"

  body := "Sample message that is";

  header := make(map[string]string)
  header["From"] = from
  header["To"] = to
  header["Subject"] = title
  header["MIME-Version"] = "1.0"
  header["Content-Type"] = "text/plain; charset=\"utf-8\""
  header["Content-Transfer-Encoding"] = "base64"

  message := ""
  for k, v := range header {
      message += fmt.Sprintf("%s: %s\r\n", k, v)
  }
  message += "\r\n" + base64.StdEncoding.EncodeToString([]byte(body))

  conn, err := net.Dial("tcp", smtpHost+":"+strconv.Itoa(smtpPort))
  if err != nil {
    fmt.Println(err)
    return
  }

  // TLS
  tlsconfig := &tls.Config{
    InsecureSkipVerify: true,
    ServerName: smtpHost,
  }

  if useTls {
    conn = tls.Client(conn, tlsconfig)
  }

  client, err := smtp.NewClient(conn, smtpHost)
  if err != nil {
    fmt.Println(err)
    return
  }

  hasStartTLS, _ := client.Extension("STARTTLS")
  if useStartTls && hasStartTLS {
    fmt.Println("STARTTLS ...")
    if err = client.StartTLS(tlsconfig); err != nil {
      fmt.Println(err)
      return
    }
  }

  if err = client.Hello(smtpHost); err != nil {
    fmt.Println(err)
    return
  }
  fmt.Println("HELO done")

  // Set up authentication information.
  auth := smtp.PlainAuth(
    "",
    smtpLogin,
    smtpPasswd,
    smtpHost,
  )

  if ok, _ := client.Extension("AUTH"); ok {
    if err := client.Auth(auth); err != nil {
      fmt.Printf("Error during AUTH %s\n", err)
      return
    }
  }
  fmt.Println("AUTH done")

  if err := client.Mail(from); err != nil {
    fmt.Printf("Error: %s\n", err)
    return
  }
  fmt.Println("FROM done")

  if err := client.Rcpt(to); err != nil {
      fmt.Printf("Error: %s\n", err)
      return
  }
  fmt.Println("TO done")

  w, err := client.Data()
  if err != nil {
     fmt.Printf("Error: %s\n", err)
     return
  }

  _, err = w.Write([]byte(message))
  if err != nil {
    fmt.Printf("Error: %s\n", err)
    return
  }

  err = w.Close()
  if err != nil {
    fmt.Printf("Error: %s\n", err)
    return
  }

  client.Quit()
}

Fails with STARTTLS on the SMTP account that works fine in thunderbird:

$ ./send-mail 
STARTTLS ...
remote error: handshake failure

Same program works fine on the account expecting simple TLS.

@bradfitz
Copy link
Contributor

@yurivict, what is the domain? We don't need a username and password. Also, why is your example so long if it fails at STARTTLS? You can delete 80% of your code and still show the problem.

@yurivict
Copy link
Author

I copy-pasted the whole example that would have worked had it not been for the problem.

Domain is domain=doctorlan

@bradfitz
Copy link
Contributor

Well, if it's not a public host, we can't diagnose. The problem is almost certainly a bad certificate on the server or an incompatible set of ciphersuites supported on the server. You don't mention which version of Go. Please try Go 1.6 beta 1 which adds more TLS support.

@yurivict
Copy link
Author

go-1.5.1

@yurivict
Copy link
Author

It also fails for the same host with TLS protocol on different port: mail.doctorlan.com:465.

There is the testssl.sh https://testssl.sh/ script testing SSL/TLS connections. It doesn't find anything weird. The set of ciphers it finds is:

Hexcode  Cipher Suite Name (OpenSSL)    KeyExch.   Encryption Bits        Cipher Suite Name (RFC)
-----------------------------------------------------------------------------------------------------------------------
 x9f     DHE-RSA-AES256-GCM-SHA384      DH 2048    AESGCM     256         TLS_DHE_RSA_WITH_AES_256_GCM_SHA384               
 x6b     DHE-RSA-AES256-SHA256          DH 2048    AES        256         TLS_DHE_RSA_WITH_AES_256_CBC_SHA256               
 x9d     AES256-GCM-SHA384              RSA        AESGCM     256         TLS_RSA_WITH_AES_256_GCM_SHA384                   
 x3d     AES256-SHA256                  RSA        AES        256         TLS_RSA_WITH_AES_256_CBC_SHA256                   
 x9e     DHE-RSA-AES128-GCM-SHA256      DH 2048    AESGCM     128         TLS_DHE_RSA_WITH_AES_128_GCM_SHA256               
 x67     DHE-RSA-AES128-SHA256          DH 2048    AES        128         TLS_DHE_RSA_WITH_AES_128_CBC_SHA256               
 x9c     AES128-GCM-SHA256              RSA        AESGCM     128         TLS_RSA_WITH_AES_128_GCM_SHA256                   
 x3c     AES128-SHA256                  RSA        AES        128         TLS_RSA_WITH_AES_128_CBC_SHA256                   
 x05     RC4-SHA                        RSA        RC4        128         TLS_RSA_WITH_RC4_128_SHA                          
 x04     RC4-MD5                        RSA        RC4        128         TLS_RSA_WITH_RC4_128_MD5                          
 x010080 RC4-MD5                        RSA        RC4        128         SSL_CK_RC4_128_WITH_MD5                           

So I don't understand what's wrong with Go here.

@minux
Copy link
Member

minux commented Dec 20, 2015 via email

@golang golang locked and limited conversation to collaborators Dec 29, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants