Implement internal mail skill MVP
This commit is contained in:
69
internal/pop3/pop3.go
Normal file
69
internal/pop3/pop3.go
Normal file
@@ -0,0 +1,69 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user