Table of Contents

Interface IMailboxWriteSession

Namespace
MailFathom.Application.Mail.Mutations
Assembly
MailFathom.Application.dll

Changes one folder of a remote mailbox, on behalf of an act the mailbox owner authored.

public interface IMailboxWriteSession : IAsyncDisposable
Inherited Members

Remarks

This is the only type in MailFathom able to change a mailbox, and it is deliberately a different type from IMailboxSession rather than a mode of it. Synchronization, reconciliation, content retrieval, and every MCP tool reach the server through that one, which exposes no operation capable of writing; a refactor therefore cannot give a read path the ability to write, because a read path never holds something that has it.

The surface is closed to exactly the mutations MailFathom is permitted to perform. There is no method that sends, replies, or forwards, none that creates, renames, deletes, or subscribes to a folder, and none that writes \Answered. Permitting one of those later is a decision to reopen rather than a method to append, and this surface is what a permitted mutation arrives on — \Flagged and the keywords did, because each is a change to one message and therefore the same kind of act as the four that were here first. What does not arrive here is an act of a different kind: folder creation is a port of its own for exactly that reason, so a caller able to file a message into a folder is deliberately unable to create one, and the reverse.

AppendAsync(ReadOnlyMemory<byte>, AppendedMailFlags, DateTimeOffset, CancellationToken) and WithdrawAppendedAsync(ImapUidValidity, ImapUid, CancellationToken) are the third reopening, and they are narrower than they look. Both act only on a message MailFathom itself composed and holds the outgoing record of: the append puts a copy of it into the folder its state calls for, and the withdrawal takes back a copy the append put there. Neither can reach a message somebody sent to this mailbox, because neither takes an occurrence — an append names no message at all and a withdrawal names a UID the append itself reported. That is also why \Draft is writable here and nowhere else: it is an assertion about a message being composed, which is true of exactly these and of nothing an owner received.

Every operation names what the caller asked for and never how the server was made to do it. Which protocol extension carried a relocation is a property of the server rather than of the change, so it reaches no caller and no record above debug detail; a server without RFC 6851 MOVE behaves identically to one with it, from here up.

A relocation and a delete are not atomic on a server that lacks MOVE, and nothing here makes them so. A crash between the commands leaves the mailbox in a state this session cannot describe, which is why every operation takes an IMailboxMutationJournal: the caller has written the change down before calling, the session announces each stage of the sequence as it passes it, and a resumed attempt reads Stage and continues from there instead of starting over.

Resuming is decided here rather than by the caller because it depends on what the connection advertises, which is this adapter's business and deliberately reaches no layer above. What the caller decides is the one thing the protocol cannot: a mutation whose placement command was issued and never acknowledged never reaches this session at all, because issuing it again would put a second message in the destination folder.

One session is used by one caller at a time and is not safe for concurrent use. It is short-lived by design: it holds the account's single write connection for as long as it is open, so a second caller waits.

Methods

AddKeywordsAsync(EmailOccurrenceId, AuthoredMailKeywords, IMailboxMutationJournal, CancellationToken)

Puts keywords on one email in this session's folder, beside the ones it already carries.

AppendAsync(ReadOnlyMemory<byte>, AppendedMailFlags, DateTimeOffset, CancellationToken)

Puts a copy of a message MailFathom composed into this session's folder.

CopyAsync(EmailOccurrenceId, RemoteFolderPath, IMailboxMutationJournal, CancellationToken)

Puts a second live occurrence of one email into another folder of the same account.

DeleteAsync(EmailOccurrenceId, IMailboxMutationJournal, CancellationToken)

Removes one email from this session's folder on the server.

RelocateAsync(EmailOccurrenceId, RemoteFolderPath, IMailboxMutationJournal, CancellationToken)

Moves one email out of this session's folder and into another folder of the same account.

RemoveKeywordsAsync(EmailOccurrenceId, AuthoredMailKeywords, IMailboxMutationJournal, CancellationToken)

Takes keywords off one email in this session's folder, leaving the ones it was not asked about.

SetFlaggedAsync(EmailOccurrenceId, bool, IMailboxMutationJournal, CancellationToken)

Sets or clears the remote \Flagged flag of one email in this session's folder.

SetKeywordsAsync(EmailOccurrenceId, AuthoredMailKeywords, IMailboxMutationJournal, CancellationToken)

Makes one email's keywords exactly the set that was named, in this session's folder.

SetSeenAsync(EmailOccurrenceId, bool, IMailboxMutationJournal, CancellationToken)

Sets or clears the remote \Seen flag of one email in this session's folder.

WithdrawAppendedAsync(ImapUidValidity, ImapUid, CancellationToken)

Takes a copy this session's folder was given by an earlier append back out of it.