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
}
Exemple #2
0
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
}
Exemple #3
0
// 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
}
Exemple #4
0
// 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
}
Exemple #5
0
// 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
}