解决使用Golang的email库发送qq邮件报错short response,错误类型为textproto.ProtocolError

问题阐述

使用email库发送QQ邮件,采用465端口:

go 复制代码
package main

import (
	"fmt"
	"net/smtp"

	"github.com/jordan-wright/email"
)

func SendEmail(sendTo string, subject string, body string) (err error) {
	e := email.NewEmail()
	// 设置发送方的邮箱
	e.From = "193*******@qq.com"
	// 设置接收方的邮箱
	e.To = []string{sendTo}
	// 设置主题
	e.Subject = subject
	// 设置文件发送的内容
	e.Text = []byte(body)
	// e.HTML = []byte(body)
	// 设置服务器相关的配置
	err = e.Send(fmt.Sprintf("%s:%d", "smtp.qq.com", 587), smtp.PlainAuth("", "193*******@qq.com", "sdacdf********", "smtp.qq.com"))
	return
}
func main() {

	err := SendEmail("[email protected]", "测试主题",
		fmt.Sprintf("您的验证码为:%s,请勿泄露于他人!该验证码5分钟内有效!如非本人操作,请忽略此邮件!", "123456"))
	if err != nil {
		fmt.Println("发送验证码失败:", err)
		//打印错误类型
		fmt.Printf("%T\n", err)
		return
	}
	fmt.Println("发送验证码成功")
}

控制台输出下面的内容:

go 复制代码
发送验证码失败: short response: 一串乱码
textproto.ProtocolError

但是收到了验证码:

可能的原因

因为在SMTP发送过程中出现了意料之外的响应情况,可能是因为连接问题、网络不稳定,或是由于服务器的一些特定限制导致的短响应。尽管服务器响应中断,邮件实际上已经发送成功。

debug过程

尝试改用465加密(ssl)端口:

go 复制代码
package main

import (
    "crypto/tls"
    "fmt"
    "net/smtp"

    "github.com/jordan-wright/email"
)

func SendEmail(sendTo string, subject string, body string) (err error) {
	e := email.NewEmail()
	// 设置发送方的邮箱
	e.From = "193*******@qq.com"
	// 设置接收方的邮箱
	e.To = []string{sendTo}
	// 设置主题
	e.Subject = subject
	// 设置文件发送的内容
	e.Text = []byte(body)
	// e.HTML = []byte(body)
	// 设置服务器相关的配置
	// 使用 SSL 端口 465 并配置 TLS
	tlsConfig := &tls.Config{
		InsecureSkipVerify: true,
		ServerName:         "smtp.qq.com",
	}
	err = e.SendWithTLS(fmt.Sprintf("%s:%d", "smtp.qq.com", 465), smtp.PlainAuth("", "193*******@qq.com", "sdacdf********", "smtp.qq.com"), tlsConfig)
	return
}

func main() {
	err := SendEmail("[email protected]", "测试主题",
		fmt.Sprintf("您的验证码为:%s,请勿泄露于他人!该验证码5分钟内有效!如非本人操作,请忽略此邮件!", "123456"))
	if err != nil {
		fmt.Println("发送验证码失败:", err)
		//打印错误类型
		fmt.Printf("%T\n", err)
		return
	}
	fmt.Println("发送验证码成功")
}

还是报相同的错误,能够收到邮件,遂放弃封装好的email库,使用原始的smtp库,但是采用不加密的587端口:

go 复制代码
package main

import (
	"fmt"
	"net/smtp"
)

func SendEmail(sendTo string, subject string, body string) error {
	from := "193*******@qq.com"
	password := "dsfdfcf******" // 邮箱授权码
	smtpServer := "smtp.qq.com:587"

	// 邮件内容,确保包含 From 头部
	msg := []byte("From: Sender Name <" + from + ">\r\n" +
		"To: " + sendTo + "\r\n" +
		"Subject: " + subject + "\r\n" +
		"\r\n" +
		body + "\r\n")

	// 设置 PlainAuth
	auth := smtp.PlainAuth("", from, password, "smtp.qq.com")

	// 发送邮件
	err := smtp.SendMail(smtpServer, auth, from, []string{sendTo}, msg)
	if err != nil {
		return fmt.Errorf("发送失败: %v", err)
	}
	return nil
}

func main() {
	err := SendEmail("193*******@qq.com", "古树林书法社团", "您的验证码为:123456,请勿泄露于他人!该验证码5分钟内有效!如非本人操作,请忽略此邮件!")
	if err != nil {
		fmt.Println(err)
		fmt.Printf("%T\n", err)
		return
	}
	fmt.Println("发送验证码成功")
}

还是报相同的错误,能够收到邮件,于是采用加密的465端口:

go 复制代码
package main

import (
	"crypto/tls"
	"fmt"
	"net/smtp"
)

func SendEmail(sendTo string, subject string, body string) error {
	from := "193*******@qq.com"
	password := "dsfdfcf******" // 邮箱授权码
	smtpServer := "smtp.qq.com:465"

	// 设置 PlainAuth
	auth := smtp.PlainAuth("", from, password, "smtp.qq.com")

	// 创建 tls 配置
	tlsconfig := &tls.Config{
		InsecureSkipVerify: true,
		ServerName:         "smtp.qq.com",
	}

	// 连接到 SMTP 服务器
	conn, err := tls.Dial("tcp", smtpServer, tlsconfig)
	if err != nil {
		return fmt.Errorf("TLS 连接失败: %v", err)
	}
	defer conn.Close()

	client, err := smtp.NewClient(conn, "smtp.qq.com")
	if err != nil {
		return fmt.Errorf("SMTP 客户端创建失败: %v", err)
	}
	defer client.Quit()

	// 使用 auth 进行认证
	if err = client.Auth(auth); err != nil {
		return fmt.Errorf("认证失败: %v", err)
	}

	// 设置发件人和收件人
	if err = client.Mail(from); err != nil {
		return fmt.Errorf("发件人设置失败: %v", err)
	}
	if err = client.Rcpt(sendTo); err != nil {
		return fmt.Errorf("收件人设置失败: %v", err)
	}

	// 写入邮件内容
	wc, err := client.Data()
	if err != nil {
		return fmt.Errorf("数据写入失败: %v", err)
	}
	defer wc.Close()

	msg := []byte("From: Sender Name <" + from + ">\r\n" +
		"To: " + sendTo + "\r\n" +
		"Subject: " + subject + "\r\n" +
		"\r\n" +
		body + "\r\n")
	_, err = wc.Write(msg)
	if err != nil {
		return fmt.Errorf("消息发送失败: %v", err)
	}

	return nil
}

func main() {
	err := SendEmail("193*******@qq.com", "古树林书法社团", "您的验证码为:123456,请勿泄露于他人!该验证码5分钟内有效!如非本人操作,请忽略此邮件!")
	if err != nil {
		fmt.Println("发送验证码失败:", err)
		//打印错误类型
		fmt.Printf("%T\n", err)
		return
	}
	fmt.Println("发送验证码成功")
}

这次控制台显示"发送验证码成功",报错消失。

相关推荐
SoFlu软件机器人2 小时前
飞算 JavaAI 与 Spring Boot:如何实现微服务开发效率翻倍?
spring boot·后端·微服务
jack_xu3 小时前
经典大厂面试题——缓存穿透、缓存击穿、缓存雪崩
java·redis·后端
Xiaoyu Wang4 小时前
Go协程的调用与原理
开发语言·后端·golang
爱发飙的蜗牛5 小时前
springboot--web开发请求参数接收注解
java·spring boot·后端
橘猫云计算机设计6 小时前
springboot-基于Web企业短信息发送系统(源码+lw+部署文档+讲解),源码可白嫖!
java·前端·数据库·spring boot·后端·小程序·毕业设计
程序猿chen6 小时前
JVM考古现场(二十五):逆熵者·时间晶体的永恒之战(进阶篇)
java·jvm·git·后端·程序人生·java-ee·改行学it
细心的莽夫6 小时前
Elasticsearch复习笔记
java·大数据·spring boot·笔记·后端·elasticsearch·docker
程序员阿鹏6 小时前
实现SpringBoot底层机制【Tomcat启动分析+Spring容器初始化+Tomcat 如何关联 Spring容器】
java·spring boot·后端·spring·docker·tomcat·intellij-idea
Asthenia04126 小时前
HTTPS 握手过程与加密算法详解
后端
刘大猫267 小时前
Arthas sc(查看JVM已加载的类信息 )
人工智能·后端·算法