我正在尝试使用默认的Go包net/smtp创建一个简单的Go电子邮件服务--我知道有gomailer,但我想使用标准库
我需要帮助将tls/server设置配置为使用Office365。
我相信我有正确的主人:
smtp.office365.com:587但是,在复制Microsoft提供的smtp文档时,在运行以下代码时,控制台中会出现以下错误:
错误: tls:第一条记录看起来不像TLS握手恐慌:运行时错误:无效的内存地址或零指针取消引用
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客户端的例子都会受到赞赏,或者任何人能发现的任何看起来可疑的东西都会很好。
谢谢
发布于 2019-11-12 15:00:46
所以问题都是关于授权的。首先,我需要在客户机上使用StartTLS方法,还需要编写一个函数和方法来支持登录,这是标准Go库所不支持的(无论出于什么原因)。
请参阅main()上面的函数和结构。
下面是带有助手函数的完整代码,它现在可以通过我的O365帐户成功地发送电子邮件:
package main
import (
"fmt"
"net"
"errors"
mail "net/mail"
smtp "net/smtp"
)
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{}, 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 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, err := smtp.NewClient(conn, 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()
}发布于 2019-11-11 17:22:36
错误消息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页面所指向的RFCs )。
在Go中,它是https://golang.org/pkg/net/smtp/#Client.StartTLS。
在你的代码中我注意到
tlsconfig := &tls.Config{
InsecureSkipVerify: true, <== REMOVE THIS
ServerName: host,
}请删除InsecureSkipVerify,顾名思义,它是不安全的,与您所面临的错误无关。
发布于 2020-08-19 14:23:57
自2017年8月以来,
以下代码实现AUTH登录
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
}tlsconfig := &tls.Config {
ServerName: host,
}conn, err := net.Dial("tcp", "smtp.office365.com:587")
if err != nil {
return err
}smtp.NewClient()后的
c, err := smtp.NewClient(conn, host)
if err != nil {
return err
}
if err = c.StartTLS(tlsconfig); err != nil {
return err
}auth := LoginAuth(fromAddress, password)
if err = c.Auth(auth); err != nil {
return err
}https://stackoverflow.com/questions/58804817
复制相似问题