Bounce messages and MAILER-DAEMON notices can have no From address, causing a panic on the bare [0] index access. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
104 lines
2.2 KiB
Go
104 lines
2.2 KiB
Go
package email
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/mail"
|
|
"strings"
|
|
|
|
"github.com/emersion/go-imap"
|
|
"github.com/emersion/go-imap/client"
|
|
)
|
|
|
|
func FetchEmails() ([]Email, error) {
|
|
config, err := NewConfigFromEnv()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
imapClient, err := config.ConnectToServer(IMAP_SERVICE)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer imapClient.Logout()
|
|
|
|
return fetchEmails(imapClient)
|
|
}
|
|
|
|
func concatAddresses(addresses []*imap.Address) string {
|
|
result := []string{}
|
|
|
|
for _, address := range addresses {
|
|
if len(address.PersonalName) > 0 {
|
|
result = append(result, fmt.Sprintf("%s <%s>", address.PersonalName, address.Address()))
|
|
} else {
|
|
result = append(result, address.Address())
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(result, "; ")
|
|
}
|
|
|
|
func fetchEmails(imapClient *client.Client) ([]Email, error) {
|
|
result := []Email{}
|
|
|
|
// Select the mailbox you want to read
|
|
_, err := imapClient.Select("INBOX", false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
criteria := imap.NewSearchCriteria()
|
|
criteria.WithoutFlags = []string{imap.SeenFlag}
|
|
uids, err := imapClient.Search(criteria)
|
|
if err != nil {
|
|
log.Printf("Search error: %s\n", err)
|
|
}
|
|
|
|
if len(uids) > 0 {
|
|
// Define the range of emails to fetch
|
|
seqSet := new(imap.SeqSet)
|
|
seqSet.AddNum(uids...)
|
|
|
|
// Fetch the required message attributes
|
|
messages := make(chan *imap.Message, 10)
|
|
section := &imap.BodySectionName{}
|
|
items := []imap.FetchItem{section.FetchItem(), imap.FetchEnvelope}
|
|
|
|
go func() {
|
|
if err := imapClient.Fetch(seqSet, items, messages); err != nil {
|
|
log.Fatal("Fetch error: " + err.Error())
|
|
}
|
|
}()
|
|
|
|
for msg := range messages {
|
|
if len(msg.Envelope.From) == 0 {
|
|
continue
|
|
}
|
|
toAddress := concatAddresses(msg.Envelope.To)
|
|
fromAddress := msg.Envelope.From[0].Address()
|
|
r := msg.GetBody(section)
|
|
if r == nil {
|
|
return result, fmt.Errorf("server didn't returned message body")
|
|
}
|
|
m, err := mail.ReadMessage(r)
|
|
if err != nil {
|
|
return result, err
|
|
}
|
|
body, err := io.ReadAll(m.Body)
|
|
|
|
email := NewEmail(
|
|
[]string{toAddress},
|
|
[]string{},
|
|
fromAddress,
|
|
msg.Envelope.Subject,
|
|
string(body),
|
|
)
|
|
result = append(result, *email)
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|