func fetch(c *imap.Client, user string, thread Thread) ([]*ParsedMail, error) { var set imap.SeqSet for _, uid := range thread { set.AddNum(uid) } cmd, err := imap.Wait(c.UIDFetch(&set, "BODY[]", "X-GM-MSGID", "X-GM-THRID")) if err != nil { return nil, ErrBadConnection } parsed := make([]*ParsedMail, len(cmd.Data)) for i, rsp := range cmd.Data { p, err := parseMail(imap.AsBytes(rsp.MessageInfo().Attrs["BODY[]"]), user) if err != nil { return nil, err } link, err := gmailLink(imap.AsString(rsp.MessageInfo().Attrs["X-GM-MSGID"])) if err != nil { return nil, err } p.GmailLink = link p.Thrid = imap.AsString(rsp.MessageInfo().Attrs["X-GM-THRID"]) parsed[i] = p } return parsed, nil }
func getEmails(client *imap.Client, cmd *imap.Command, markAsRead, delete bool, responses chan Response) { seq := &imap.SeqSet{} msgCount := 0 for _, rsp := range cmd.Data { for _, uid := range rsp.SearchResults() { msgCount++ seq.AddNum(uid) } } // nothing to request?! why you even callin me, foolio? if seq.Empty() { return } fCmd, err := imap.Wait(client.UIDFetch(seq, "INTERNALDATE", "BODY[]", "UID", "RFC822.HEADER")) if err != nil { responses <- Response{Err: fmt.Errorf("unable to perform uid fetch: %s", err)} return } var email Email for _, msgData := range fCmd.Data { msgFields := msgData.MessageInfo().Attrs // make sure is a legit response before we attempt to parse it // deal with unsolicited FETCH responses containing only flags // I'm lookin' at YOU, Gmail! // http://mailman13.u.washington.edu/pipermail/imap-protocol/2014-October/002355.html // http://stackoverflow.com/questions/26262472/gmail-imap-is-sometimes-returning-bad-results-for-fetch if _, ok := msgFields["RFC822.HEADER"]; !ok { continue } email, err = newEmail(msgFields) if err != nil { responses <- Response{Err: fmt.Errorf("unable to parse email: %s", err)} return } responses <- Response{Email: email} if !markAsRead { err = removeSeen(client, imap.AsNumber(msgFields["UID"])) if err != nil { responses <- Response{Err: fmt.Errorf("unable to remove seen flag: %s", err)} return } } if delete { err = deleteEmail(client, imap.AsNumber(msgFields["UID"])) if err != nil { responses <- Response{Err: fmt.Errorf("unable to delete email: %s", err)} return } } } return }
// getEmails will fetch the full bodies of all emails listed in the given command. func getEmails(client *imap.Client, cmd *imap.Command) ([]map[string]interface{}, error) { var emails []map[string]interface{} seq := new(imap.SeqSet) for _, rsp := range cmd.Data { for _, uid := range rsp.SearchResults() { seq.AddNum(uid) } } if seq.Empty() { return emails, nil } fCmd, err := imap.Wait(client.UIDFetch(seq, "INTERNALDATE", "BODY[]", "UID", "RFC822.HEADER")) if err != nil { return emails, err } var email map[string]interface{} for _, msgData := range fCmd.Data { msgFields := msgData.MessageInfo().Attrs email, err = newEmailMessage(msgFields) if err != nil { return emails, err } emails = append(emails, email) // mark message as read fSeq := new(imap.SeqSet) fSeq.AddNum(imap.AsNumber(msgFields["UID"])) _, err = imap.Wait(client.UIDStore(fSeq, "+FLAGS", "\\SEEN")) if err != nil { return emails, err } } return emails, nil }
// loadMessages will search and fetch message body func loadMessages(client *imap.Client, config *Config) error { cmd, err := imap.Wait(client.UIDSearch("FROM", client.Quote(config.From), "UNSEEN")) if err != nil { return err } seq := new(imap.SeqSet) if len(cmd.Data) > 0 { seq.AddNum(cmd.Data[0].SearchResults()...) } if seq.Empty() { return nil } logger.Infof("Fetched UIDs %v", seq) cmd, err = imap.Wait(client.UIDFetch(seq, "FLAGS", "INTERNALDATE", "RFC822.SIZE", "BODY[]")) if err != nil { return err } for _, rsp := range cmd.Data { body, err := fetchMessage(client, rsp.MessageInfo().UID) if err != nil { logger.Fatal(err) return err } err = writeFileFromBody(bytes.NewReader(body), config) if err != nil { logger.Fatal(err) return err } } if !seq.Empty() { _, err = imap.Wait(client.UIDStore(seq, "+FLAGS.SILENT", imap.NewFlagSet(`\Seen`))) } cmd.Data = nil return err }
// fetchMessage send UID FETCH command to retrieve message body func fetchMessage(client *imap.Client, messageUID uint32) ([]byte, error) { seq := new(imap.SeqSet) seq.AddNum(messageUID) cmd, err := imap.Wait(client.UIDFetch(seq, "INTERNALDATE", "BODY[]", "UID", "RFC822.HEADER")) if err != nil { logger.Errorf("Unable to fetch message (%d): %s", messageUID, err.Error()) return nil, nil } if len(cmd.Data) == 0 { logger.WithField("uid", messageUID).Info("Unable to fetch message from src: NO DATA") return nil, errors.New("message not found") } msgFields := cmd.Data[0].MessageInfo().Attrs body := imap.AsBytes(msgFields["BODY[]"]) cmd.Data = nil return body, nil }