fetcher.go

  1package fetcher
  2
  3import (
  4	"fmt"
  5	"io"
  6	"log"
  7	"time"
  8
  9	"github.com/andrinoff/email-cli/config"
 10	"github.com/emersion/go-imap"
 11	"github.com/emersion/go-imap/client"
 12	"github.com/emersion/go-message/mail"
 13)
 14
 15type Email struct {
 16	From    string
 17	To      []string
 18	Subject string
 19	Body    string
 20	Date    time.Time
 21}
 22
 23func FetchEmails(cfg *config.Config) ([]Email, error) {
 24	var imapServer string
 25	var imapPort int
 26
 27	// Determine the IMAP server based on the service provider in the config.
 28	switch cfg.ServiceProvider {
 29	case "gmail":
 30		imapServer = "imap.gmail.com"
 31		imapPort = 993
 32	case "icloud":
 33		imapServer = "imap.mail.me.com"
 34		imapPort = 993
 35	default:
 36		return nil, fmt.Errorf("unsupported or missing service_provider in config.json: %s", cfg.ServiceProvider)
 37	}
 38
 39	// Connect to the server
 40	addr := fmt.Sprintf("%s:%d", imapServer, imapPort)
 41	c, err := client.DialTLS(addr, nil)
 42	if err != nil {
 43		return nil, err
 44	}
 45	log.Println("Connected")
 46	defer c.Logout()
 47
 48	// Login
 49	if err := c.Login(cfg.Email, cfg.Password); err != nil {
 50		return nil, err
 51	}
 52	log.Println("Logged in")
 53
 54	// Select INBOX
 55	mbox, err := c.Select("INBOX", false)
 56	if err != nil {
 57		return nil, err
 58	}
 59
 60	// Get the last 10 messages
 61	from := uint32(1)
 62	to := mbox.Messages
 63	if mbox.Messages > 10 {
 64		from = mbox.Messages - 9
 65	}
 66	seqset := new(imap.SeqSet)
 67	seqset.AddRange(from, to)
 68
 69	messages := make(chan *imap.Message, 10)
 70	done := make(chan error, 1)
 71	go func() {
 72		done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchItem("BODY[]")}, messages)
 73	}()
 74
 75	var emails []Email
 76	for msg := range messages {
 77		r := msg.GetBody(&imap.BodySectionName{})
 78		if r == nil {
 79			log.Fatal("Server didn't return message body")
 80		}
 81
 82		mr, err := mail.CreateReader(r)
 83		if err != nil {
 84			log.Fatal(err)
 85		}
 86
 87		header := mr.Header
 88		fromAddrs, _ := header.AddressList("From")
 89		toAddrs, _ := header.AddressList("To")
 90		subject, _ := header.Subject()
 91		date, _ := header.Date()
 92
 93		var fromAddr string
 94		if len(fromAddrs) > 0 {
 95			fromAddr = fromAddrs[0].Address
 96		}
 97
 98		var toAddrList []string
 99		for _, addr := range toAddrs {
100			toAddrList = append(toAddrList, addr.Address)
101		}
102
103		p, err := mr.NextPart()
104		if err != nil && err != io.EOF {
105			log.Fatal(err)
106		}
107
108		body, _ := io.ReadAll(p.Body)
109
110		emails = append(emails, Email{
111			From:    fromAddr,
112			To:      toAddrList,
113			Subject: subject,
114			Body:    string(body),
115			Date:    date,
116		})
117	}
118
119	if err := <-done; err != nil {
120		return nil, err
121	}
122
123	// Reverse the order of emails to be from newest to oldest.
124	for i, j := 0, len(emails)-1; i < j; i, j = i+1, j-1 {
125		emails[i], emails[j] = emails[j], emails[i]
126	}
127
128	return emails, nil
129}