用go语言直接向mx记录的25端口发邮件
已测试可以成功向qq邮箱、icloud和gmail发邮件,除了gmail会进垃圾邮箱,其他都正常收信
下面是linux的搭建步骤
wget -O /root/go1.23.2.linux-amd64.tar.gz https://golang.google.cn/dl/go1.23.2.linux-amd64.tar.gz
tar xf /root/go1.23.2.linux-amd64.tar.gz -C /root
mkdir /root/sendmail
cd /root/sendmail
nano main.go
/root/go/bin/go mod init sendmail
/root/go/bin/go build
./sendmail -from go-sendmail-test@2398dj.com -to 309385018@qq.com -subject GO语言测试邮件 -body 这是你要发的邮件内容
AI提示词
用go语言直接向mx记录的25端口发邮件,要采用STARTTLS连接方式,要包含Message-ID,要做成实用工具可指定from\to\subject\body
package main
import (
"crypto/tls"
"flag"
"fmt"
"log"
"math/rand"
"net"
"net/smtp"
"strings"
"time"
)
func main() {
// 定义命令行参数
fromPtr := flag.String("from", "", "发件人邮箱")
toPtr := flag.String("to", "", "收件人邮箱")
subjectPtr := flag.String("subject", "", "邮件主题")
bodyPtr := flag.String("body", "", "邮件内容")
flag.Parse()
// 检查必填参数
if *fromPtr == "" || *toPtr == "" || *subjectPtr == "" || *bodyPtr == "" {
fmt.Println("Usage: ./sendmail -from <sender_email> -to <recipient_email> -subject <subject> -body <bodytext>")
return
}
// 发送邮件
err := SendMail(*fromPtr, *toPtr, *subjectPtr, *bodyPtr)
if err != nil {
log.Fatal(err)
}
fmt.Println("Email sent successfully")
}
func generateMessageID(from string) string {
timestamp := time.Now().UnixNano()
randomPart := rand.Int()
domain := strings.Split(from, "@")[1]
return fmt.Sprintf("<%d.%d@%s>", timestamp, randomPart, domain)
}
func SendMail(from, to, subject, body string) error {
// 1. 解析收件人域名的MX记录
domain := strings.Split(to, "@")[1]
mxRecords, err := net.LookupMX(domain)
if err != nil {
return fmt.Errorf("failed to lookup MX records: %v", err)
}
if len(mxRecords) == 0 {
return fmt.Errorf("no MX records found for domain %s", domain)
}
// 2. 连接到第一个MX记录的25端口
mxHost := mxRecords[0].Host
conn, err := net.Dial("tcp", mxHost+":25")
if err != nil {
return fmt.Errorf("failed to connect to MX host %s: %v", mxHost, err)
}
defer conn.Close()
client, err := smtp.NewClient(conn, mxHost)
if err != nil {
return fmt.Errorf("failed to create SMTP client: %v", err)
}
defer client.Quit()
// 3. 发送 HELO 命令,使用发件人的域名
senderDomain := strings.Split(from, "@")[1]
if err := client.Hello(senderDomain); err != nil {
return fmt.Errorf("failed to say HELO: %v", err)
}
// 4. 发送 STARTTLS 命令
if ok, _ := client.Extension("STARTTLS"); !ok {
return fmt.Errorf("STARTTLS not supported by %s", mxHost)
}
config := &tls.Config{ServerName: mxHost, InsecureSkipVerify: true}
if err := client.StartTLS(config); err != nil {
return fmt.Errorf("failed to start TLS: %v", err)
}
// 5. 设置发件人和收件人
if err := client.Mail(from); err != nil {
return fmt.Errorf("failed to set sender: %v", err)
}
if err := client.Rcpt(to); err != nil {
return fmt.Errorf("failed to set recipient: %v", err)
}
// 6. 编写邮件内容,添加Message-ID头
wc, err := client.Data()
if err != nil {
return fmt.Errorf("failed to get write closer: %v", err)
}
msgID := generateMessageID(from)
msg := fmt.Sprintf("Message-ID: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s", msgID, from, to, subject, body)
_, err = wc.Write([]byte(msg))
if err != nil {
return fmt.Errorf("failed to write message: %v", err)
}
if err := wc.Close(); err != nil {
return fmt.Errorf("failed to close write closer: %v", err)
}
return nil
}
本文来自博客园,作者:项希盛,转载请注明原文链接:https://www.cnblogs.com/xiangxisheng/p/18517267