Skip to content

fix(core): stop ActiveSync log spam and folder loss on IMAP outage#193

Merged
ralflang merged 2 commits into
FRAMEWORK_6_0from
fix/activesync-imap-outage-log-spam
Jul 8, 2026
Merged

fix(core): stop ActiveSync log spam and folder loss on IMAP outage#193
ralflang merged 2 commits into
FRAMEWORK_6_0from
fix/activesync-imap-outage-log-spam

Conversation

@TDannhauer

Copy link
Copy Markdown
Contributor

Summary

  • Collapse the multi-layer ERR/WARN logging cascade on an IMAP outage down to a single NOTICE.
  • Distinguish transient IMAP connection failures from hard errors and surface them as Horde_ActiveSync_Exception_TemporaryFailure.
  • Stop returning an empty folder hierarchy on a transient failure (which could delete the client's mail folders); defer the FOLDERSYNC instead.

Motivation

With a device polling ActiveSync while the IMAP server is down, one connection failure was caught, logged, and re-thrown at every layer, spamming horde.log at ERR/WARN once per poll per device. getFolders() returning [] also caused FOLDERSYNC to diff against an empty hierarchy, risking removal of the user's mail folders on the device.

Changes

  • Horde_Core_ActiveSync_Imap_Factory::getMailboxes(): new _isTransientImapError() walks the exception chain (the underlying Horde_Imap_Client_Exception code survives inside wrappers such as the injector's "Cannot create IMP_Ftree"). Transient failures log once at NOTICE and throw Horde_ActiveSync_Exception_TemporaryFailure; other errors keep the ERR + Horde_ActiveSync_Exception behavior.
  • Horde_Core_ActiveSync_Driver::_getMailFolders(): drop the duplicate ERR re-log (kept a debug trace), re-throw preserving the exception type.
  • Horde_Core_ActiveSync_Driver::getFolders(): propagate TemporaryFailure instead of returning []; downgrade the non-transient log to debug.
  • Horde_Core_ActiveSync_Driver::getFolderList(): catch TemporaryFailure and return false, the state engine's "skip folder diff" signal.

Dependencies

Relies on horde/ActiveSync PR "report no folder changes when getFolderList() is false" so the false return is handled without a count(null) fatal. Merge that first.

Test plan

  • With IMAP reachable: FOLDERSYNC/SYNC behave as before.
  • With IMAP down: horde.log shows a single NOTICE per poll (not the ERR/WARN cascade); FOLDERSYNC returns no changes with the same synckey; device keeps its folders and recovers when IMAP returns.
  • Auth/config (non-connection) IMAP errors still log at ERR.

When the mail server is unreachable during ActiveSync polling, a single
IMAP connection failure was caught, logged at ERR/WARN, and re-thrown at
every layer (IMAP factory, _getMailFolders, getFolders), producing
several log lines per poll per device. getFolders() also returned an
empty array, which made FOLDERSYNC diff against an empty hierarchy and
could make clients drop all their mail folders.

Classify transient connection failures (DISCONNECT / SERVER_CONNECT /
LOGIN_UNAVAILABLE, detected via the preserved exception chain) in the
IMAP factory: log once at NOTICE and throw
Horde_ActiveSync_Exception_TemporaryFailure. Drop the redundant
re-logging in the driver, and have getFolderList() return false on a
temporary failure so the state engine skips folder-change detection this
round and the device retries later instead of losing folders. Genuine
(non-connection) errors are unchanged: still logged at ERR.
@TDannhauer TDannhauer requested a review from ralflang July 8, 2026 06:25
// the caller defer the sync instead of treating it as a
// hard error (which spams the log at every layer and can
// make clients drop their mail folders).
Horde::log(sprintf(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use Horde::log - inject a logger.

@ralflang

ralflang commented Jul 8, 2026

Copy link
Copy Markdown
Member

Hard-error IMAP failures still return [] from getFolders(). That would still allow hard errors to trigger clients deleting folders.

…d IMAP errors

Incorporate review feedback on the ActiveSync IMAP outage handling:

- Imap_Factory: inject a Horde_Log_Logger via the constructor instead of
  the static Horde::log() facade (wired from the injector in the
  ActiveSyncBackend factory); a null logger is used when none is given.
- Driver::getFolders(): propagate hard IMAP errors instead of returning
  an empty/partial hierarchy. Returning [] let FOLDERSYNC diff against a
  reduced list and could make clients delete the user's mail folders -
  the same risk previously only guarded for transient failures.
- Driver::getFolderList(): catch the base Horde_ActiveSync_Exception so
  any folder-enumeration failure (transient or hard) skips folder-change
  detection this round; the device retries later. Log severity is still
  decided once in the factory (NOTICE transient, ERR hard).
@TDannhauer TDannhauer requested a review from ralflang July 8, 2026 18:43
@ralflang ralflang merged commit 7a7194f into FRAMEWORK_6_0 Jul 8, 2026
1 check failed
@TDannhauer TDannhauer deleted the fix/activesync-imap-outage-log-spam branch July 10, 2026 11:08
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.

2 participants