package main import ( "encoding/json" "fmt" "io" "io/ioutil" "mime" "mime/multipart" "net/mail" "os" "strings" "time" "gitea.inhome.blapointe.com/local-sandbox/contact" "gitea.inhome.blapointe.com/local/args" ) type MultipartReaderReader struct { buff []byte r *multipart.Reader } func (mrr *MultipartReaderReader) Read(b []byte) (int, error) { n := copy(b, mrr.buff) mrr.buff = mrr.buff[n:] for n < len(b) { part, err := mrr.r.NextPart() if err != nil { return n, err } defer part.Close() mrr.buff, err = io.ReadAll(part) if err != nil { return n, err } m := copy(b, mrr.buff) mrr.buff = mrr.buff[m:] n += m } return n, nil } func main() { emailer := contact.NewEmailer() as := args.NewArgSet() as.Append(args.STRING, "imap", "imap server:port", "imap.gmail.com:993") as.Append(args.STRING, "pop3", "pop3 server:port", "") as.Append(args.INT, "n", "limit (<1 for inf)", 10) as.Append(args.STRING, "u", "username", emailer.From) as.Append(args.STRING, "p", "password", emailer.Password) as.Append(args.INT, "b", "dont read more than this many characters", 4096) as.Append(args.BOOL, "json", "output as json", false) if err := as.Parse(); err != nil { panic(err) } emailer.IMAP = as.Get("imap").GetString() emailer.POP3 = as.Get("pop3").GetString() emailer.Limit = as.Get("n").GetInt() emailer.From = as.GetString("u") emailer.Password = as.GetString("p") var msgs <-chan *mail.Message var err error if emailer.POP3 != "" { msgs, err = emailer.ReadPOP3() } else { msgs, err = emailer.Read() } if err != nil { panic(err) } emails := make([]map[string]any, 0, emailer.Limit) for msg := range msgs { var r io.Reader if n := int64(as.GetInt("b")); n >= 0 { r = io.LimitReader(msg.Body, n) } else if mediaType, params, _ := mime.ParseMediaType(msg.Header.Get("Content-Type")); strings.HasPrefix(mediaType, "multipart/") { r = &MultipartReaderReader{ r: multipart.NewReader(msg.Body, params["boundary"]), } } else { r = msg.Body } b, _ := ioutil.ReadAll(r) s := strings.ReplaceAll(string(b), "\r\n", "\n") s = strings.ReplaceAll(string(s), "\n", "\n") s = strings.ReplaceAll(string(s), "\r", "\n") if !strings.Contains(s, " ") { s = "..." } d, _ := msg.Header.Date() d = d.In(time.Local) if as.GetBool("json") { emails = append(emails, map[string]any{ "t": d.Format("06-01-02T15:04Z07"), "from": msg.Header.Get("From"), "subject": msg.Header.Get("Subject"), "body": s, }) } else { fmt.Printf( "@%+v @%+v: \n\t%+v: \n\t%s\n", d.Format("06-01-02T15:04Z07"), msg.Header.Get("From"), msg.Header.Get("Subject"), s, ) } } if as.GetBool("json") { enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") enc.Encode(emails) } }