Skip to content

serve: dispatch scheduled sync by source type (IMAP support)#330

Merged
wesm merged 1 commit into
kenn-io:mainfrom
franklintra:fix-imap-scheduled-sync
May 24, 2026
Merged

serve: dispatch scheduled sync by source type (IMAP support)#330
wesm merged 1 commit into
kenn-io:mainfrom
franklintra:fix-imap-scheduled-sync

Conversation

@franklintra
Copy link
Copy Markdown
Contributor

Summary

  • Fixes serve: IMAP accounts in config.toml fail every tick — daemon's scheduled sync is Gmail-only #329: runScheduledSync was hardcoded to the Gmail OAuth path, so every scheduled tick for an IMAP account configured in config.toml failed with the misleading oauth2: token expired and refresh token is not set error and no IMAP sync ever ran from the daemon.
  • Look up the source by identifier and dispatch on source_type: Gmail keeps the existing incremental flow (and its daemon-specific token error messages); IMAP runs a full sync via the shared buildAPIClient helper (NoResume=true, matching the CLI's IMAP behaviour).
  • A nil source still falls back to Gmail to preserve the token-first workflow where tokens are uploaded via the API before any source row exists.

Notes

  • The shared buildAPIClient helper handles both password-IMAP (via imap.LoadCredentials) and OAuth-IMAP (Microsoft) — both work from the daemon.
  • Unsupported source types (mbox, apple-mail, imessage, etc.) now return an explicit error instead of being misclassified as Gmail.

Test plan

  • go vet ./... clean
  • make test — full suite green
  • New TestFindScheduledSyncSource — covers nil / imap-only / mixed gmail+mbox / mbox-only identifier rows.
  • New TestRunScheduledIMAPSync_NoCredentials — verifies the dispatcher actually reaches the IMAP path (no Gmail-flavoured error) and fails with a useful credentials error.

@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 21, 2026

roborev: Combined Review (4dd6a7d)

High severity issue found: scheduled IMAP full syncs can route through Gmail source handling.

High

  • cmd/msgvault/cmd/serve.go:542 - The IMAP scheduler path calls syncer.Full(ctx, src.Identifier), but Full creates or uses a Gmail source for that identifier. This can store IMAP messages under a gmail source, and because findScheduledSyncSource prefers Gmail, later scheduled runs for the same IMAP URL may dispatch through the Gmail OAuth path instead of IMAP.

    Fix: Add or use a full-sync entry point that syncs against the existing IMAP source ID/source type, or update Full to honor an explicit source type/source so IMAP never creates a Gmail source for the IMAP identifier.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 21, 2026

roborev: Combined Review (4dd6a7d)

Verdict: No Medium, High, or Critical issues found.

All provided review outputs agree there are no reportable findings for this PR.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@wesm wesm force-pushed the fix-imap-scheduled-sync branch from 4dd6a7d to 801e516 Compare May 24, 2026 19:12
@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 24, 2026

roborev: Combined Review (801e516)

Scheduled IMAP support has two medium-severity correctness issues that should be fixed before merge.

Medium

  • cmd/msgvault/cmd/serve.go:398
    Scheduled source lookup only checks sources.identifier, but IMAP/O365 sources store the user-facing email in display_name while identifier is the imaps://... URL. A config entry like email = "user@outlook.com" will miss the IMAP source and incorrectly fall back to the Gmail OAuth path.
    Fix: Resolve scheduled sources with GetSourcesByIdentifierOrDisplayName, then keep the existing Gmail-over-IMAP filtering.

  • cmd/msgvault/cmd/serve.go:515
    runScheduledIMAPSync calls confirmDefaultIdentity with src.Identifier, which is an IMAP URL rather than an email address. If identities were intentionally cleared, the daemon can recreate an identity such as imaps://user@..., polluting account_identities and breaking deduplication.
    Fix: Remove this call, or use src.DisplayName / parsed imapCfg.Username if fallback identity injection is required.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@roborev-ci
Copy link
Copy Markdown

roborev-ci Bot commented May 24, 2026

roborev: Combined Review (446ccd8)

Verdict: Code review is clean; no Medium, High, or Critical findings were reported.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

runScheduledSync was hardcoded to the Gmail OAuth path, so every
scheduled tick for an IMAP account in config.toml failed with the
misleading 'oauth2: token expired and refresh token is not set'
error. Look up the source by identifier or display_name and
dispatch: Gmail keeps the existing incremental-sync flow; IMAP
runs a full sync via the shared buildAPIClient helper. A nil
source still falls back to Gmail to preserve the token-first
workflow.

- findScheduledSyncSource matches against identifier OR
  display_name. IMAP sources from add-imap store the user-facing
  email in display_name while identifier is the imaps:// URL, so
  a config.toml entry like email = "user@example.com" resolves
  the IMAP row instead of falling back to Gmail.
- runScheduledIMAPSync passes src.DisplayName (the email recorded
  by add-imap) to confirmDefaultIdentity, not src.Identifier (the
  imaps:// URL), so the daemon never injects a URL into
  account_identities if the user has cleared identities. A
  legacy IMAP row with NULL display_name silently skips the
  write.

Fixes kenn-io#329
@wesm wesm force-pushed the fix-imap-scheduled-sync branch from 446ccd8 to 6fc13b7 Compare May 24, 2026 21:11
@wesm wesm merged commit b376d85 into kenn-io:main May 24, 2026
5 of 6 checks passed
@wesm
Copy link
Copy Markdown
Member

wesm commented May 24, 2026

thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

serve: IMAP accounts in config.toml fail every tick — daemon's scheduled sync is Gmail-only

2 participants