package pop3 import ( "context" "fmt" gopop3 "github.com/knadh/go-pop3" "internal-mail-skill/internal/config" "internal-mail-skill/internal/model" ) type Fetcher struct { cfg config.POP3Config } func NewFetcher(cfg config.POP3Config) *Fetcher { return &Fetcher{cfg: cfg} } func (f *Fetcher) Fetch(ctx context.Context) ([]model.FetchedMessage, error) { if f.cfg.Host == "" { return nil, fmt.Errorf("POP3_HOST is required") } select { case <-ctx.Done(): return nil, ctx.Err() default: } client := gopop3.New(gopop3.Opt{ Host: f.cfg.Host, Port: f.cfg.Port, TLSEnabled: f.cfg.UseTLS, DialTimeout: f.cfg.Timeout(), }) conn, err := client.NewConn() if err != nil { return nil, fmt.Errorf("connect POP3: %w", err) } defer conn.Quit() if err := conn.Auth(f.cfg.Username, f.cfg.Password); err != nil { return nil, fmt.Errorf("POP3 auth: %w", err) } ids, err := conn.Uidl(0) if err != nil { return nil, fmt.Errorf("POP3 UIDL: %w", err) } out := make([]model.FetchedMessage, 0, len(ids)) for _, item := range ids { select { case <-ctx.Done(): return out, ctx.Err() default: } raw, err := conn.RetrRaw(item.ID) if err != nil { out = append(out, model.FetchedMessage{ServerID: item.ID, UID: item.UID, Error: fmt.Sprintf("POP3 RETR %d: %v", item.ID, err)}) continue } out = append(out, model.FetchedMessage{ ServerID: item.ID, UID: item.UID, Raw: raw.Bytes(), }) } return out, nil }