Skip to content

Add on-premises Exchange through EWS - #201

Merged
rajzik merged 43 commits into
mainfrom
codex/issue-70-add-on-premises-exchange-through-ews
Jul 28, 2026
Merged

rajzik merged 43 commits into
mainfrom
codex/issue-70-add-on-premises-exchange-through-ews

Conversation

@rajzik

@rajzik rajzik commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Closes #70

Summary

  • add device-local on-premises EWS setup for Exchange 2013 SP1, 2016, and 2019 with password, app-password, OAuth, strict HTTPS identity, and Exchange Online rejection
  • integrate EWS folders, drafts, staged metadata/backfill, complete-scan reconciliation, encrypted body caching, provider actions, Outbox sending, Pins, and provider-neutral routing
  • persist body-free EWS metadata with SwiftData, require all full-capability mailbox roles, and hold ambiguous mutations for reconciliation instead of replaying them
  • document EWS support and local persistence, with a package changeset

Validation

  • mise exec -- zsh scripts/check-apple-lint.zsh
  • mise exec -- xcodebuild test -quiet -project apps/unwired-mail/unwired-mail.xcodeproj -scheme unwired-mail -destination 'platform=iOS Simulator,name=iPhone 17'
  • git diff --check

Two independent code reviews against repository standards and issue #70 completed with no remaining blockers.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith with what you need. Autofix is disabled.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds full-capability on-premises Exchange mailbox support through secure EWS, including setup, device-local authorization, SOAP operations, local-first synchronization, message actions, sending, routing, failure handling, persistence, UI integration, and extensive tests.

Changes

EWS mailbox integration

Layer / File(s) Summary
Setup contracts and account integration
apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift, apps/unwired-mail/unwired-mail/Features/Account/*, apps/unwired-mail/unwired-mail/Services/ProductSync/MailboxConnectionDefinition.swift, apps/unwired-mail/unwired-mail.xcodeproj/project.pbxproj, docs/adr/0004-swiftdata-for-local-persistence.md
Adds EWS validation, device-local authorization, synchronized definitions, setup UI, Account Settings wiring, target membership, and SwiftData snapshot semantics.
EWS SOAP client and protocol operations
apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift
Implements authenticated SOAP requests, XML parsing, mailbox verification, folder/message paging, body retrieval, mutations, sending, delivery status, and protocol validation.
Local-first adapter synchronization and actions
apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift, apps/unwired-mail/unwired-mailTests/EWSMailboxConnectionAdapterTests.swift
Adds metadata and encrypted body storage, resumable synchronization, reconciliation, message projection, provider actions, offline queues, identity refresh, and adapter coverage.
Provider routing, failures, and validation
apps/unwired-mail/unwired-mail/Services/Mailbox/IMAPMailboxConnectionAdapter.swift, apps/unwired-mail/unwired-mail/Services/Mailbox/OutboxDeliveryService.swift, apps/unwired-mail/unwired-mail/Services/Mailbox/PendingProviderActionService.swift, apps/unwired-mail/unwired-mail/Services/Mailbox/MailboxConnection.swift, apps/unwired-mail/unwired-mailTests/*
Routes EWS through shared services, classifies EWS failures, updates archive filtering, and tests provider isolation and retry behavior.
Documentation and release metadata
README.md, .changeset/on-premises-exchange-ews.md
Documents supported endpoints, EWS capabilities, credential handling, and synchronization behavior.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AccountSettings
  participant EWSSetupService
  participant SystemEWSClient
  participant EWSMailboxConnectionAdapter
  participant ExchangeServer
  AccountSettings->>EWSSetupService: submit EWS connection details
  EWSSetupService->>SystemEWSClient: verify mailbox
  SystemEWSClient->>ExchangeServer: send SOAP request
  ExchangeServer-->>SystemEWSClient: return mailbox and folder data
  EWSSetupService-->>AccountSettings: save connection definition
  EWSMailboxConnectionAdapter->>SystemEWSClient: synchronize folders and messages
  SystemEWSClient->>ExchangeServer: page mailbox metadata
  ExchangeServer-->>EWSMailboxConnectionAdapter: return EWS message pages
Loading

Possibly related PRs

  • unwired-dev/product#91: Shares the Product Sync mailbox-definition model extended here with EWS definitions.
  • unwired-dev/product#109: Intersects with the shared mailbox role and account-selection pipeline changed for EWS.
  • unwired-dev/product#138: Provides the pending provider-action pipeline extended here for EWS mutations and failure handling.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding on-premises Exchange support through EWS.
Description check ✅ Passed The description is directly related to the PR and matches the EWS/on-premises Exchange changes.
Linked Issues check ✅ Passed The implementation and tests cover #70's requirements for on-prem EWS, strict HTTPS, sync, actions, sending, and provider isolation.
Out of Scope Changes check ✅ Passed The changes are centered on the EWS feature plus related docs, project wiring, and tests, with no obvious unrelated additions.

Comment @coderabbitai help to get the list of available commands.

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d47b2bb82b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
@rajzik

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f562f7b11

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Features/Account/EWSSetupPanel.swift
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
@rajzik

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3eec31c26b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Features/Account/EWSSetupPanel.swift
@rajzik

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0344f38c0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
@rajzik

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 90248f0208

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Features/Account/EWSSetupPanel.swift Outdated
@rajzik

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a658d6bda8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Features/Account/EWSSetupPanel.swift
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9016c9f47

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/OutboxDeliveryService.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/SystemEWSClient.swift Outdated
Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 122f5ac065

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Services/Mailbox/EWSMailboxConnectionAdapter.swift Outdated

rajzik commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@rajzik
rajzik marked this pull request as ready for review July 27, 2026 06:31

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9c53aca330

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 604a050517

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 30aaab7083

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1314 to +1316
let text = try await client.loadMessageBody(
itemId: providerMessage.itemId,
authorization: authorization

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Recover body loads after external EWS moves

When an uncached message is moved by Outlook or another EWS client, Exchange assigns it a new item ID, but this path sends the cached pre-move ID directly to GetItem without recovery through the stable search key. For an older message that falls outside both folders' newest 50-item pages, recent synchronization will not repair that identity until the next full reconciliation, so opening its still-cached thread can fail with ErrorItemNotFound for up to the reconciliation interval. Unlike the pending-action path, body loading has no stale-identity handling; resolve the current item by stableProviderId and update the snapshot before retrying the body request.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Deferred to #204 because safe recovery requires a bounded stable-key lookup and metadata reconciliation shared by actions and body loads. The issue now includes body-load acceptance criteria and links this thread; leaving it unresolved until that work lands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 29e80ed329

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Features/Account/AccountView.swift

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 83ede8f832

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/unwired-mail/unwired-mail/Features/Account/AccountView.swift

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e3d42684fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add on-premises Exchange through EWS

1 participant