127 lines
2.9 KiB
Go
127 lines
2.9 KiB
Go
|
|
package mail
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"log"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"github.com/emersion/go-imap/v2/imapclient"
|
||
|
|
"mail2couch/config"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ImapClient wraps the IMAP client
|
||
|
|
type ImapClient struct {
|
||
|
|
*imapclient.Client
|
||
|
|
}
|
||
|
|
|
||
|
|
// Message represents an email message retrieved from IMAP
|
||
|
|
type Message struct {
|
||
|
|
UID uint32
|
||
|
|
From []string
|
||
|
|
To []string
|
||
|
|
Subject string
|
||
|
|
Date time.Time
|
||
|
|
Body string
|
||
|
|
Headers map[string][]string
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewImapClient creates a new IMAP client from the configuration
|
||
|
|
func NewImapClient(source *config.MailSource) (*ImapClient, error) {
|
||
|
|
addr := fmt.Sprintf("%s:%d", source.Host, source.Port)
|
||
|
|
|
||
|
|
client, err := imapclient.DialTLS(addr, nil)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to dial IMAP server: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := client.Login(source.User, source.Password).Wait(); err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to login: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return &ImapClient{client}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ListMailboxes lists all available mailboxes
|
||
|
|
func (c *ImapClient) ListMailboxes() ([]string, error) {
|
||
|
|
var mailboxes []string
|
||
|
|
cmd := c.List("", "*", nil)
|
||
|
|
|
||
|
|
infos, err := cmd.Collect()
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, info := range infos {
|
||
|
|
mailboxes = append(mailboxes, info.Mailbox)
|
||
|
|
}
|
||
|
|
|
||
|
|
return mailboxes, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetMessages retrieves messages from a specific mailbox (simplified version)
|
||
|
|
func (c *ImapClient) GetMessages(mailbox string, since *time.Time) ([]*Message, error) {
|
||
|
|
// Select the mailbox
|
||
|
|
mbox, err := c.Select(mailbox, nil).Wait()
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to select mailbox %s: %w", mailbox, err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if mbox.NumMessages == 0 {
|
||
|
|
return []*Message{}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// For now, just return placeholder messages to test the flow
|
||
|
|
var messages []*Message
|
||
|
|
numToFetch := mbox.NumMessages
|
||
|
|
if numToFetch > 5 {
|
||
|
|
numToFetch = 5 // Limit to 5 messages for testing
|
||
|
|
}
|
||
|
|
|
||
|
|
for i := uint32(1); i <= numToFetch; i++ {
|
||
|
|
msg := &Message{
|
||
|
|
UID: i,
|
||
|
|
From: []string{"test@example.com"},
|
||
|
|
To: []string{"user@example.com"},
|
||
|
|
Subject: fmt.Sprintf("Message %d from %s", i, mailbox),
|
||
|
|
Date: time.Now(),
|
||
|
|
Body: fmt.Sprintf("This is a placeholder message %d from mailbox %s", i, mailbox),
|
||
|
|
Headers: make(map[string][]string),
|
||
|
|
}
|
||
|
|
messages = append(messages, msg)
|
||
|
|
}
|
||
|
|
|
||
|
|
return messages, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ShouldProcessMailbox checks if a mailbox should be processed based on filters
|
||
|
|
func (c *ImapClient) ShouldProcessMailbox(mailbox string, filter *config.FolderFilter) bool {
|
||
|
|
// If include list is specified, mailbox must be in it
|
||
|
|
if len(filter.Include) > 0 {
|
||
|
|
found := false
|
||
|
|
for _, included := range filter.Include {
|
||
|
|
if mailbox == included {
|
||
|
|
found = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if !found {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// If exclude list is specified, mailbox must not be in it
|
||
|
|
for _, excluded := range filter.Exclude {
|
||
|
|
if mailbox == excluded {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
// Logout logs the client out
|
||
|
|
func (c *ImapClient) Logout() {
|
||
|
|
if err := c.Client.Logout(); err != nil {
|
||
|
|
log.Printf("Failed to logout: %v", err)
|
||
|
|
}
|
||
|
|
}
|