actions

package
v0.1.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package actions is the only code that changes a mailbox: the executor that applies a rule's actions, and undo. This file holds the types its callers share.

Index

Constants

View Source
const TrashFolder = "MailRules Trash"

TrashFolder is where a trash action moves mail while the trash_to_folder setting is on: an ordinary folder, made on first use and given no special-use role, so the provider never empties it the way it empties Trash.

Variables

View Source
var ErrGone = errors.New("message was moved or deleted outside MailRules")

ErrGone means an action cannot be undone because its message is no longer where MailRules left it. The HTTP layer answers 409 with this text.

View Source
var ErrLeftReview = fmt.Errorf("taken off Needs review: %w", ErrGone)

ErrLeftReview means an answer to Needs review found the email no longer where MailRules saw it, so it was taken off the queue (state skipped) and nothing else was done. It wraps ErrGone. The HTTP layer answers 409 message_gone with its own text.

View Source
var ErrTooOld = errors.New("the action is too old to undo")

ErrTooOld means an action was made more than store.UndoDays ago and can no longer be undone. The HTTP layer answers 409 too_old.

Functions

This section is empty.

Types

type Accounts

type Accounts interface {
	// Mailbox returns the account's open connection.
	Mailbox(accountID int64) (mail.Mailbox, error)
	// Lock waits until the account's processor is between messages and holds it there
	// until unlock is called. Undo and corrections take it, so mail they move back into
	// the watched folder is on record before the processor can mistake it for new mail.
	Lock(accountID int64) (unlock func())
}

Accounts is how the executor reaches a mail account (worker.Manager implements it).

type ActionRecord

type ActionRecord = store.Action

ActionRecord is one row of the actions table.

type Correction

type Correction struct {
	MessageID   int64
	RightRuleID int64 // 0 = keep in the inbox
	// Always also stores a user sender rule, so future mail goes the same way: for the
	// message's sender (rules.MatchAddress) or its whole domain (rules.MatchDomain). "" = no.
	Always string
	Review bool // an answer given in Needs review, as opposed to a fix made from the feed
}

Correction is the user saying a message belongs to another rule.

type DecisionRecord

type DecisionRecord struct {
	DecisionID int64       // 0 = no decision, e.g. a correction
	MessageID  int64       // messages.id
	Ref        mail.MsgRef // where the message is now
}

DecisionRecord says which message to act on and for which decision.

type Exec

type Exec struct {
	Store    *store.Store
	Accounts Accounts
	Hub      *events.Hub // nil = publish nothing
	// DryRunDefault is used until the dry_run setting is stored (MAILRULES_DRY_RUN).
	DryRunDefault bool
	Now           func() time.Time // nil = time.Now
}

Exec is the executor: the only code that changes a mailbox.

func (*Exec) Apply

func (x *Exec) Apply(ctx context.Context, d DecisionRecord, acts []rules.Action, batchID int64) ([]ActionRecord, error)

Apply runs acts in order on one message. In dry-run (checked here and nowhere else) it only writes a dry_run row per action and never contacts the server. Otherwise it reads the message's flags once, and for each action writes its row with the before snapshot first, then changes the mailbox, then stores the outcome, so there is no change without a row. A failure stops the remaining actions and is returned; whoever asked decides about a retry. With trash_to_folder on, a trash row names TrashFolder as its folder, in dry-run too, so what it says it did (or would do) is where the mail went.

func (*Exec) Correct

func (x *Exec) Correct(ctx context.Context, c Correction) (batchID int64, err error)

Correct fixes one message: it undoes what was done to it (newest first), applies the right rule's actions, or none for "keep", and records the correction, which deletes the learned sender rule for that sender and, with Always, stores a user sender rule instead. The new actions are one batch, whose id is returned. It also resolves a message waiting in Needs review. When the new actions cannot be applied, what was undone stays undone; the row as it now is goes out as message.processed all the same, after the action.undone events, so a screen that shows the email does not keep the old picture. An email waiting in Needs review that is no longer where MailRules saw it is taken off the queue instead, with nothing done to any mailbox, and the error is ErrLeftReview.

func (*Exec) EnsureFolders

func (x *Exec) EnsureFolders(ctx context.Context, accountID int64, names []string) error

EnsureFolders creates folders on an account's server, ahead of the rules that will move mail into them. It is a mailbox change like any other: in dry-run it does nothing, and the first live move creates the folder then.

func (*Exec) Undo

func (x *Exec) Undo(ctx context.Context, actionID int64) error

Undo reverses one action: a move goes back to the folder it came from, a flag change goes back to what the before snapshot says. Undoing an action that is already undone, or that never changed the mailbox (dry-run, failed), does nothing. An action made more than store.UndoDays ago is refused with ErrTooOld. When the message is not where the action left it, the error is ErrGone and the action stays as it was. Undo does not look at dry-run: it only restores what MailRules itself changed, and only when asked.

func (*Exec) UndoBatch

func (x *Exec) UndoBatch(ctx context.Context, batchID int64) (Undid, error)

UndoBatch undoes a batch's actions, newest first, and says what it undid. An action that cannot be undone does not stop the rest: its error is joined into the one returned, and the batch is marked undone only when every action was. A batch that never changed a mailbox (all its actions were recorded in dry-run, or failed) has nothing to undo: that is a no-op, and the batch stays as it is.

func (*Exec) UndoMessage

func (x *Exec) UndoMessage(ctx context.Context, messageID int64) (batchID int64, u Undid, why, err error)

UndoMessage reverses everything still in effect on one message, newest first, as one batch of kind undo: "undo this email" in one step. An action that cannot be undone does not stop the others; why is the first such failure (ErrGone when the message is gone), nil when there was none.

func (*Exec) UndoSince

func (x *Exec) UndoSince(ctx context.Context, ruleID, since int64) (batchID int64, u Undid, err error)

UndoSince reverses every action made at or after since that is still in effect, newest first: "undo the last hour". With ruleID it only takes the actions that rule led to. The run is recorded as one batch of kind undo, whose id is returned with what was undone and how many actions could not be (their message is gone, or its account is not connected). One that cannot be undone does not stop the rest.

type Executor

type Executor interface {
	// Apply runs acts in order on one message and returns a record per action attempted.
	// A failure stops the remaining actions and is returned with the records so far.
	Apply(ctx context.Context, d DecisionRecord, acts []rules.Action, batchID int64) ([]ActionRecord, error)
	Undo(ctx context.Context, actionID int64) error
	UndoBatch(ctx context.Context, batchID int64) (Undid, error)
}

Executor applies and undoes actions.

type NoFolderError

type NoFolderError struct{ Role string } // Archive | Trash | Junk

NoFolderError means an archive, trash or junk action has nowhere to go: the account has no folder the server marks for that use, and MailRules never guesses one or creates one. Its text is what the action's row records ("no Archive folder"). Trash only meets it with trash_to_folder off: otherwise it goes to TrashFolder, which MailRules makes.

func (*NoFolderError) Error

func (e *NoFolderError) Error() string

type Undid

type Undid struct {
	Actions int // actions undone
	// Emails is how many emails at least one action was undone on: put back as they were.
	// An email a cleanup only recorded in dry-run, passed over, or whose actions all
	// failed was never changed, so it is not counted.
	Emails int
	Failed int // actions that could not be undone and are still in effect
}

Undid counts what one undo run did.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL