使用Office 365设置标准Go net / smtp失败,并显示“错误tls:第一条记录看起来不像TLS握手”

我正在尝试使用默认的Go包net / smtp创建一个简单的Go电子邮件服务-我知道有gomailer,但我想使用标准库

我需要配置tls /服务器设置以与 Office365

一起使用时需要帮助

我相信我的主机正确:

smtp.office365.com:587

但是,通过复制microsoft提供的smtp文档,运行以下代码时,控制台中出现以下错误:

错误:tls:第一条记录看起来不像TLS握手 紧急:运行时错误:无效的内存地址或nil指针取消引用

package main

import (
"fmt"
"net"
mail "net/mail"
smtp "net/smtp"
)

func main() {

from := mail.Address{"","example@example.com"}
to := mail.Address{"","example@example.com"}
subject := "My test subject"
body := "Test email body"

// Setup email headers
headers := make(map[string]string)
headers["From"] = from.String()
headers["To"] = to.String()
headers["Subject"] = subject

message := ""
for k,v := range headers {
    message += fmt.Sprintf("%s: %s\r\n",k,v)
}
message += "\r\n" + body

servername := "smtp.office365.com:587"
host,_,_ := net.SplithostPort(servername)

auth := smtp.PlainAuth("","example@example.com","password",host)

tlsconfig := &tls.Config{
    InsecureSkipVerify: true,ServerName:         host,}

conn,err := tls.Dial("tcp","smtp.office365.com:587",tlsconfig)
if err != nil {
    fmt.Println("tls.Dial Error: %s",err)
}

c,err := smtp.NewClient(conn,host)
if err != nil {
    fmt.Println("smtp.NewClient Error: %s",err)
}

if err = c.Auth(auth); err != nil {
    fmt.Println("c.Auth Error: %s",err)
}

if err = c.Mail(from.Address); err != nil {
    fmt.Println("c.Mail Error: %s",err)
}

if err = c.Rcpt(to.Address); err != nil {
    fmt.Println("c.Rcpt Error: %s",err)
}

w,err := c.Data()
if err != nil {
    fmt.Println("c.Data Error: %s",err)
}

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

err = w.Close()
if err != nil {
    fmt.Println("reader Error: %s",err)
}

c.Quit()
}

任何O365客户端的示例都将受到赞赏,或者任何人都可以发现的看起来可疑的东西都是很棒的

谢谢

gzabocom 回答:使用Office 365设置标准Go net / smtp失败,并显示“错误tls:第一条记录看起来不像TLS握手”

错误消息Error: tls: first record does not look like a TLS handshake告诉您问题出在哪里:-)。如果尝试连接到服务器,您将看到(与任何SMTP服务器一样)它使用纯文本:

telnet smtp.office365.com 587
Trying 2603:1026:c0b:10::2...
Connected to zrh-efz.ms-acdc.office.com.
Escape character is '^]'.
220 ZRAP278CA0003.outlook.office365.com Microsoft ESMTP MAIL Service ready at Mon,11 Nov 2019 17:13:50 +0000
...

您需要使用STARTTLS命令,请参见https://en.wikipedia.org/wiki/Opportunistic_TLS(以及该Wiki页面所指向的RFC)。

在Go中,它是https://golang.org/pkg/net/smtp/#Client.StartTLS

在您的代码中,我注意到了

tlsconfig := &tls.Config{
    InsecureSkipVerify: true,<== REMOVE THIS
    ServerName:         host,}

请删除InsecureSkipVerify,顾名思义,它是不安全的,与您面临的错误无关。

,
  1. Outlook.com自2017年8月起不再支持AUTH PLAIN身份验证。

https://support.microsoft.com/en-us/office/outlook-com-no-longer-supports-auth-plain-authentication-07f7d5e9-1697-465f-84d2-4513d4ff0145?ui=en-us&rs=en-us&ad=us

  1. 使用AUTH LOGIN

以下代码实现了AUTH LOGIN

type loginAuth struct {
    username,password string
}

func LoginAuth(username,password string) smtp.Auth {
    return &loginAuth{username,password}
}


func (a *loginAuth) Start(server *smtp.ServerInfo) (string,[]byte,error) {
    return "LOGIN",[]byte(a.username),nil
}


func (a *loginAuth) Next(fromServer []byte,more bool) ([]byte,error) {
    if more {
        switch string(fromServer) {
        case "Username:":
            return []byte(a.username),nil
        case "Password:":
            return []byte(a.password),nil
        default:
            return nil,errors.New("Unknown from server")
        }
    }
    return nil,nil
}
  1. 删除“ InsecureSkipVerify:true”
tlsconfig := &tls.Config {
    ServerName: host,}
  1. 请勿使用tsl.Dial(),而应使用net.Dial()
conn,err := net.Dial("tcp","smtp.office365.com:587")
if err != nil {
    return err
}
  1. 在smtp.NewClient()之后调用StartTLS()
c,err := smtp.NewClient(conn,host)
if err != nil {
    return err
}

if err = c.StartTLS(tlsconfig); err != nil {
    return err
}
  1. 使用AUTH LOGIN
auth := LoginAuth(fromAddress,password) 

if err = c.Auth(auth); err != nil {
    return err
}
,

以下与我合作很好:

package main

import (
    "bytes"
    "crypto/tls"
    "errors"
    "fmt"
    "net"
    "net/smtp"
    "text/template"
)

type loginAuth struct {
    username,password}
}

func (a *loginAuth) Start(server *smtp.ServerInfo) (string,nil
}

func (a *loginAuth) Next(fromServer []byte,nil
}

func main() {

    // Sender data.
    from := "O365 logging name"
    password := "O365 logging pasword"

    // Receiver email address.
    to := []string{
        "receiver email",}

    // smtp server configuration.
    smtpHost := "smtp.office365.com"
    smtpPort := "587"

    conn,"smtp.office365.com:587")
    if err != nil {
        println(err)
    }

    c,smtpHost)
    if err != nil {
        println(err)
    }

    tlsconfig := &tls.Config{
        ServerName: smtpHost,}

    if err = c.StartTLS(tlsconfig); err != nil {
        println(err)
    }

    auth := LoginAuth(from,password)

    if err = c.Auth(auth); err != nil {
        println(err)
    }

    t,_ := template.ParseFiles("template.html")

    var body bytes.Buffer

    mimeHeaders := "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\n\n"
    body.Write([]byte(fmt.Sprintf("Subject: This is a test subject \n%s\n\n",mimeHeaders)))

    t.Execute(&body,struct {
        Name    string
        Message string
    }{
        Name:    "Hasan Yousef",Message: "This is a test message in a HTML template",})

    // Sending email.
    err = smtp.SendMail(smtpHost+":"+smtpPort,auth,from,to,body.Bytes())
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("Email Sent!")
}

使用以下模板作为奖励:)

<!-- template.html -->
<!DOCTYPE html>
<html>
<body>
    <h3>Name:</h3><span>{{.Name}}</span><br/><br/>
    <h3>Email:</h3><span>{{.Message}}</span><br/>
</body>
</html>
,

所以问题全在授权上。首先要求我在客户端上使用StartTLS方法,还要求我编写一个函数和方法来支持LOGIN,而标准Go库则不支持(出于某种原因)

请参阅main()上方的函数和结构

这是带有帮助程序功能的完整代码,现在可以通过我的O365帐户成功发送电子邮件:

package main

import (
"fmt"
"net"
"errors"
mail "net/mail"
smtp "net/smtp"
)

type loginAuth struct {
    username,[]byte{},errors.New("Unknown fromServer")
        }
    }
    return nil,nil
}

func main() {

from := mail.Address{"","example@example.com"}
to := mail.Address{"","example@example.com"}
subject := "My test subject"
body := "Test email body"

headers := make(map[string]string)
headers["From"] = from.String()
headers["To"] = to.String()
headers["Subject"] = subject

message := ""
for k,v := range headers {
    message += fmt.Sprintf("%s: %s\r\n",k,v)
}
message += "\r\n" + body

tlsconfig := &tls.Config{
    ServerName:         host,}

conn,err := tls.Dial("tcp","smtp.office365.com:587",tlsconfig)
if err != nil {
    fmt.Println("tls.Dial Error: ",err)
}

c,host)
if err != nil {
    fmt.Println("smtp.NewClient Error: ",err)
}


if err = c.Auth(LoginAuth("example@example.com","password")); err != nil {
        fmt.Println("c.Auth Error: ",err)
        return
}

if err = c.Mail(from.Address); err != nil {
    fmt.Println("c.Mail Error: ",err)
}

if err = c.Rcpt(to.Address); err != nil {
    fmt.Println("c.Rcpt Error: ",err)
}

w,err := c.Data()
if err != nil {
    fmt.Println("c.Data Error: ",err)
}

_,err = w.Write([]byte(message))
if err != nil {
    fmt.Println("Error: ",err)
}

err = w.Close()
if err != nil {
    fmt.Println("reader Error: ",err)
}

c.Quit()
}
本文链接:https://www.f2er.com/3122917.html

大家都在问