我有一个小应用程序可以验证邮件服务器上是否存在电子邮件。我知道我的实现不会给出 100% 的结果,但顺其自然吧。 所以,我得到了获取电子邮件 slice 并检查该 slice 中的每封电子邮件的函数:
func CheckMails(mails []string) []string {
var existingMails []string
fmt.Printf("!!!!!!!!!!!!!!STARTING!!!!!!!!!!!! %s \n\n\n", mails[1])
for i := 0; i < len(mails); i++ {
err := validateHost(mails[i])
if err != nil {
fmt.Printf("Error validating host. %s", err)
}
smtpErr, ok := err.(checkmail.SmtpError)
if ok {
fmt.Printf("Code: %s, Msg: %s", smtpErr.Code(), smtpErr)
if smtpErr.Code() == "dia" {
break
}
} else {
fmt.Println("Email exists")
existingMails = append(existingMails, mails[i])
}
}
fmt.Printf("!!!!!!!!!!!!!!ENDING!!!!!!!!!!!! %s \n\n\n", mails[1])
return existingMails
}
下一步 - 我的函数从字面上检查电子邮件是否存在(顺便说一句,这个函数来自小型库 github.com/badoux/checkmail 但如果我只使用这个函数,我将它复制粘贴到我的代码中以记录错误、变量等。 ):
func validateHost(email string) error {
_, host := split(email)
mx, err := net.LookupMX(host)
if err != nil {
fmt.Printf("Error, UnresolvableHost! %s", err)
}
client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
// fmt.Println(client)
defer client.Close()
if err != nil {
//fmt.Println(client)
//log.Fatalln(err)
fmt.Printf("SmtpError! %s \n", err)
}
t := time.AfterFunc(forceDisconnectAfter, func() { client.Close() })
defer t.Stop()
// t := NewTimer(10, func() { client.Close() })
// defer t.Stop()
err = client.Hello("checkmail.me")
//err = client.Hello("gmail.com")
// fmt.Println(client)
if err != nil {
//log.Fatalln(err)
fmt.Printf("client.Hello SmtpError! %s \n", err)
}
err = client.Mail("lansome-cowboy@gmail.com")
if err != nil {
fmt.Printf("client.MailSmtpError! %s \n", err)
}
err = client.Rcpt(email)
if err != nil {
fmt.Printf("client.Rcpt SmtpError! %s \n", err)
}
return nil
}
而且我还制作了支持功能,该功能会中断检查服务器响应是否太长:
// CheckMailsWithExpectedInterval want to get expectected number of seconds which you are ready to wait while
// the mail trys to be validated (this time is for ONE mail, slice could have a lot of mails to check)
// and slice of mails which should be validated
func CheckMailsWithExpectedInterval(expectedSec int, mails []string) (ok bool, existingMails []string) {
done := make(chan struct{})
t1 := time.Now()
var eMails []string
go func() {
eMails = CheckMails(mails)
close(done)
}()
select {
case <-done:
if len(eMails) > 1 {
ok = false
} else {
ok = true
existingMails = eMails
}
case <-time.After(time.Duration(expectedSec) * time.Second):
}
fmt.Printf("\nTime since:")
fmt.Println(time.Since(t1))
return ok, existingMails
}
以及上述功能需要的其他支持功能:
func split(email string) (account, host string) {
i := strings.LastIndexByte(email, '@')
account = email[:i]
host = email[i+1:]
return
}
const forceDisconnectAfter = time.Second * 10
进入函数的 slice 的例子是
email1 := []string{
"andreasId@fromatob.com",
"Andreas.Wolff@fromatob.com",
"AndreasWolff@fromatob.com",
"Wolff.Andreas@fromatob.com",
"WolffAndreas@fromatob.com",
"Andreas@fromatob.com,Wolff@fromatob.com",
"A.Wolff@fromatob.com",
"AWolff@fromatob.com",
"Andreas.W@fromatob.com",
"AndreasW@fromatob.com",
"Wolff.A@fromatob.com",
"WolffA@fromatob.com",
"W.Andreas@fromatob.com",
"WAndreas@fromatob.com",
}
我遇到了下一个问题。有时我的应用程序 panic 下一个:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x84fefa]
goroutine 260 [running]:
net/smtp.(*Client).Close(0x0, 0x0, 0x0)
/usr/lib/go-1.10/src/net/smtp/smtp.go:76 +0x2a
panic(0x90a360, 0xb94ae0)
/usr/lib/go-1.10/src/runtime/panic.go:502 +0x24a
net/smtp.(*Client).Hello(0x0, 0x97d912, 0x9, 0x0, 0x0)
/usr/lib/go-1.10/src/net/smtp/smtp.go:100 +0x78
magictool/mailchecker.validateHost(0xc4204c7020, 0x23, 0x0, 0x0)
/home/username/go/src/magictool/mailchecker/mailchecker.go:115 +0x749
magictool/mailchecker.CheckMails(0xc4201c0000, 0xf, 0xf, 0x0, 0x0, 0x0)
/home/username/go/src/magictool/mailchecker/mailchecker.go:20 +0x1d1
magictool/mailchecker.CheckMailsWithExpectedInterval.func1(0xc4201c0000, 0xf, 0xf, 0xc42038f5c0, 0xc4203b7ec0)
/home/username/go/src/magictool/mailchecker/mailchecker.go:49 +0x3f
created by magictool/mailchecker.CheckMailsWithExpectedInterval
/home/username/go/src/magictool/mailchecker/mailchecker.go:48 +0x12c
我真的无法理解如何处理这种 panic 。另外,仅供引用,应用程序在检查了大约 3-5 个 slice 后崩溃,几个小时前检查了 10 个邮件 slice ,然后崩溃了。
而且,重要的是,过去 1-2 周一切都很好,没有错误/ panic 。我给函数提供了 20-50-100-150 封电子邮件(1 封邮件接近 15 封电子邮件)并且没有错误。
如有任何帮助,我们将不胜感激!
最佳答案
您没有进行正确的错误处理。这可能是您遇到问题的原因。特别是,您会从堆栈跟踪中注意到,您在标准库的 smtp.go
文件的第 76 行遇到了 panic 。这一行写着:
return c.Text.Close()
看来您正在尝试关闭无效连接。
当我们阅读您的代码时,这很直观:
client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25))
// fmt.Println(client)
defer client.Close()
if err != nil {
//fmt.Println(client)
//log.Fatalln(err)
fmt.Printf("SmtpError! %s \n", err)
}
您甚至在知道客户端连接是否有效之前就调用了 defer client.Close()
。这意味着如果 SMTP 连接失败,您将尝试关闭无效连接,这很可能会导致观察到的行为。
要更正此问题,您必须进行两项更改。
不仅要打印错误,还要处理它们。这可能只是意味着归还它们:
client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25)) defer client.Close() if err != nil { return err }
针对您的每一个错误执行此操作。
只有在知道连接有效后才调用
client.Close()
!client, err := smtp.Dial(fmt.Sprintf("%s:%d", mx[0].Host, 25)) if err != nil { return err } defer client.Close()
关于go - golang 中的 smtp 问题( panic ,信号 SIGSEGV : segmentation violation),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50292325/