# IMAP UID and cursor lifecycle

An IMAP mailbox has no change log, so Connect resumes from a UID — the position in the folder up to which everything has been dealt with. It advances only for work that was actually processed. A refusal, a failure or a partial pass leaves it where it was, which means the same messages are offered again rather than skipped.

- **Status:** Available
- **Audience:** both, developer
- **Channels:** email
- **In the app:** #/mailboxes
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/email/imap-cursor/

## What the cursor claims

A cursor is not a bookmark saying "I read this far". It is a claim that everything up to that point has been canonicalised, triaged and accounted for. That distinction decides every rule on this page: a bookmark can be moved optimistically, a claim cannot.

IMAP gives each message in a folder a UID that is unique within that folder and increases over time, which makes "everything after N" a cheap question. What IMAP does not give is a log of changes, so unlike [Gmail history sync](/docs/email/gmail-history-sync/) there is nothing to ask about deletions, flags or moves in one call. The protocol itself is described in the [technology reference](/docs/technology/).

## The one outcome that advances it

| Outcome | Cursor | Why |
|---|---|---|
| Messages fetched, bridged and accepted | Advances | The claim is now true up to the new UID |
| The daily allowance refused the batch | Stays | The work was not done; the mail waits at the server and Needs You shows the refusal |
| The connection dropped mid-pass | Stays | A partial pass proves nothing about the messages it did not reach |
| The bridge rejected a message | Stays at the last accepted UID | A canonical record was not produced, so the claim would be false |
| Nothing new above the cursor | Stays | A [quiet mailbox](/docs/email/quiet-mailbox/): correct and uneventful |

The cost of this discipline is duplication of effort — a message may be fetched more than once if a pass keeps failing after it. The cost of the alternative is a customer who was never answered and no record that they were ever seen. [How a mail cursor loses messages, and how to stop it](/research/cursor-loss/) works through why the second cost is not comparable to the first.

> **Careful** The allowance refusal is the case to internalise. It is not an error, it happens routinely on a plan with a daily bound, and it is precisely the moment when advancing a cursor would feel harmless. It is not: it converts "we will get to these tomorrow" into "nobody will ever look at these".

## When a UID stops meaning anything

**The folder's validity marker changed** — IMAP servers publish a validity value alongside UIDs; when it changes, previously recorded UIDs no longer refer to the same messages. A cursor from before the change cannot be trusted against the folder after it.
**The mailbox was recreated or migrated** — A restore, a migration between servers, or a rebuilt folder can renumber everything. The mailbox is then in the position of one that has never been read.
**The folder being read changed** — A cursor belongs to a folder. Pointing the connection at a different one is a different sequence of UIDs, not a continuation of the old one.
**The mailbox was reconnected** — A new connection establishes a new position rather than inheriting the old one, in the same way a first pass does.

None of these deletes anything in the workspace. Canonical threads, messages and contacts already produced are unaffected — they were copied across the bridge and belong to the workspace, not to the folder they came from.

## Diagnosing a stuck cursor

1. Check whether the mailbox is refusing or failing. They look identical from the Conversations screen and are different problems.
   - Result: A refusal appears in Needs You with its reason; a failure appears as a health verdict on the mailbox row.
2. If it is a refusal, look at the allowance rather than the mailbox.
   - Result: Nothing is wrong with the connection. The work resumes when the allowance does — [The daily email allowance](/docs/email/daily-allowance/).
3. If it is a failure, test the incoming half on its own.
   - Result: IMAP and SMTP fail independently, and a mailbox whose reads are stuck may be sending perfectly — [Connecting an IMAP and SMTP server](/docs/email/connect-imap-smtp/).
4. Only then consider reconnecting.
   - Result: Reconnecting establishes a new position, which resolves a cursor that has genuinely become meaningless and does nothing at all for a mailbox that was simply refused.

## Questions

### Will the same message be processed twice?

It can be fetched twice — that is the deliberate cost of never advancing on a refusal. What protects you downstream is that canonicalisation and the send boundary are the same for both attempts, so a repeat fetch does not become a repeated reply.

### Can I move the cursor by hand?

It is not a user-facing setting, and that is intentional: every manual position change is either a no-op or an assertion that unprocessed mail was processed. Reconnecting is the supported way to establish a new position.

### Does the cursor track deletions or read flags on the server?

A UID cursor answers "what is new above this point". Changes to older messages are not something a plain UID position describes, which is one of the concrete differences between IMAP and Gmail's history mechanism.

## Related

- [Connecting an IMAP and SMTP server](https://connectbyjbrh.com/docs/email/connect-imap-smtp/)
- [Gmail history sync](https://connectbyjbrh.com/docs/email/gmail-history-sync/)
- [Syncing an inbox](https://connectbyjbrh.com/docs/email/inbox-sync/)
- [The daily email allowance](https://connectbyjbrh.com/docs/email/daily-allowance/)
- [IMAP](https://connectbyjbrh.com/docs/technology/imap/)
- [How a mail cursor loses messages, and how to stop it](https://connectbyjbrh.com/research/cursor-loss/)

## What this page is based on

- Connect source pack — channels, §1: the allowance holds work and deliberately does not advance the read cursor
- Connect source pack — channels, §1: IMAP/SMTP as a provider; the two mail models
- Connect capability registry (`docs-source/facts.py`) — `imap_smtp`, `daily_quota_refusal`
