diff --git a/internal/imapclient/service.go b/internal/imapclient/service.go new file mode 100644 index 0000000..0c8edac --- /dev/null +++ b/internal/imapclient/service.go @@ -0,0 +1,27 @@ +package imapclient + +import ( + "context" + + "email-mcp/internal/secretstore" +) + +type Service struct { + backend Backend +} + +func NewService(backend Backend) Service { + return Service{backend: backend} +} + +func (s Service) ListMailboxes(ctx context.Context, cred secretstore.Credential) ([]Mailbox, error) { + return s.backend.ListMailboxes(ctx, cred) +} + +func (s Service) ListMessages(ctx context.Context, cred secretstore.Credential, mailbox string, limit int) ([]MessageSummary, error) { + return s.backend.ListMessages(ctx, cred, mailbox, limit) +} + +func (s Service) GetMessage(ctx context.Context, cred secretstore.Credential, mailbox string, id string) (Message, error) { + return s.backend.GetMessage(ctx, cred, mailbox, id) +} diff --git a/internal/imapclient/service_test.go b/internal/imapclient/service_test.go new file mode 100644 index 0000000..21f4ac0 --- /dev/null +++ b/internal/imapclient/service_test.go @@ -0,0 +1,38 @@ +package imapclient + +import ( + "context" + "testing" + + "email-mcp/internal/secretstore" +) + +type backendStub struct{} + +func (backendStub) ListMailboxes(context.Context, secretstore.Credential) ([]Mailbox, error) { + return []Mailbox{{Name: "INBOX"}}, nil +} + +func (backendStub) ListMessages(context.Context, secretstore.Credential, string, int) ([]MessageSummary, error) { + return nil, nil +} + +func (backendStub) GetMessage(context.Context, secretstore.Credential, string, string) (Message, error) { + return Message{}, nil +} + +func TestServiceListMailboxesUsesBackend(t *testing.T) { + svc := NewService(backendStub{}) + + boxes, err := svc.ListMailboxes(context.Background(), secretstore.Credential{ + Host: "imap.example.com", + Username: "alice", + Password: "secret", + }) + if err != nil { + t.Fatalf("ListMailboxes returned error: %v", err) + } + if len(boxes) != 1 || boxes[0].Name != "INBOX" { + t.Fatalf("unexpected mailboxes: %#v", boxes) + } +} diff --git a/internal/imapclient/types.go b/internal/imapclient/types.go new file mode 100644 index 0000000..7184a4b --- /dev/null +++ b/internal/imapclient/types.go @@ -0,0 +1,31 @@ +package imapclient + +import ( + "context" + + "email-mcp/internal/secretstore" +) + +type Mailbox struct { + Name string `json:"name"` +} + +type MessageSummary struct { + ID string `json:"id"` + Subject string `json:"subject"` + From string `json:"from"` + UID uint32 `json:"uid"` +} + +type Message struct { + ID string `json:"id"` + Mailbox string `json:"mailbox"` + Headers map[string]string `json:"headers"` + Body string `json:"body"` +} + +type Backend interface { + ListMailboxes(context.Context, secretstore.Credential) ([]Mailbox, error) + ListMessages(context.Context, secretstore.Credential, string, int) ([]MessageSummary, error) + GetMessage(context.Context, secretstore.Credential, string, string) (Message, error) +}