最近有一个 场景是基于某封邮件进行回复,这样可以在收件箱内形成一个完整的邮件链,比如进行倒计时的提醒,自动邮件回复等情况还挺实用的,日常对邮件的处理主要还是发邮件进行告警等,使用imap进行回复的场景还是挺少见的,所以简单记录一下。
package main
import (
"fmt"
"gopkg.in/mail.v2"
"time"
)
func main() {
currentTime := time.Now()
format := "2006-01-02"
nowTimeFormat := currentTime.Format(format)
deadLineFormat := currentTime.AddDate(0, 1, 0).Format(format)
timeDifference := currentTime.AddDate(0, 1, 0).Sub(currentTime)
daysDifference := int(timeDifference.Hours() / 24)
title := fmt.Sprintf("[重要] 资产确认倒计时: %v", nowTimeFormat)
sender := mail.NewMessage()
sender.SetHeader("From", "xxx@mail.com")
sender.SetHeader("To", "yyy@mail.com","zzz@mail.com")
sender.SetHeader("Subject", title)
htmlBody := fmt.Sprintf(`
<head>
<style>
table {
border-collapse: collapse;
border-spacing: 0;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
</style>
</head>
<p>各位领导:</p>
<p>请确认以下资源的是否还在使用。</p>
<p><b>截止时间: %v</b></p>
<p><b>剩余时间: %v</b></p>
<p><b>资源确认链接: https://xxxx/resource/list</b></p>
<p><b>业务产品线: 售后</b></p>
<table>
<thead>
<tr>
<th>资源类型</th>
<th>已确认</th>
<th>待确认</th>
</tr>
</thead>
<tbody>
<tr>
<td>ECS</td>
<td>OSS</td>
<td>RDS</td>
</tr>
<tr>
<td>100</td>
<td>120</td>
<td>80</td>
</tr>
<tr>
<td>30</td>
<td>20</td>
<td>10</td>
</tr>
</tbody>
</table>
<p>烦请尽快确认资源归属</p>
<p>感谢您的支持</p>
`, deadLineFormat, daysDifference)
sender.SetBody("text/html", htmlBody)
// 邮件服务器的设置
d := mail.NewDialer("smtp.xxx.cn", 587, "xxx@mail.com", "passwd")
// 发送邮件
if err := d.DialAndSend(sender); err != nil {
panic(err)
}
}
package main
import (
"fmt"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/client"
"github.com/emersion/go-message/mail"
mailv2 "gopkg.in/mail.v2"
"regexp"
"time"
)
func searchMessagesFrom(c *client.Client, mailbox, from string) ([]uint32, error) {
// 构造 SEARCH 命令
cmd := &imap.SearchCriteria{}
// 执行 SEARCH 命令
ids, err := c.Search(cmd)
if err != nil {
return nil, err
}
fmt.Println(ids)
return ids, nil
}
func decodeMIMEHeader(encoded string) (string, error) {
// 使用 mime.WordDecoder 解码
decoder := new(mime.WordDecoder)
decoded, err := decoder.DecodeHeader(encoded)
if err != nil {
return "", err
}
return decoded, nil
}
func main() {
// 连接imap服务器
c, err := client.DialTLS("imap.xxx.cn:993", nil)
if err != nil {
panic(err)
}
defer c.Logout()
// 登陆认证
if err := c.Login("xxx@mail.com", "passwd"); err != nil {
panic(err)
}
// 列出所有收件箱
mailboxes := make(chan *imap.MailboxInfo, 10)
done := make(chan error, 1)
go func() {
done <- c.List("", "*", mailboxes)
}()
for m := range mailboxes {
fmt.Println("* " + m.Name)
}
if err := <-done; err != nil {
fmt.Println(err)
}
// 选择发件箱
mbox, err := c.Select("已发送", false)
if err != nil {
fmt.Println(err)
}
// 获得最新的一封邮件
from := uint32(1)
to := mbox.Messages
if mbox.Messages > 0 {
from = mbox.Messages - 0
}
seqset := new(imap.SeqSet)
seqset.AddRange(from, to)
messages := make(chan *imap.Message, 1)
go func() {
if err := c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope, imap.FetchRFC822, imap.FetchFlags, imap.FetchUid}, messages); err != nil {
fmt.Println(err)
}
}()
for msg := range messages {
// 解析邮件头
r := msg.GetBody(&imap.BodySectionName{})
if r == nil {
fmt.Println("Email body is empty.")
continue
}
mr, err := mail.CreateReader(r)
if err != nil {
fmt.Println(err)
}
header := mr.Header
// 打印邮件主题和发件人
// 解码 Subject
decodedSubject, err := decodeMIMEHeader(msg.Envelope.Subject)
if err != nil {
fmt.Println(err)
}
keyWord := "aass"
re := regexp.MustCompile(`\[.*` + keyWord + `.*\]`)
match := re.FindStringSubmatch(decodedSubject)
if len(match) != 0 {
fmt.Println("匹配到keyword邮件")
// 使用net/smtp库发送邮件
currentTime := time.Now()
format := "2006-01-02"
nowTimeFormat := currentTime.Format(format)
deadLineFormat := currentTime.AddDate(0, 1, 0).Format(format)
timeDifference := currentTime.AddDate(0, 1, 0).Sub(currentTime)
daysDifference := int(timeDifference.Hours() / 24)
sender := mailv2.NewMessage()
sender.SetHeader("From", header.Get("From"))
sender.SetHeader("To", header.Get("To"))
replyTitle := fmt.Sprintf("[重要] 资产确认[%v] %v", keyWord, nowTimeFormat)
sender.SetHeader("Subject", replyTitle)
// 设置 In-Reply-To 和 References 头字段
sender.SetHeader("In-Reply-To", header.Get("Message-ID"))
sender.SetHeader("References", header.Get("Message-ID"))
htmlBody := fmt.Sprintf(`
<head>
<style>
table {
border-collapse: collapse;
border-spacing: 0;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: left;
}
</style>
</head>
<p>各位领导:</p>
<p>请确认以下资源的是否还在使用。</p>
<p><b>截止时间: %v</b></p>
<p><b>剩余时间: %v</b></p>
<p><b>资源确认链接: https://xxxx/resource/list</b></p>
<p><b>业务产品线: 售后</b></p>
<table>
<thead>
<tr>
<th>资源类型</th>
<th>已确认</th>
<th>待确认</th>
</tr>
</thead>
<tbody>
<tr>
<td>ECS</td>
<td>OSS</td>
<td>RDS</td>
</tr>
<tr>
<td>100</td>
<td>120</td>
<td>80</td>
</tr>
<tr>
<td>30</td>
<td>20</td>
<td>10</td>
</tr>
</tbody>
</table>
<p>烦请尽快确认资源归属</p>
<p>感谢您的支持</p>
`, deadLineFormat, daysDifference)
sender.SetBody("text/html", htmlBody)
d := mailv2.NewDialer("smtp.xx.cn", 587, "xxx@mail.com", "password")
// 发送邮件
if err := d.DialAndSend(sender); err != nil {
panic(err)
}
fmt.Println("邮件发送成功!")
}
}
fmt.Println("Done!")
}