
第一段引用上面的摘要:
本文档介绍了在使用 Go 语言通过非加密 SMTP 连接发送电子邮件时可能遇到的 "unencrypted connection" 错误,并提供了绕过此限制的两种解决方案:复制并修改标准库中的 smtp.PlainAuth 函数,或者创建一个包装器类型来欺骗身份验证机制,使其认为连接已加密。同时强调了使用加密连接的重要性,并建议尽可能使用更安全的身份验证机制,如 CRAM-MD5。
在使用 Go 语言的 net/smtp 包发送电子邮件时,如果尝试通过未加密的连接使用 smtp.PlainAuth 进行身份验证,可能会遇到 "unencrypted connection" 错误。这是因为 smtp.PlainAuth 默认情况下拒绝在非加密连接上发送密码,以保护用户的安全。
解决方案一:修改 smtp.PlainAuth (不推荐)
虽然不推荐,但如果确实需要通过非加密连接发送邮件,可以复制 smtp.PlainAuth 的源代码并进行修改,移除对加密连接的检查。
找到 smtp.PlainAuth 的源代码: 可以在 Go 语言标准库的 net/smtp/auth.go 文件中找到 PlainAuth 函数的实现。
复制并修改代码: 将该函数复制到你的项目中,并删除以下代码段:
if !server.TLS {
return "", nil, errors.New("unencrypted connection")
}- 使用修改后的函数: 在你的代码中使用修改后的函数进行身份验证。
重要提示: 这种方法极不安全,因为你的密码将以明文形式通过网络传输。强烈建议不要在生产环境中使用此方法。
解决方案二:创建包装器类型 (推荐)
一个更安全的选择是创建一个包装器类型,欺骗身份验证机制,使其认为连接已加密。
采用三层架构开发,前台集成了产品在线展示,用户注册、在线调查、在线投稿后台有类别管理\图书管理\订单管理\会员管理\配送范围管理\邮件列表\广告管理\友情链接管理等后台添加图书时自动生成缩略图和文字水印主要参考了petshop的设计架构、使用了Asp.net2.0中很多MemberShip、master等新功能后台管理地址/web/admin/ 超级管理员账号密码均为aspx1特别提示:该系统需要
type unencryptedAuth struct {
smtp.Auth
}
func (a unencryptedAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {
s := *server
s.TLS = true
return a.Auth.Start(&s)
}
// 使用示例
auth := unencryptedAuth {
smtp.PlainAuth(
"",
"your_email@example.com",
"your_password",
"mail.example.com",
),
}
// 然后像往常一样使用 auth 变量
err := smtp.SendMail(
"mail.example.com:25",
auth,
"sender@example.com",
[]string{"recipient@example.com"},
[]byte("This is the email body."),
)
if err != nil {
log.Fatal(err)
}代码解释:
- unencryptedAuth 结构体包装了 smtp.Auth 接口。
- Start 方法拦截了 *smtp.ServerInfo,并将其 TLS 字段设置为 true,从而欺骗了底层的身份验证机制。
注意事项:
- 虽然这种方法比直接修改 smtp.PlainAuth 更安全,但仍然存在风险,因为你的密码仍然以明文形式发送。
- 务必在代码中添加详细的注释,说明你为什么要这样做,以及潜在的安全风险。
最佳实践:使用加密连接和更安全的身份验证机制
强烈建议尽可能使用加密连接(TLS/SSL)和更安全的身份验证机制,如 CRAM-MD5 或 OAuth 2.0。这些方法可以更好地保护你的密码和数据安全。
以下是使用 TLS 连接发送邮件的示例代码:
package main
import (
"crypto/tls"
"log"
"net/smtp"
)
func main() {
// Set up authentication information.
auth := smtp.PlainAuth(
"",
"your_email@example.com",
"your_password",
"mail.example.com",
)
// Connect to the server.
conn, err := tls.Dial("tcp", "mail.example.com:465", &tls.Config{})
if err != nil {
log.Fatal(err)
}
client, err := smtp.NewClient(conn, "mail.example.com")
if err != nil {
log.Fatal(err)
}
// Authenticate.
if err = client.Auth(auth); err != nil {
log.Fatal(err)
}
// Set the sender and recipient.
if err = client.Mail("sender@example.com"); err != nil {
log.Fatal(err)
}
if err = client.Rcpt("recipient@example.com"); err != nil {
log.Fatal(err)
}
// Send the email body.
wc, err := client.Data()
if err != nil {
log.Fatal(err)
}
_, err = wc.Write([]byte("This is the email body."))
if err != nil {
log.Fatal(err)
}
err = wc.Close()
if err != nil {
log.Fatal(err)
}
// Quit.
err = client.Quit()
if err != nil {
log.Fatal(err)
}
}总结:
虽然可以通过修改代码或创建包装器类型来绕过 Go 语言 net/smtp 包的加密连接检查,但强烈建议不要这样做。为了保护你的密码和数据安全,应该尽可能使用加密连接和更安全的身份验证机制。 在不得不使用非加密连接的情况下,务必权衡安全风险,并采取必要的保护措施。









