func TestEmailHeaders(t *testing.T) { var ( from = "*****@*****.**" to = "*****@*****.**" bcc = "*****@*****.**" subject = "Test" ) _, body, err := emailToMessages(&Email{ From: from, To: []string{to}, Bcc: []string{bcc}, Subject: subject, }) if err != nil { t.Fatal(err) } r := bytes.NewBuffer(body) m, err := mail.ReadMessage(r) if err != nil { t.Fatal(err) } if v := m.Header.Get("From"); v != from { t.Fatalf("%s != %s", v, from) } if v := m.Header.Get("To"); v != to { t.Fatalf("%s != %s", v, to) } if v := m.Header.Get("Bcc"); v != "" { t.Fatalf("%s != \"\"", v) } if v := m.Header.Get("Subject"); v != subject { t.Fatalf("%s != %s", v, subject) } }
func testInlineAgainstStdLib(t *testing.T, msg *Message, rawBytes []byte) { // confirm stdlib can parse it too stdlibMsg, err := mail.ReadMessage(bytes.NewReader(rawBytes)) if err != nil { t.Fatal("Standard Library could not parse message:", err) } // confirm stdlib headers match our headers // StandardLibrary is not decoding Q-encoded headers. TODO: Re-enable when GoLang does this. //if !reflect.DeepEqual(map[string][]string(msg.Header), map[string][]string(stdlibMsg.Header)) { // t.Fatal("Message does not match its parsed counterpart") //} // confirm subsequent parts match mixedReader := multipart.NewReader(stdlibMsg.Body, boundary(map[string][]string(stdlibMsg.Header))) alternativePart, err := mixedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } // test the multipart/alternative testMultipartInlineWithStdLib(t, msg.Parts[0], alternativePart) // test attachments attachmentPart, err := mixedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } testBodyPartWithStdLib(t, msg.Parts[1], attachmentPart) // confirm EOF if _, err = mixedReader.NextPart(); err != io.EOF { t.Fatal("Should be EOF", err) } }
func prepTemplate(parent *template.Template, fn, base string) error { t := parent.New(base) f, err := os.Open(fn) if err != nil { return err } defer f.Close() msg, err := mail.ReadMessage(f) if err != nil { return err } for k, v := range defaultHeaders { if msg.Header.Get(k) == "" { msg.Header[k] = v } } data := &bytes.Buffer{} // This is the only place I could find this method. :/ http.Header(msg.Header).Write(data) data.Write([]byte{'\r', '\n'}) _, err = io.Copy(data, msg.Body) if err != nil { return err } _, err = t.Parse(data.String()) return err }
// Get parses the email and returns all relevant data func Get(con *data.Context, m io.Reader) (*Email, error) { msg, err := mail.ReadMessage(m) if err != nil { return nil, fmt.Errorf("Error at mail.ReadMessage while parsing the email. Error: %v", err) } con.Log.Debugf("header: %v", msg.Header) // get body email, err := extract(con, msg.Header, msg.Body) if err != nil { return nil, fmt.Errorf("Error at extracting email. Error: %v", err) } //con.Log.Debugf("Received mail: %v", email) namespaces, err := getNamespaces(msg) if err != nil { return nil, fmt.Errorf("Error at parsing the receiver fields. Error: %v", err) } con.Log.Debugf("Detected namespaces: %v", namespaces) email.Namespaces = namespaces email.Subject, err = getSubject(msg) if err != nil { con.Log.Errorf("Could not decode subject. Error: %v", err) email.Subject = "" } return email, nil }
func FetchMessages(c *imap.Client, uidSet *imap.SeqSet) (fetched []MsgData, err error) { cmd, errF := c.UIDFetch(uidSet, "RFC822") if errF != nil { err = errF return } for cmd.InProgress() { errC := c.Recv(-1) if errC != nil { return } for _, rsp := range cmd.Data { uid := imap.AsNumber(rsp.MessageInfo().Attrs["UID"]) mime := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822"]) msg, errR := mail.ReadMessage(bytes.NewReader(mime)) if errR != nil { continue } if msg != nil { msgdata := GetMessage(msg, uid) fetched = append(fetched, msgdata) } } cmd.Data = nil } return }
// ReceiveMail will receive an e-mail and echo it back to the sender. func ReceiveMail(w http.ResponseWriter, r *http.Request) { ctx := appengine.NewContext(r) m, err := mail.ReadMessage(r.Body) if err != nil { log.Errorf(ctx, "Failed reading a mail!") http.Error(w, err.Error(), http.StatusInternalServerError) return } err = echoMailFunc.Call(ctx, m) if err != nil { log.Errorf(ctx, "Failed enqueing handler for a mail!") http.Error(w, err.Error(), http.StatusInternalServerError) return } io.WriteString(w, "OK") // TODO(flowlo): // 1. Check whether range m.Header.AddressList("From") // fits a registered customer // 2. Filter mail content for further e-mail addresses // 3. Create a Fingerprint // 4. Mail the Fingerprint URL to the other address }
func main() { rawMessage := `From: Feather <*****@*****.**> To: [email protected], [email protected] Subject: =?utf-8?B?5rWL6K+V5Y+R6YCB?= Date: Fri, 21 May 2010 08:54:49 +0800 Message-ID: <*****@*****.**> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: plain Hello Golang Mail` buf := bytes.NewBuffer([]byte(rawMessage)) // parse mail message, buf may from net or somewhere. msg, err := mail.ReadMessage(buf) if err != nil { panic(err) } // mail body body, _ := ioutil.ReadAll(msg.Body) fmt.Printf("Mail Body:\n%s\n", body) fmt.Println("To Addresses:") printAddrs(msg, "to") fmt.Println("From Address:") printAddrs(msg, "From") // auto convert to golang time.Time date, _ := msg.Header.Date() fmt.Println("Date:", date) // mime header will ignore case fmt.Println("mime version:", msg.Header.Get("mime-version")) }
func SaveMail(newmail chan *ServerMessage) { for { message := <-newmail parsedMessage, err := mail.ReadMessage(strings.NewReader(message.Body.String())) fmt.Println(parsedMessage, err) } }
func main() { file, _ := os.Open("/Users/rbd/Temp/7ccaa5be-acf7-45c7-a289-c6bd2cb0492a.eml") msg, _ := mail.ReadMessage(file) // Read email using Go's net/mail mime, _ := enmime.ParseMIMEBody(msg) // Parse message body with enmime // Headers are in the net/mail Message fmt.Printf("From: %v\n", msg.Header.Get("From")) fmt.Printf("From: %v\n", mime.GetHeader("From")) // enmime can decode quoted-printable headers fmt.Printf("Subject: %v\n", mime.GetHeader("Subject")) // The plain text body is available as mime.Text fmt.Printf("Text Body: %v chars\n", len(mime.Text)) fmt.Printf("Text Body: %s\n", mime.Text) // The HTML body is stored in mime.Html fmt.Printf("HTML Body: %v chars\n", len(mime.Html)) // mime.Inlines is a slice of inlined attacments fmt.Printf("Inlines: %v\n", len(mime.Inlines)) // mime.Attachments contains the non-inline attachments fmt.Printf("Attachments: %v\n", len(mime.Attachments)) }
func UnpackMessage(eml string, errors chan error, wg *sync.WaitGroup) { if wg != nil { defer wg.Done() } f, err := os.Open(eml) if err != nil { errors <- MessageError( fmt.Sprintf( "Problem opening the %q message file for unpacking: %s", eml, err.Error())) return } defer f.Close() msg, err := mail.ReadMessage(f) if err != nil { errors <- MessageError( fmt.Sprintf( "Problem opening the %q message file for unpacking: %s", eml, err.Error())) return } partsIterate(msg.Header, msg.Body, cutExt(eml), errors) }
func HandleMail(client_data string, client_rcpt_to string, gConfig map[string]string) { var to = client_rcpt_to[1 : len(client_rcpt_to)-1] addresses := strings.Split(to, ",") for _, address := range addresses { emailData := client_data[:len(client_data)-4] msg, err := mail.ReadMessage(bytes.NewBuffer([]byte(emailData))) if err != nil { sendErrorReport(err, emailData, address, gConfig) return } headers := make(map[string]string) for key, value := range msg.Header { headers[key] = value[0] } body, _ := ioutil.ReadAll(msg.Body) encryptedBody := encrypt(string(body), address, gConfig) sendEmail(headers, encryptedBody, address, gConfig) } }
func main() { flag.Parse() if filename == nil || strings.TrimSpace(*filename) == "" { log.Fatal("--file is required") } fh, err := os.Open(*filename) if err != nil { log.Fatal(err) } msg, err := mail.ReadMessage(fh) if err != nil { log.Fatal(err) } m, err := mime.ParseMIMEBody(msg) if err != nil { log.Fatal(err) } fmt.Fprintf(os.Stderr, "HTML=%d Text=%d\n", len(m.HTML), len(m.Text)) if len(m.HTML) <= 0 { log.Fatalf("No HTML part found in %s\n", *filename) } w := bufio.NewWriter(os.Stdout) n, err := w.WriteString(m.HTML) if err != nil { log.Fatal(err) } fmt.Fprintf(os.Stderr, "Wrote %d bytes to standard output\n", n) w.Flush() }
func fetchAllHeaders(user, authToken, box string) ([]mail.Header, error) { c, err := imap.DialTLS("imap.gmail.com:993", nil) if err != nil { return nil, err } _, err = c.Auth(oauthSASL{user, authToken}) if err != nil { return nil, err } c.Select(box, true) set, _ := imap.NewSeqSet("1:*") cmd, err := imap.Wait(c.Fetch(set, "BODY.PEEK[HEADER.FIELDS (DATE)]")) if err != nil { return nil, err } headers := make([]mail.Header, 0, len(cmd.Data)) parseFailures := 0 for _, rsp := range cmd.Data { header := imap.AsBytes(rsp.MessageInfo().Attrs["BODY[HEADER.FIELDS (DATE)]"]) // no peek if msg, _ := mail.ReadMessage(bytes.NewReader(header)); msg != nil { headers = append(headers, msg.Header) } else { parseFailures++ } } log.Printf("Finished processing %d emails with %d parse failures.\n", len(headers), parseFailures) return headers, nil }
func LoadMessage(path string) (*Message, error) { m := &Message{path: path} f, err := os.Open(path) if err != nil { return nil, err } fi, err := os.Stat(path) if err != nil { return nil, err } defer f.Close() msg, err := mail.ReadMessage(f) if err != nil { return nil, err } m.From = mimedec(msg.Header.Get("From")) m.ReplyTo = mimedec(msg.Header.Get("reply-to")) m.CCs = mimedec(msg.Header.Get("cc")) m.To = mimedec(msg.Header.Get("To")) m.Subject = mimedec(msg.Header.Get("Subject")) m.Date, _ = msg.Header.Date() m.size = fi.Size() i := strings.LastIndex(path, ":2,") if i != -1 { m.Flags = parseFlags(path[i+3:]) } return m, nil }
func TestMessage(t *testing.T) { msg := &Message{} msg.SetFrom("Marc Weistroff", "*****@*****.**") msg.AddTo("Marc Weistroff", "*****@*****.**") msg.AddTo("Foo Bar", "*****@*****.**") msg.AddCc("Bar Foo", "*****@*****.**") msg.AddBcc("The Boss", "*****@*****.**") msg.Subject = "Lorem ipsum gollum" msg.Body = `Oy Mate! Wanna drink a beer tonight? Cheers` proof, _ := mail.ReadMessage(bytes.NewBuffer(msg.Bytes())) body, _ := ioutil.ReadAll(proof.Body) if string(body) != msg.Body { t.Log(string(body)) t.FailNow() } from, _ := proof.Header.AddressList("From") if from[0].Name != "Marc Weistroff" || from[0].Address != "*****@*****.**" { t.Log(from[0]) t.FailNow() } to, _ := proof.Header.AddressList("To") if len(to) != 2 { proof.Header.Get("To") t.Log(to) t.FailNow() } if to[0].Name != "Marc Weistroff" || to[0].Address != "*****@*****.**" { t.Log(to[0]) t.FailNow() } if to[1].Name != "Foo Bar" || to[1].Address != "*****@*****.**" { t.Log(to[1]) t.FailNow() } cc, _ := proof.Header.AddressList("Cc") if cc[0].Name != "Bar Foo" || cc[0].Address != "*****@*****.**" { t.Log(cc[0]) t.FailNow() } bcc, _ := proof.Header.AddressList("Bcc") if bcc[0].Name != "The Boss" || bcc[0].Address != "*****@*****.**" { t.Log(bcc[0]) t.FailNow() } subject := proof.Header.Get("Subject") if subject != msg.Subject { t.Log(subject) t.FailNow() } }
// Top will return a varible number of lines for a given message as a // mail.Message object. func (c *Client) Top(msg int, n int) (m *mail.Message, err error) { if _, err = c.Cmd("%s %d %d\r\n", TOP, msg, n); err != nil { return } m, err = mail.ReadMessage(c.r) if err != nil { return } // mail.ReadMessage does not consume the message end dot in the buffer // so we must move the buffer along. Need to find a better way of // doing this. line, err := c.ReadLine() if err != nil { return } if line != "." { if err = c.r.UnreadByte(); err != nil { return } } return }
func stringToMessage(mimestring string) *mail.Message { msg, err := mail.ReadMessage(strings.NewReader(mimestring)) if err != nil { panic("err") } return msg }
// looks into the specified detectiondir to find and parse all mails in that dir func parse_mails(c map[string]string) []email { // get entries of directory files, _ := ioutil.ReadDir(c["Detectiondir"]) // allocate space to store the parsed mails mails := make([]email, 0, len(files)) // loop over all non-dir-files and try to parse mails // return a slice of those files that are parsable as mail for _, f := range files { if !f.IsDir() { // try parsing content, _ := ioutil.ReadFile(c["Detectiondir"] + "/" + f.Name()) mail, err := mail.ReadMessage(bytes.NewReader(content)) // save if parsable if err == nil { mails = append(mails, email{f.Name(), mail}) } } } return mails }
// ReceiveMail will receive an e-mail and echo it back to the sender. func ReceiveMail(ctx context.Context, w http.ResponseWriter, r *http.Request) (int, error) { m, err := mail.ReadMessage(r.Body) if err != nil { log.Errorf(ctx, "Failed reading a mail!") return http.StatusInternalServerError, err } err = echoMailFunc.Call(ctx, m) if err != nil { log.Errorf(ctx, "Failed enqueing handler for a mail!") return http.StatusInternalServerError, err } if _, err = io.WriteString(w, "OK"); err != nil { return http.StatusInternalServerError, err } return http.StatusOK, nil // TODO(flowlo): // 1. Check whether range m.Header.AddressList("From") // fits a registered customer // 2. Filter mail content for further e-mail addresses // 3. Create a Fingerprint // 4. Mail the Fingerprint URL to the other address }
func WalkParts(r io.Reader, parse ParseFn, pc *ParserContext, maxDepth int) error { msg, err := mail.ReadMessage(r) if err != nil { return err } return partWalker(msg.Body, []int{}, msg.Header, parse, pc, maxDepth) }
func main() { if len(os.Args) != 2 { log.Fatalln("pass mail file path") } r, err := os.Open(os.Args[1]) if err != nil { log.Fatalln(err) } defer r.Close() msg, err := mail.ReadMessage(r) if err != nil { log.Fatalln(err) } for k, _ := range msg.Header { log.Printf("%s: %s\n", k, msg.Header.Get(k)) } d, err := msg.Header.Date() if err != nil { log.Fatalln(err) } log.Println(d) log.Println(msg.Header.Get("subject")) }
func Example() { file, _ := os.Open("test-data/mail/qp-utf8-header.raw") msg, _ := mail.ReadMessage(file) // Read email using Go's net/mail mime, _ := enmime.ParseMIMEBody(msg) // Parse message body with enmime // Headers are in the net/mail Message fmt.Printf("From: %v\n", msg.Header.Get("From")) // enmime can decode quoted-printable headers fmt.Printf("Subject: %v\n", mime.GetHeader("Subject")) // The plain text body is available as mime.Text fmt.Printf("Text Body: %v chars\n", len(mime.Text)) // The HTML body is stored in mime.Html fmt.Printf("HTML Body: %v chars\n", len(mime.Html)) // mime.Inlines is a slice of inlined attacments fmt.Printf("Inlines: %v\n", len(mime.Inlines)) // mime.Attachments contains the non-inline attachments fmt.Printf("Attachments: %v\n", len(mime.Attachments)) // Output: // From: James Hillyerd <*****@*****.**> // Subject: MIME UTF8 Test ¢ More Text // Text Body: 1300 chars // HTML Body: 1736 chars // Inlines: 0 // Attachments: 0 }
func (m *Message) parse(r io.Reader) error { msg, err := mail.ReadMessage(r) if err != nil { return err } m.Subject = msg.Header.Get("Subject") m.To = msg.Header.Get("To") mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type")) if err != nil || !strings.HasPrefix(mediaType, "multipart/") { slurp, _ := ioutil.ReadAll(msg.Body) m.Body = string(slurp) return nil } if err := m.parseMultipart(msg.Body, params["boundary"]); err != nil { return err } // If we didn't find a text/plain body, pick the first body we did find. if m.Body == "" { for _, body := range m.bodies { if body != "" { m.Body = body break } } } return nil }
func ExampleReadMessage() { msg := `Date: Mon, 23 Jun 2015 11:40:36 -0400 From: Gopher <*****@*****.**> To: Another Gopher <*****@*****.**> Subject: Gophers at Gophercon Message body ` r := strings.NewReader(msg) m, err := mail.ReadMessage(r) if err != nil { log.Fatal(err) } header := m.Header fmt.Println("Date:", header.Get("Date")) fmt.Println("From:", header.Get("From")) fmt.Println("To:", header.Get("To")) fmt.Println("Subject:", header.Get("Subject")) body, err := ioutil.ReadAll(m.Body) if err != nil { log.Fatal(err) } fmt.Printf("%s", body) // Output: // Date: Mon, 23 Jun 2015 11:40:36 -0400 // From: Gopher <*****@*****.**> // To: Another Gopher <*****@*****.**> // Subject: Gophers at Gophercon // Message body }
func makeMailHandler(mandrillAPI *gochimp.MandrillAPI, sendLimiter *rerate.Limiter, spamLimiter *rerate.Limiter) func(smtpd.Peer, smtpd.Envelope) error { return func(peer smtpd.Peer, env smtpd.Envelope) error { // Validate data before sending them if _, err := mail.ReadMessage(bytes.NewReader(env.Data)); err != nil { return err } response, err := mandrillAPI.MessageSendRaw(string(env.Data), env.Recipients, gochimp.Recipient{Email: env.Sender}, false) if err != nil { log.WithFields(log.Fields{ "peer": peer, "error": err, }).Info("Error sending message") return smtpd.Error{Code: 451, Message: "Error with Remote API"} } if response[0].Status == "rejected" && response[0].RejectedReason == "spam" { log.WithFields(log.Fields{ "peer": peer, "RejectedReason": response[0].RejectedReason, }).Info("Message filtered as SPAM") if err := spamLimiter.Inc(peer.HeloName); err != nil { log.WithFields(log.Fields{ "heloName": peer.HeloName, "error": err, }).Warn("Can't increment send") } return smtpd.Error{Code: 451, Message: "Spam filtered, increment rate limit"} } return nil } }
func TestTextEmail(t *testing.T) { m := NewMailer("", "username", "password", "host", "587") for _, info := range tests { msg := m.NewMessage(info.messageValues[0], info.messageValues[1], info.messageValues[2], info.messageValues[3], info.messageValues[4]) // verifying length since date & boundary values will mess up the direct byte comparison if len(info.messageContent) != len(msg.Bytes()) { t.Error("Expected content length to match: \n" + string(msg.Bytes()) + "\n == \n" + string(info.messageContent)) } if msg.IsText != info.isText || msg.IsHtml != info.isHtml { t.Error("Email should match text/html content expectations.") } // verify parts of the message explicitly check, _ := mail.ReadMessage(bytes.NewBuffer(msg.Bytes())) from, _ := check.Header.AddressList("From") if len(from) > 0 { if from[0].Name != info.messageValues[1] || from[0].Address != info.messageValues[1] { t.Error("From address to be: " + info.messageValues[1] + " got: " + from[0].Address) } } subject := check.Header.Get("Subject") if len(from) > 0 { if subject != info.messageValues[2] { t.Error("From address to be: " + info.messageValues[2] + " got: " + subject) } } } }
func testBasicAgainstStdLib(t *testing.T, msg *Message, rawBytes []byte) { // confirm stdlib can parse it too stdlibMsg, err := mail.ReadMessage(bytes.NewReader(rawBytes)) if err != nil { t.Fatal("Standard Library could not parse message:", err) } // confirm stdlib headers match our headers if !reflect.DeepEqual(map[string][]string(msg.Header), map[string][]string(stdlibMsg.Header)) { t.Fatal("Message does not match its parsed counterpart") } // confirm subsequent parts match mixedReader := multipart.NewReader(stdlibMsg.Body, boundary(map[string][]string(stdlibMsg.Header))) alternativePart, err := mixedReader.NextPart() if err != nil { t.Fatal("Couldn't get next part", err) } // test the multipart/alternative testMultipartAlternativeWithStdLib(t, msg.Parts[0], alternativePart) // confirm EOF if _, err = mixedReader.NextPart(); err != io.EOF { t.Fatal("Should be EOF", err) } }
func readMail() (*mail.Message, error) { var buffer *bytes.Buffer buffer = bytes.NewBuffer(nil) io.Copy(buffer, os.Stdin) return mail.ReadMessage(buffer) }
func getAddresses(fn string, results chan<- *Contact) { file, err := os.Open(fn) if err != nil { log.Fatalf("Failed to open %q: %s\n", fn, err) } msg, err := mail.ReadMessage(file) if err != nil { log.Printf("Failed to parse message %q: %s\n", fn, err) return } headers := []string{"to", "cc"} for _, header := range headers { addrs, err := msg.Header.AddressList(header) if err != nil { //log.Printf("Failed to parse %s: header in %q: %s", header, fn, err) continue } for _, addr := range addrs { c := &Contact{*addr, fn} results <- c } } }
// parseMail reads a mailfile's content and parses it into a mail-struct if one of ours. func parseMail(path string) (email, error) { // to date the mails found t := time.Now() // try parsing f, err := os.Open(path) if err != nil { return email{}, err } defer fileClose(f) mail, err := mail.ReadMessage(io.LimitReader(f, 8192)) if err != nil { return email{}, err } payl, err := ioutil.ReadAll(mail.Body) if err != nil { return email{}, err } payloadbytes := bytes.TrimSpace(payl) // mostly for trailing "\n" p, err := decomposePayload(payloadbytes) // return if parsable // (non-parsable mails are not sent by us (or broken) and therefore not needed if err != nil { return email{}, errNotOurDept } return email{path, p.configname, p.token, time.Unix(0, p.timestamp), t}, nil }