From c577274d3ae191639912b28bd2d70eeb2298b32f Mon Sep 17 00:00:00 2001 From: root Date: Mon, 30 Oct 2023 17:36:00 +0800 Subject: [PATCH] Initial commit --- .gitignore | 1 + config.json | 5 ++ go.mod | 5 ++ go.sum | 2 + mian.go | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 185 insertions(+) create mode 100644 .gitignore create mode 100644 config.json create mode 100644 go.mod create mode 100644 go.sum create mode 100644 mian.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..99d4d89 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/temp-mail-receiver \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..c2a972c --- /dev/null +++ b/config.json @@ -0,0 +1,5 @@ +{ + "addr": ":25", + "api_url": "", + "api_key": "superfuck" +} \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..76d4422 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module gitlab.ni-co.moe/shira/temp-mail-receiver + +go 1.20 + +require github.com/mhale/smtpd v0.8.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..768d7b7 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/mhale/smtpd v0.8.0 h1:5JvdsehCg33PQrZBvFyDMMUDQmvbzVpZgKob7eYBJc0= +github.com/mhale/smtpd v0.8.0/go.mod h1:MQl+y2hwIEQCXtNhe5+55n0GZOjSmeqORDIXbqUL3x4= diff --git a/mian.go b/mian.go new file mode 100644 index 0000000..0de5d12 --- /dev/null +++ b/mian.go @@ -0,0 +1,172 @@ +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", "") +}