Skip to content

Conversation

@toddheasley
Copy link
Collaborator

@toddheasley toddheasley commented Jan 27, 2026

Building on top of IMAPCommand, PR implements following mailbox-specific commands:

  • namespace
  • list, status
  • select, examine, unselect
  • create, rename, delete
  • expunge, close
  • subscribe, unsubscribe

All commands added to IMAPClient public interface and tested by IMAPClientTests.allCommands. Both IMAP and SMTP tests are refactored to support testing with multiple live email accounts concurrently, configurable. IMAP tests currently pass against AOL, Gmail and iCloud accounts; Outlook fails basic auth.

Additionally, errors and logging are streamlined for usefulness, legibility:

Mailbox commands not implemented here, to be implemented later in milestone:

Close #159; close #198

@toddheasley toddheasley marked this pull request as ready for review January 29, 2026 17:26
@toddheasley toddheasley requested a review from a team as a code owner January 29, 2026 17:26
@toddheasley toddheasley requested review from asoucar and removed request for a team January 29, 2026 17:26
struct IMAPClientTests {
@Test(.disabled(if: Server.server.isDisabled)) func connect() async throws {
let client: IMAPClient = IMAPClient(.server)
@Test(arguments: Server.allCases(disabled: false)) func allCommands(_ server: Server) async throws {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because IMAP commands are sequential and stateful, testing on live server works as one big named integration w/ a bunch of tests in logical order


@Test(.disabled(if: Server.server.password.isEmpty)) func sendToRecipient() async throws {
try await SMTPClient(.server).send(.email, to: "recipient@example.com")
@Test(arguments: Server.allCases(disabled: false)) func send(server: Server) async throws {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updating SMTP live server testing to match IMAP

}
let promise: EventLoopPromise<T.Result> = channel.eventLoop.makePromise(of: T.Result.self)
let tag: String = tag() // Hold onto specific auto-generated tag
let tag: String = UUID().uuidString(1) // Hold onto specific auto-generated tag
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Testing against live IMAP servers (AOL, Gmail, Fastmail, iCloud, Outlook/Hotmail), there's no advantage to traditional, custom tags (a001-a999) over shortened UUIDs, which are less work/code that we own, and way less likely to collide.

import NIOCore
import NIOIMAPCore

// Avoid republishing the entire (cluttered) NIOIMAP public interface with @_exported; instead
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The NIOIMAP models, in most cases, meet our (interface) needs, but we'll use only the ones we need directly, without republishing the entire NIOIMAP module interface. In some cases, e.g., Namespace and Message, we'll tailor our own models to suit.

import NIOCore
import NIOIMAP

// Generic wrapper for void-result commands that succeed or fail only
Copy link
Collaborator Author

@toddheasley toddheasley Jan 29, 2026

Choose a reason for hiding this comment

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

The majority of IMAP commands (1) take no arguments and (2) succeed or fail with no returned payload. In which case, directly run the NIOIMAP command.

@toddheasley toddheasley merged commit 289125f into thunderbird:main Feb 9, 2026
1 check passed
@toddheasley toddheasley deleted the feature-imap-folders branch February 9, 2026 15:33
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.

IMAP-SMTP Foundation: Add IMAP folder commands IMAP-SMTP Foundation: Codable IMAP Models

2 participants