diff --git a/README.md b/README.md index d60132fb5..7f07bc33f 100644 --- a/README.md +++ b/README.md @@ -490,7 +490,7 @@ Use an inbox as a channel: PicoClaw connects via IMAP to read new mail and (opti "password": "YOUR_APP_PASSWORD", "mailbox": "INBOX", "check_interval": 30, - "use_idle": true, + "forced_polling": false, "use_tls": true, "allow_from": ["allowed-sender@example.com"], "attachment_dir": "/path/to/save/attachments", @@ -507,8 +507,8 @@ Use an inbox as a channel: PicoClaw connects via IMAP to read new mail and (opti | `imap_server`, `imap_port` | IMAP server (e.g. 993 with TLS). | | `username`, `password` | Mailbox login; 163/QQ require app password. | | `mailbox` | Folder to watch (default `INBOX`). | -| `use_idle` | `true`: use IMAP IDLE when supported (push); `false`: poll every `check_interval` seconds. | -| `check_interval` | Polling interval in seconds when IDLE is off or unsupported (default 30). | +| `forced_polling` | When the server does not implement IDLE/NOOP per spec, set `true` to use application-level polling; leave `false` normally. | +| `check_interval` | Polling interval in seconds when using forced polling or when IDLE is unsupported (default 30). | | `allow_from` | Allowed sender addresses; only their mails trigger the agent. | | `attachment_dir` | Directory to save attachments; leave empty to skip saving. | | `smtp_server`, `smtp_port`, `smtp_use_tls` | Optional; if set, the agent can send replies. | diff --git a/config/config.example.json b/config/config.example.json index b79388523..b0c18d4fe 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -79,10 +79,10 @@ "password": "your_password", "mailbox": "INBOX", "check_interval": 30, + "forced_polling": false, "use_tls": true, "allow_from": ["allowed_email@example.com"], "attachment_dir": "~/.picoclaw/workspace/attachments", - "use_idle": true, "smtp_server": "smtp.example.com--eg:smtp.qq.com", "smtp_port": 465, "smtp_use_tls": true diff --git a/pkg/channels/email.go b/pkg/channels/email.go index e7ae2723e..01cc6af02 100644 --- a/pkg/channels/email.go +++ b/pkg/channels/email.go @@ -310,12 +310,13 @@ func (c *EmailChannel) checkLoop(ctx context.Context) { // Run one check immediately c.checkNewEmails() - if c.config.UseIdle { + if !c.config.ForcedPolling { + // support IDLE user idle loop, waiting for server push update c.runIdleLoop(ctx, interval) return } - // Polling mode + // not support IDLE user polling mode, check new emails every interval c.mu.Lock() c.checkTicker = time.NewTicker(interval) ticker := c.checkTicker diff --git a/pkg/config/config.go b/pkg/config/config.go index 10a4ac619..8f1a4d4c6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -149,15 +149,16 @@ type LINEConfig struct { } type EmailConfig struct { - Enabled bool `json:"enabled" env:"PICOCLAW_CHANNELS_EMAIL_ENABLED"` - IMAPServer string `json:"imap_server" env:"PICOCLAW_CHANNELS_EMAIL_IMAP_SERVER"` - IMAPPort int `json:"imap_port" env:"PICOCLAW_CHANNELS_EMAIL_IMAP_PORT"` - Username string `json:"username" env:"PICOCLAW_CHANNELS_EMAIL_USERNAME"` - Password string `json:"password" env:"PICOCLAW_CHANNELS_EMAIL_PASSWORD"` - Mailbox string `json:"mailbox" env:"PICOCLAW_CHANNELS_EMAIL_MAILBOX"` // 默认 "INBOX" - CheckInterval int `json:"check_interval" env:"PICOCLAW_CHANNELS_EMAIL_CHECK_INTERVAL"` // seconds, default 30; used for polling when IDLE disabled or unsupported - UseIdle bool `json:"use_idle" env:"PICOCLAW_CHANNELS_EMAIL_USE_IDLE"` // use IMAP IDLE (push) when server supports it; otherwise poll - UseTLS bool `json:"use_tls" env:"PICOCLAW_CHANNELS_EMAIL_USE_TLS"` + Enabled bool `json:"enabled" env:"PICOCLAW_CHANNELS_EMAIL_ENABLED"` + IMAPServer string `json:"imap_server" env:"PICOCLAW_CHANNELS_EMAIL_IMAP_SERVER"` + IMAPPort int `json:"imap_port" env:"PICOCLAW_CHANNELS_EMAIL_IMAP_PORT"` + Username string `json:"username" env:"PICOCLAW_CHANNELS_EMAIL_USERNAME"` + Password string `json:"password" env:"PICOCLAW_CHANNELS_EMAIL_PASSWORD"` + Mailbox string `json:"mailbox" env:"PICOCLAW_CHANNELS_EMAIL_MAILBOX"` // 默认 "INBOX" + CheckInterval int `json:"check_interval" env:"PICOCLAW_CHANNELS_EMAIL_CHECK_INTERVAL"` // seconds, default 30; used for polling when IDLE disabled or unsupported + UseTLS bool `json:"use_tls" env:"PICOCLAW_CHANNELS_EMAIL_USE_TLS"` + // ForcedPolling: when the mail server does not implement IDLE/NOOP per spec (e.g. NOOP does not return * EXISTS), set true to use application-level polling (check new mail at CheckInterval). Leave false under normal conditions. + ForcedPolling bool `json:"forced_polling" env:"PICOCLAW_CHANNELS_EMAIL_FORCED_POLLING"` AllowFrom FlexibleStringSlice `json:"allow_from" env:"PICOCLAW_CHANNELS_EMAIL_ALLOW_FROM"` AttachmentDir string `json:"attachment_dir" env:"PICOCLAW_CHANNELS_EMAIL_ATTACHMENT_DIR"` // SMTP send (optional, if not configured, Send is not available) @@ -332,7 +333,7 @@ func DefaultConfig() *Config { Password: "", Mailbox: "INBOX", CheckInterval: 30, - UseIdle: true, + ForcedPolling: false, UseTLS: true, AllowFrom: FlexibleStringSlice{}, SMTPServer: "",