Golang使用smtp.SendMail时出现“崩溃”问题如何解决
Golang使用smtp.SendMail时出现“崩溃”问题如何解决 我有一个使用Golang作为"Apache"的网站。
http.ListenAndServe(":9090", nil) <----- 启动网站
在这个网站中,我有一个表单,使用smtp.SendMail提交邮件。
-
发送"有效"邮件地址时工作完美
-
发送"有效"邮件地址时有时返回"550 5.7.1 SPF失败。域名test.com不允许从(IP地址)发送邮件"
-
发送"无意义"邮件地址(test)失败并报告"501 5.1.7 发件人地址语法错误"
mailfrom = "test@company.se" <--- 有效的邮件地址
auth := smtp.PlainAuth("", "sibert@gmail.com", "password", "smtp.gmail.com")
from := (mailfrom)
to := []string{"sibert@gmail.com"}
msg := []byte("From: " + mailfrom + "\r\n" +
"To: support@company.com\r\n" +
"Subject: Test\r\n" +
"testmail\r\n" +
(mailfrom))
err := smtp.SendMail("smtp.gmail.com:587", auth, from, to, msg)
if err != nil {
log.Fatal(err)
}
}
有两个问题:
- 如何捕获这个错误并向用户发送"抱歉,邮件未送达"?
- 当Go不喜欢邮件地址时,如何防止"http.ListenAndServe"崩溃?
更多关于Golang使用smtp.SendMail时出现“崩溃”问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
好的,记录错误或更少。
更多关于Golang使用smtp.SendMail时出现“崩溃”问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
不要使用致命日志记录,它意味着程序会发生恐慌。
谢谢!这解决了问题。
if err != nil {
return ("sorry.html")
}
return ("thanks.html")
NobbZ:
不要使用致命日志记录,这会导致程序恐慌。
那我应该怎么做?
我不清楚这个函数原本应该做什么,但对我来说,当它应该发送邮件时却返回一个HTML文档的名称,这似乎不太对劲。
此外,通常你会希望记录错误及其原因,因为用户可能会试图寻找你软件中的弱点。
最后但同样重要的是,return 不是一个函数,不需要加括号……
func main() {
fmt.Println("hello world")
}
针对您的问题,以下是解决方案和示例代码:
问题1:捕获错误并向用户返回友好消息
package main
import (
"fmt"
"log"
"net/http"
"net/smtp"
"strings"
)
func sendEmailHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
mailfrom := "test@company.se"
auth := smtp.PlainAuth("", "sibert@gmail.com", "password", "smtp.gmail.com")
from := mailfrom
to := []string{"sibert@gmail.com"}
msg := []byte("From: " + mailfrom + "\r\n" +
"To: support@company.com\r\n" +
"Subject: Test\r\n" +
"testmail\r\n" +
mailfrom)
err := smtp.SendMail("smtp.gmail.com:587", auth, from, to, msg)
if err != nil {
log.Printf("邮件发送失败: %v", err)
// 检查错误类型并返回友好消息
errorMsg := "抱歉,邮件未送达"
if strings.Contains(err.Error(), "550") {
errorMsg = "抱歉,邮件发送失败:SPF验证问题"
} else if strings.Contains(err.Error(), "501") {
errorMsg = "抱歉,邮件地址格式不正确"
}
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "邮件发送成功")
}
func main() {
http.HandleFunc("/send-email", sendEmailHandler)
log.Println("服务器启动在 :9090")
log.Fatal(http.ListenAndServe(":9090", nil))
}
问题2:防止服务器崩溃的完整解决方案
package main
import (
"fmt"
"log"
"net/http"
"net/smtp"
"strings"
)
func validateEmail(email string) bool {
// 简单的邮箱格式验证
return strings.Contains(email, "@") && strings.Contains(email, ".")
}
func sendEmailHandler(w http.ResponseWriter, r *http.Request) {
// 使用defer和recover捕获panic
defer func() {
if err := recover(); err != nil {
log.Printf("处理请求时发生panic: %v", err)
http.Error(w, "服务器内部错误", http.StatusInternalServerError)
}
}()
if r.Method != "POST" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 从表单获取邮件地址
r.ParseForm()
mailfrom := r.FormValue("email")
// 验证邮件地址格式
if !validateEmail(mailfrom) {
http.Error(w, "无效的邮件地址格式", http.StatusBadRequest)
return
}
auth := smtp.PlainAuth("", "sibert@gmail.com", "password", "smtp.gmail.com")
from := mailfrom
to := []string{"sibert@gmail.com"}
msg := []byte("From: " + mailfrom + "\r\n" +
"To: support@company.com\r\n" +
"Subject: Test\r\n" +
"Content-Type: text/plain; charset=UTF-8\r\n" +
"\r\n" +
"testmail\r\n" +
"发件人: " + mailfrom)
err := smtp.SendMail("smtp.gmail.com:587", auth, from, to, msg)
if err != nil {
log.Printf("SMTP错误: %v", err)
// 分类处理不同的SMTP错误
errorMsg := "抱歉,邮件发送失败"
errStr := err.Error()
switch {
case strings.Contains(errStr, "550"):
errorMsg = "邮件发送失败:SPF验证未通过"
case strings.Contains(errStr, "501"):
errorMsg = "邮件地址格式不正确"
case strings.Contains(errStr, "535"):
errorMsg = "认证失败,请检查账号密码"
case strings.Contains(errStr, "421"):
errorMsg = "邮件服务器暂时不可用"
}
http.Error(w, errorMsg, http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "邮件发送成功")
}
func main() {
// 设置全局panic处理
defer func() {
if err := recover(); err != nil {
log.Printf("服务器发生panic: %v", err)
}
}()
http.HandleFunc("/send-email", sendEmailHandler)
log.Println("服务器启动在 :9090")
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatalf("服务器启动失败: %v", err)
}
}
增强的错误处理版本
package main
import (
"fmt"
"log"
"net/http"
"net/smtp"
"regexp"
)
type EmailService struct {
smtpHost string
smtpPort string
auth smtp.Auth
}
func NewEmailService(username, password, host, port string) *EmailService {
auth := smtp.PlainAuth("", username, password, host)
return &EmailService{
smtpHost: host,
smtpPort: port,
auth: auth,
}
}
func (es *EmailService) SendEmail(from, to, subject, body string) error {
// 验证邮件地址
if !isValidEmail(from) || !isValidEmail(to) {
return fmt.Errorf("无效的邮件地址格式")
}
msg := []byte(fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s",
from, to, subject, body))
server := fmt.Sprintf("%s:%s", es.smtpHost, es.smtpPort)
return smtp.SendMail(server, es.auth, from, []string{to}, msg)
}
func isValidEmail(email string) bool {
emailRegex := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
matched, _ := regexp.MatchString(emailRegex, email)
return matched
}
func main() {
emailService := NewEmailService("sibert@gmail.com", "password", "smtp.gmail.com", "587")
http.HandleFunc("/send-email", func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("Handler panic: %v", err)
http.Error(w, "内部服务器错误", http.StatusInternalServerError)
}
}()
if r.Method != "POST" {
http.Error(w, "方法不允许", http.StatusMethodNotAllowed)
return
}
r.ParseForm()
from := r.FormValue("from")
to := r.FormValue("to")
subject := r.FormValue("subject")
body := r.FormValue("body")
err := emailService.SendEmail(from, to, subject, body)
if err != nil {
log.Printf("邮件发送错误: %v", err)
http.Error(w, "抱歉,邮件发送失败: "+err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "邮件发送成功")
})
log.Println("服务器运行在 :9090")
log.Fatal(http.ListenAndServe(":9090", nil))
}
这些解决方案通过以下方式解决问题:
- 使用
defer和recover()捕获 panic 防止服务器崩溃 - 对 SMTP 错误进行分类处理,返回用户友好的错误信息
- 添加邮件地址格式验证,提前拦截无效地址
- 使用结构体封装邮件服务,提高代码可维护性

