TempMailReceiver/mian.go
2023-10-30 17:36:00 +08:00

173 lines
4.1 KiB
Go

package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"mime"
"mime/multipart"
"net"
"net/http"
"net/mail"
"os"
"strings"
"time"
"github.com/mhale/smtpd"
)
type Config struct {
Address string `json:"addr"`
ApiUrl string `json:"api_url"`
ApiKey string `json:"api_key"`
}
type MailContent struct {
Key string `json:"key"`
From string `json:"from"`
To string `json:"to"`
Title string `json:"title"`
Body string `json:"body"`
FromAddr string `json:"from_addr"`
FromProtocol string `json:"from_protocol"`
ReceivedAt string `json:"received_at"`
}
var appConfig Config
func decodeHeader(header string) (string, error) {
decoded, err := (&mime.WordDecoder{}).DecodeHeader(header)
if err != nil {
return "", err
}
return decoded, nil
}
func postMailContent(url string, key string, mailContent *MailContent) error {
// 将邮件内容转换为 JSON
jsonData, err := json.Marshal(mailContent)
if err != nil {
return err
}
// 创建 HTTP 请求
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
// 发送 HTTP 请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
// 读取响应体(如果需要)
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
log.Println("Response Status:", resp.Status)
log.Println("Response Body:", string(body))
return nil
}
func mailHandler(origin net.Addr, from string, to []string, data []byte) error {
reader := bytes.NewReader(data)
msg, _ := mail.ReadMessage(reader)
subject := msg.Header.Get("Subject")
decodedSubject, _ := decodeHeader(subject)
mediaType, params, _ := mime.ParseMediaType(msg.Header.Get("Content-Type"))
body, _ := ioutil.ReadAll(msg.Body)
mailBody := ""
if strings.HasPrefix(mediaType, "text/plain") || strings.HasPrefix(mediaType, "text/html") {
mailBody = string(body)
} else if strings.HasPrefix(mediaType, "multipart/") {
mr := multipart.NewReader(msg.Body, params["boundary"])
for {
part, err := mr.NextPart()
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
partMediaType, _, err := mime.ParseMediaType(part.Header.Get("Content-Type"))
if err != nil {
log.Fatal(err)
}
partBody, err := ioutil.ReadAll(part)
if err != nil {
log.Fatal(err)
}
if strings.HasPrefix(partMediaType, "text/plain") {
mailBody = mailBody + string(partBody)
} else if strings.HasPrefix(partMediaType, "text/html") {
mailBody = mailBody + string(partBody)
}
}
} else {
fmt.Println("Unsupported media type")
}
log.Printf("Received mail from %s for %s with subject %s", from, to[0], decodedSubject)
receivedAt := time.Now() // 例如,使用当前时间作为接收时间
// 创建 MailContent 对象
mailContent := &MailContent{
From: from,
To: to[0],
Title: decodedSubject,
Body: mailBody,
FromAddr: origin.String(),
FromProtocol: origin.Network(),
ReceivedAt: receivedAt.Format(time.RFC3339),
}
// 将邮件内容发送到 API
err := postMailContent(appConfig.ApiUrl, appConfig.ApiKey, mailContent)
if err != nil {
log.Println("Failed to post mail content:", err)
}
return nil
}
func main() {
configPath := flag.String("c", "config.json", "Path to the configuration file")
flag.Parse()
file, err := os.Open(*configPath)
if err != nil {
log.Fatalf("Error opening config file: %v", err)
}
defer file.Close()
configBytes, err := ioutil.ReadAll(file)
if err != nil {
log.Fatalf("Error reading config file: %v", err)
}
if err := json.Unmarshal(configBytes, &appConfig); err != nil {
log.Fatalf("Error parsing config file: %v", err)
}
log.Printf("Starting server at %s", appConfig.Address)
smtpd.ListenAndServe(appConfig.Address, mailHandler, "MyServerApp", "")
}